当前位置: 首页 > news >正文

14---OpenCV:图像检测之边缘检测

一、图像边缘

边缘(edge)是指图像局部强度变化最显著的部分。主要存在于目标与目标、目标与背景、区域与区域(包括不同色彩)之间,是图像分割、纹理特征和形状特征等图像分析的重要基础。图像强度的显著变化可分为:

  • 阶跃变化函数,即图像强度在不连续处的两边的像素灰度值有着显著的差异

  • 线条(屋顶)变化函数,即图像强度突然从一个值变化到另一个值,保持一较小行程后又回到原来的值

图像的边缘有方向和幅度两个属性,沿边缘方向像素变化平缓,垂直于边缘方向像素变化剧烈.边缘上的这种变化可以用微分算子检测出来,通常用一阶或二阶导数来检测边缘。

 ab分别是阶跃函数和屋顶函数的三维图像

cd是阶跃和屋顶函数的函数二维图像

ef对应一阶导数

gh是二阶导数

1.Sobel算子(索伯)

        Sobel算子是一种常用的边缘检测算子,是一阶的梯度算法。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。

计算过程

API介绍

void Laplacian( InputArray src, OutputArray dst, int ddepth,int ksize = 1, double scale = 1, double delta = 0,int borderType = BORDER_DEFAULT );
/*******************************************************************
*           src:            输入图             
*           dst:            输出图
*           ddepth:         输出图深度 CV_16S/CV_32F/CV_64F等
*           ksize:          核大小,必须是正奇数,默认值是1
*           scale:          计算导数值时可选的缩放因子
*           delta:          可选值,默认为0
*           borderType:     边缘处理模式  
*********************************************************************/

2.LapLace 算子(拉普拉斯)

拉普拉斯对噪声敏感,会产生双边效果。不能检测出边的方向。通常不直接用于边的检测,只起辅助的角色,检测一个像素是在边的亮的一边还是暗的一边利用零跨越,确定边的位置.

计算过程

API介绍

void Laplacian( InputArray src, OutputArray dst, int ddepth,int ksize = 1, double scale = 1, double delta = 0,int borderType = BORDER_DEFAULT );
/*******************************************************************
*           src:            输入图             
*           dst:            输出图
*           ddepth:         输出图深度 CV_16S/CV_32F/CV_64F等
*           ksize:          核大小,必须是正奇数,默认值是1
*           scale:          计算导数值时可选的缩放因子
*           delta:          可选值,默认为0
*           borderType:     边缘处理模式  
*********************************************************************/

3.Canny算子(坎尼)

计算过程

  • 用高斯滤波器平滑图像

  • 用一阶偏导的有限差分计算梯度的幅值核方向

  • 对梯度幅值进行非极大值抑制

    • 超过255 用255表示

    • 低于0 用绝对值表示

  • 用双阈值算法检测和连接边缘

API介绍

void Canny( InputArray image, OutputArray edges,double threshold1, double threshold2,int apertureSize = 3, bool L2gradient = false );
/*******************************************************************
*           src:            输入图             
*           edges:          输出图
*           threshold1:     第一个阈值
*           threshold2:     第二个阈值
*           apertureSize:   内核大小
*           L2gradient:     计算图像梯度幅值方法的标志
*********************************************************************/

4.综合代码

注意:

        ①相关函数说明

convertScaleAbs(result["y"], result["y"]);  //图像增强函数
addWeighted(result["x"], 0.5, result["y"], 0.5, 0, result["xy"]);
//将两个图像按一定权值融合在一起

        ②sobel算子和拉普拉斯算子处理完后效果并不会太好,需要调用图像增强函数。

