【C++】图像处理中的微分算子原理与实现(一)

简介: 一阶微分边缘算子:经典算子比如:Roberts(罗伯特)、Prewitt(普鲁伊特)、Sobel(索贝尔),Canny(坎尼)等。二阶微分边缘算子:Laplacian算子,LoG( Laplace of Gaussian function)边缘检测算子和DoG(Difference of Gaussian)高斯差分算子。

fe5a1c705f924bae992d7671ccac28ed.png

Roberts算子

1963年,Roberts算子,又称罗伯茨算子,是一种最简单的算子,是一种利用局部差分算子寻找边缘的算子。他采用对角线方向相邻两象素之差近似梯度幅值检测边缘。检测垂直边缘的效果好于斜向边缘,定位精度高,对噪声敏感,无法抑制噪声的影响。

Roberts算子的模板分为水平方向和垂直方向,如下式所示,从其模板可以看出,Roberts算子能较好的增强正负45度的图像边缘。

9d7a0b990576428fa8877b99048c5bf1.gif

voidquick_opencv::roberts_Demo(Mat&img)
{
// Roberts算子边缘检测cvtColor(img,img,COLOR_BGR2GRAY);
Matgrad;
grad.create(img.size(), CV_8UC1);
for (inti=1; i<img.rows-1; i++)
    {
for (intj=1; j<img.cols-1; j++)
        {
grad.at<uchar>(i, j) =saturate_cast<uchar>(fabs(img.at<uchar>(i, j) -img.at<uchar>(i-1, j-1)) +fabs(img.at<uchar>(i, j-1) -img.at<uchar>(i-1, j)));
        }
    }
imshow("Roberts算子", grad);

Prewitt算子

1970年,Prewitt算子来自J.M.S. Prewitt "Object Enhancement and Extraction" in "Picture processing and Psychopictorics", Academic Press

Prewitt算子是一种图像边缘检测的微分算子,其原理是利用特定区域内像素灰度值产生的差分实现边缘检测。由于Prewitt算子采用 33 模板对区域内的像素值进行计算,而Robert算子的模板为 22,故Prewitt算子的边缘检测结果在水平方向和垂直方向均比Robert算子更加明显。Prewitt算子适合用来识别噪声较多、灰度渐变的图像,其计算公式如下所示:

02e8c151c79e4e93b3a5701347ffce3c.gif

voidgetPrewitt_oper(Mat&getPrewitt_horizontal, Mat&getPrewitt_vertical, Mat&getPrewitt_Diagonal1, Mat&getPrewitt_Diagonal2) {
//水平方向getPrewitt_horizontal= (Mat_<float>(3, 3) <<-1, -1, -1, 0, 0, 0, 1, 1, 1);
//垂直方向getPrewitt_vertical= (Mat_<float>(3, 3) <<-1, 0, 1, -1, 0, 1, -1, 0, 1);
//对角135°getPrewitt_Diagonal1= (Mat_<float>(3, 3) <<0, 1, 1, -1, 0, 1, -1, -1, 0);
//对角45°getPrewitt_Diagonal2= (Mat_<float>(3, 3) <<-1, -1, 0, -1, 0, 1, 0, 1, 1);
//逆时针反转180°得到卷积核flip(getPrewitt_horizontal, getPrewitt_horizontal, -1);
flip(getPrewitt_vertical, getPrewitt_vertical, -1);
flip(getPrewitt_Diagonal1, getPrewitt_Diagonal1, -1);
flip(getPrewitt_Diagonal2, getPrewitt_Diagonal2, -1);
}
voidedge_Prewitt(Mat&src, Mat&dst1, Mat&dst2, Mat&dst3, Mat&dst4, Mat&dst, intddepth, doubledelta=0, intborderType=BORDER_DEFAULT) {
//获取Prewitt算子MatgetPrewitt_horizontal;
MatgetPrewitt_vertical;
MatgetPrewitt_Diagonal1;
MatgetPrewitt_Diagonal2;
getPrewitt_oper(getPrewitt_horizontal, getPrewitt_vertical, getPrewitt_Diagonal1, getPrewitt_Diagonal2);
//卷积得到水平方向边缘filter2D(src, dst1, ddepth, getPrewitt_horizontal, Point(-1, -1), delta, borderType);
//卷积得到4垂直方向边缘filter2D(src, dst2, ddepth, getPrewitt_vertical, Point(-1, -1), delta, borderType);
//卷积得到45°方向边缘filter2D(src, dst3, ddepth, getPrewitt_Diagonal1, Point(-1, -1), delta, borderType);
//卷积得到135°方向边缘filter2D(src, dst4, ddepth, getPrewitt_Diagonal2, Point(-1, -1), delta, borderType);
//边缘强度(近似)convertScaleAbs(dst1, dst1); //求绝对值并转为无符号8位图convertScaleAbs(dst2, dst2);
convertScaleAbs(dst3, dst3); //求绝对值并转为无符号8位图convertScaleAbs(dst4, dst4);
dst=dst1+dst2;
}
voidquick_opencv::prewitt_Demo(Mat&img)
{
Matdst, dst1, dst2, dst3, dst4;
cvtColor(img, img, COLOR_BGR2GRAY);
//注意:要采用CV_32F,因为有些地方卷积后为负数,若用8位无符号,则会导致这些地方为0edge_Prewitt(img, dst1, dst2, dst3, dst4, dst, CV_32F);
namedWindow("水平边缘", WINDOW_NORMAL);
imshow("水平边缘", dst1);
namedWindow("垂直边缘", WINDOW_NORMAL);
imshow("垂直边缘", dst2);
namedWindow("45°边缘", WINDOW_NORMAL);
imshow("45°边缘", dst3);
namedWindow("135°边缘", WINDOW_NORMAL);
imshow("135°边缘", dst4);
namedWindow("边缘强度", WINDOW_NORMAL);
imshow("边缘强度", dst);
}
目录
相关文章
|
3月前
|
存储 自然语言处理 安全
C++ STL标准库 《string原理与实战分析》
C++ STL标准库 《string原理与实战分析》
66 0
|
4月前
|
小程序 编译器 Linux
C++ 异常原理:以一个小程序为例
作者在调查某个 bug 时涉及到 C++ 异常,借此机会以本文把 C++ 异常机制梳理清楚供大家参考。
|
1月前
|
存储 编译器 C++
C++多态实现的原理:深入探索与实战应用
【8月更文挑战第21天】在C++的浩瀚宇宙中,多态性(Polymorphism)无疑是一颗璀璨的星辰,它赋予了程序高度的灵活性和可扩展性。多态允许我们通过基类指针或引用来调用派生类的成员函数,而具体调用哪个函数则取决于指针或引用所指向的对象的实际类型。本文将深入探讨C++多态实现的原理,并结合工作学习中的实际案例,分享其技术干货。
52 0
|
3月前
|
大数据 C++ 索引
C++ STL标准库 《vector向量原理与实战分析》
C++ STL标准库 《vector向量原理与实战分析》
41 0
|
3月前
|
C++ 容器
C++ STL标准库 《queue单向队列原理与实战分析》
C++ STL标准库 《queue单向队列原理与实战分析》
39 0
|
4月前
|
设计模式 算法 C++
【C++】STL之迭代器介绍、原理、失效
【C++】STL之迭代器介绍、原理、失效
106 2
|
4月前
|
编解码 JavaScript 前端开发
【专栏】介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例
【4月更文挑战第29天】本文介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例。Base64编码将24位二进制数据转换为32位可打印字符,用“=”作填充。文中展示了各语言的编码解码代码,帮助开发者理解并应用于实际项目。
105 1
|
4月前
|
编译器 C++ 容器
C++模板的原理及使用
C++模板的原理及使用
|
4月前
|
设计模式 C语言 C++
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
|
4月前
|
存储 C++
C++底层原理
C++底层原理
180 0