#include <iostream>
#include <string>
#include <map>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class Edge 
{
public:
    Edge() :img(imread("test.jpg")) 
    {
        result["img"] = img;
    }
    void TestSobel() 
    {
        Sobel(img, result["x"], CV_16S, 1, 0);
        //图像增强
        //α*src+β
        convertScaleAbs(result["x"], result["x"]);
        Sobel(img, result["y"], CV_16S, 0, 1);
        convertScaleAbs(result["y"], result["y"]);
        addWeighted(result["x"], 0.5, result["y"], 0.5, 0, result["xy"]);
        Sobel(img, result["sobel"], CV_16S, 1, 1);
        convertScaleAbs(result["sobel"], result["sobel"]);
    }
    void TestLapLacian() 
    {
        Laplacian(img, result["LapLacian"], CV_16S);
        convertScaleAbs(result["LapLacian"], result["LapLacian"]);
    }
    void TestCanny() 
    {
        //高阈值
        Canny(img, result["Canny"], 100, 200);
        //灰度后的高阈值和低阈值
        cvtColor(img, result["Gray"], COLOR_BGR2GRAY);
        Canny(result["Gray"], result["Max"], 100, 200);
        Canny(result["Gray"], result["Min"], 20, 40);
        //高斯模糊后做双阈值
        GaussianBlur(result["Gray"], result["Gauss"], Size(3, 3), 5);
        Canny(result["Gauss"], result["OK"], 100, 200);
    }
​
    void Show() 
    {
        for (auto& v : result) 
        {
            imshow(v.first, v.second);
        }
        waitKey(0);
    }
protected:
    Mat img;
    map<string, Mat> result;
};
​
int main() 
{
    unique_ptr<Edge> p(new Edge);
    p->TestSobel();
    p->TestLapLacian();
    p->TestCanny();
    p->Show();
​
    return 0;
}

显然最佳的方法是用二值化的灰度图像,然后高斯滤波处理,再去用canny检测算法(两个阈值的选定很重要---->要多试试)(得到的OK图像如下,边缘的线条很细,且取出了原本canny算法算出来的很多的噪声)

相关文章:

  • 带救援的两阶段随机规划问题的LShaped算法理论与算例
  • 为什么比特币将持续增长
  • .Net CoreRabbitMQ消息存储可靠机制
  • 2022年9月2号学习总结
  • Hive基本概念
  • 有向图的强连通分量
  • 新建SpringBoot Maven项目中pom常用依赖配置及常用的依赖的介绍
  • 想搞清楚API网关到底是什么?请看这篇
  • 【STM32F4系列】【HAL库】电机控制(转速和角度)(PID实战1)
  • 设定目标(1)- 为什么你每天感觉很忙却没什么拿得出手的业绩?
  • Java 进阶集合Set、Map(二)
  • 2022-Docker常用命令
  • Spring中事务传播特性(Propagation)
  • Matlab:Matlab编程语言应用之数学统计(柱状图、曲线分析等)的使用方法简介、案例实现之详细攻略
  • YOLOv7改进之二十五:引入Swin Transformer
  • $translatePartialLoader加载失败及解决方式
  • 《Java编程思想》读书笔记-对象导论
  • Apache Spark Streaming 使用实例
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • ES6简单总结(搭配简单的讲解和小案例)
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • ucore操作系统实验笔记 - 重新理解中断
  • Wamp集成环境 添加PHP的新版本
  • 阿里云购买磁盘后挂载
  • 仿天猫超市收藏抛物线动画工具库
  • 分享一份非常强势的Android面试题
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 排序算法学习笔记
  • 如何实现 font-size 的响应式
  • 深入浅出webpack学习(1)--核心概念
  • 用quicker-worker.js轻松跑一个大数据遍历
  • 自制字幕遮挡器
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • 阿里云移动端播放器高级功能介绍
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​比特币大跌的 2 个原因
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #、%和$符号在OGNL表达式中经常出现
  • (1)(1.11) SiK Radio v2(一)
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (四) 虚拟摄像头vivi体验
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (转) 深度模型优化性能 调参
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • .NET CORE 第一节 创建基本的 asp.net core
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • @Validated和@Valid校验参数区别
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