Prewitt算子边缘检测原理及实现

article/2025/11/9 3:50:13

写在前面

Prewitt算子同样也是一种一阶微分算子,利用像素点上下左右邻点灰度差,在边缘处达到极值检测边缘,对噪声具有平滑的作用。

原理

其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。

相比Roberts算子,Prewitt算子对噪声有抑制作用,抑制噪声的原理是通过像素平均,因此噪声较多的图像处理得比较好,但是像素平均相当于对图像的低通滤波,所以Prewitt算子对边缘的定位却不如Roberts算子。

那么为啥Prewitt算子对噪声有抑制作用呢?请看Prewitt算子的卷积核:

ââ

                                                         Prewitt_X                                     Prewitt_Y 

图像与Prewitt_X卷积后可以反映图像的垂直边缘,与Prewitt_Y卷积后可以反映图像的水平边缘。最重要的是,这两个卷积是可分离的:

                                    Prewitt_X =\begin{bmatrix}1 \\ 1 \\ 1 \end{bmatrix} *\begin{bmatrix} -1 & 0 &1 \end{bmatrix}        ,          Prewitt_Y =\begin{bmatrix} 1 & 1 &1 \end{bmatrix}*\begin{bmatrix}1 \\ 0 \\ -1 \end{bmatrix}

从分离的结果来看, Prewitt_X算子实际上是先对图像进行垂直方向的非归一化的均值平滑,然后进行水平方向的差分; 然而Prewitt_Y算子实际上是先对图像进行水平方向的非归一化的均值平滑,然后进行垂直方向的差分。这就是Prewitt算子能够抑制噪声的原因。

同理,我们也可以得到对角上的Prewitt算子算子,见代码即可。

 

代码实现

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>void getPrewitt_oper(cv::Mat& getPrewitt_horizontal, cv::Mat& getPrewitt_vertical, cv::Mat& getPrewitt_Diagonal1,cv::Mat& getPrewitt_Diagonal2){//水平方向getPrewitt_horizontal = (cv::Mat_<float>(3, 3) << -1, -1, -1, 0, 0, 0, 1, 1, 1);//垂直方向getPrewitt_vertical = (cv::Mat_<float>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);//对角135°getPrewitt_Diagonal1 = (cv::Mat_<float>(3, 3) << 0, 1, 1, -1, 0, 1, -1, -1, 0);//对角45°getPrewitt_Diagonal2 = (cv::Mat_<float>(3, 3) << -1, -1, 0, -1, 0, 1, 0, 1, 1);//逆时针反转180°得到卷积核cv::flip(getPrewitt_horizontal, getPrewitt_horizontal, -1);cv::flip(getPrewitt_vertical, getPrewitt_vertical, -1);cv::flip(getPrewitt_Diagonal1, getPrewitt_Diagonal1, -1);cv::flip(getPrewitt_Diagonal2, getPrewitt_Diagonal2, -1);
}void edge_Prewitt(cv::Mat& src, cv::Mat& dst1, cv::Mat& dst2, cv::Mat& dst3, cv::Mat& dst4, cv::Mat& dst, int ddepth, double delta = 0, int borderType = cv::BORDER_DEFAULT){//获取Prewitt算子cv::Mat getPrewitt_horizontal;cv::Mat getPrewitt_vertical;cv::Mat getPrewitt_Diagonal1;cv::Mat getPrewitt_Diagonal2;getPrewitt_oper(getPrewitt_horizontal, getPrewitt_vertical, getPrewitt_Diagonal1, getPrewitt_Diagonal2);//卷积得到水平方向边缘cv::filter2D(src, dst1, ddepth, getPrewitt_horizontal, cv::Point(-1, -1), delta, borderType);//卷积得到4垂直方向边缘cv::filter2D(src, dst2, ddepth, getPrewitt_vertical, cv::Point(-1, -1), delta, borderType);//卷积得到45°方向边缘cv::filter2D(src, dst3, ddepth, getPrewitt_Diagonal1, cv::Point(-1, -1), delta, borderType);//卷积得到135°方向边缘cv::filter2D(src, dst4, ddepth, getPrewitt_Diagonal2, cv::Point(-1, -1), delta, borderType);//边缘强度(近似)cv::convertScaleAbs(dst1, dst1); //求绝对值并转为无符号8位图cv::convertScaleAbs(dst2, dst2);cv::convertScaleAbs(dst3, dst3); //求绝对值并转为无符号8位图cv::convertScaleAbs(dst4, dst4);dst = dst1 + dst2 ;}int main(){cv::Mat src = cv::imread("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Img\\(embedded_square_noisy_512).tif");if (src.empty()){return -1;}if (src.channels() > 1) cv::cvtColor(src, src, CV_RGB2GRAY);cv::Mat dst, dst1, dst2, dst3, dst4;//注意:要采用CV_32F,因为有些地方卷积后为负数,若用8位无符号,则会导致这些地方为0edge_Prewitt(src, dst1, dst2, dst3, dst4, dst, CV_32F);cv::namedWindow("src", CV_WINDOW_NORMAL);imshow("src", src);cv::namedWindow("水平边缘", CV_WINDOW_NORMAL);imshow("水平边缘", dst1);cv::namedWindow("垂直边缘", CV_WINDOW_NORMAL);imshow("垂直边缘", dst2);cv::namedWindow("45°边缘", CV_WINDOW_NORMAL);imshow("45°边缘", dst3);cv::namedWindow("135°边缘", CV_WINDOW_NORMAL);imshow("135°边缘", dst4);cv::namedWindow("边缘强度", CV_WINDOW_NORMAL);imshow("边缘强度", dst);cv::waitKey(0);return 0;
}

效果

 


http://chatgpt.dhexx.cn/article/OJgpTM1G.shtml

相关文章

Prewitt和Sobel算子

在3*3模板中&#xff1a; 我如下定义水平、垂直和两对角线方向的梯度&#xff1a; 该定义下的算子称之为Prewitt算子&#xff1a; Sobel算子是在Prewitt算子的基础上改进的&#xff0c;在中心系数上使用一个权值2&#xff0c;相比较Prewitt算子&#xff0c;Sobel模板能够较好…

Prewitt边缘检测算子

Prewitt算子也是一种一阶微分算子&#xff0c;用于边缘检测。与Robert使用22的模板不同&#xff0c;Prewitt算子使用的是33的模板&#xff0c;利用像素点上下、左右邻点的灰度差来检测边缘&#xff0c;故其边缘检测结果在水平方向和垂直方向均比Robert算子更加明显。 其数学表…

图像边缘检测之Prewitt算子

Prewitt 算子 1. 原理 Prewitt算子是一种图像边缘检测的微分算子&#xff0c;其原理是利用特定区域内像素灰度值产生的差分实现边缘检测。由于Prewitt算子采用 3x3 模板对区域内的像素值进行计算&#xff0c;而Robert算子的模板为 2x2&#xff0c;故Prewitt算子的边缘检测结果…

华为--配置本地环回接口地址

该实验紧接上一节实验 网络拓扑图如下 AR1环回接口配置 AR2环回接口配置 AR3环回接口配置 配置AR1回环接口路由 配置AR2回环接口路由 配置AR3回环接口路由 在AR1上测试回环接口的连通性 在AR2上测试回环接口的连通性 在AR3上测试回环接口的连通性 测试成功 转载于:https://my.o…

【LINUX】ifconfig只有本地环回地址问题的解决方法

问题描述&#xff1a; ifconfig只有lo&#xff0c;没有看到ens33 ifconfig -a看到了ens33&#xff0c;但是没有地址 解决方法&#xff1a; &#xff08;1&#xff09;stop network-manager sudo service network-manager stop &#xff08;2&#xff09;删除旧有的网络配置…

怎么判断一个ipv4地址是 私有地址,环回地址,实验地址,TEST-NET地址,本地链路地址?

问题的提出&#xff1a; 理论讲解(黄色的为上题的答案&#xff09;&#xff1a; IP地址分为五类&#xff1a; A类保留给政府机构&#xff0c;B类分配给中等规模的公司&#xff0c;C类分配给任何需要的人&#xff0c;D类用于组播&#xff0c;E类用于实验&#xff0c;各类可容纳…

回环地址 127.0.0.1

控制台输入ping 127.0.0.1。 $ ping 127.0.0.1 PING 127.0.0.1 (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq0 ttl64 time0.080 ms 64 bytes from 127.0.0.1: icmp_seq1 ttl64 time0.093 ms 64 bytes from 127.0.0.1: icmp_seq2 ttl64 time0.074 ms 64 byte…

环回接口 环回地址 环回路由

网络协议的数据链路层的一些重点我们来讲解一下。这此我们主要讲解的是环回接口的问题。环回接口&#xff08;loopback&#xff09;:路由器上的一个逻辑、虚拟接口.路由器默认没有任何环回接口.此接口允许运行在同一台主机上的客户程序和服务器程序通过TCP/IP进行通信.一般系统…

什么是环回接口(Loopback Interface、环回地址)

2.7 环回接口 大多数的产品都支持环回接口&#xff08;Loopback Interface&#xff09;&#xff0c;以允许运行在同一台主机上的客户程序和服务器程序通过TCP/IP进行通信。 A类网络号 127就是为环回接口预留的。根据惯例&#xff0c;大多数系统把 IP地址127.0.0.1分配给这个接…

特殊IP地址——环回地址

环回地址&#xff08;Loopback Address&#xff09;127.0.0.1---127.255.255.254 是一种特殊的 IP 地址&#xff0c;它允许计算机的软件组件在本地主机上进行网络通信&#xff0c;也称作本地回环地址。 在计算机网络中&#xff0c;环回地址是一个虚拟地址&#xff0c;它不属于任…

“谁告诉你环回地址就是127.0.0.1?” “老师就是这么说的。”

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「专栏简介」&#xff1a;此文章已录入专栏《计算机网络零基础快速入门》 环回地址是本地的「虚拟接口」&#xff0c;默认不会宕掉。 我们经…

带头结点单链表、不带头结点单链表(头指针单链表)

1、头结点和头指针的区别 1.1区别&#xff1a; 头指针表明了链表的结点&#xff0c;可以唯一确定一个单链表。 头指针指向链表的第一个结点&#xff0c;其记录第一个存储数据的结点的地址。 头结点是点链表的第一个结点&#xff0c;若单链表有头结点&#xff0c;则头指针指向头…

不带头结点的单链表------C语言实现

1 /****************************************************/ 3 File name&#xff1a;no_head_link.c4 Author&#xff1a;SimonKly Version:0.1 Date: 2017.5.205 Description&#xff1a;不带头节点的单链表6 Funcion List: 7 ***************************************…

单链表的头结点的作用

问题&#xff1a;在单链表中使用“头结点”&#xff0c;这个哑结点始终是链表的第一个元素&#xff0c;这个技巧的利与弊&#xff1f; 链表中第一个结点的存储位置叫做头指针&#xff0c;那么整个链表的存取就必须从头指针开始进行了。之后的每一个结点&#xff0c;其实就是上…

【数据结构】单链表之带头结点的单链表

一、单链表相关知识点介绍&#xff1a; 1. 结点&#xff1a;结点就是单链表中研究的数据元素&#xff0c;结点中存储数据的部分称为数据域&#xff0c;存储直接后继地址的部分称为指针域。 2. 头结点&#xff1a;引入头结点的目的是&#xff0c;将链表首元结点的插入和删除操作…

【链表】带头节点和不带头节点单链表的区别

目录 &#x1f354;当链表的结点只包含一个指针域时&#xff0c;叫做单链表 &#x1f354;不论带不带头节点&#xff0c;所有的链表都要有个头指针&#xff01; &#x1f35f;带头结点的链表的头指针指向的是头结点&#xff0c;头结点的指针域指向首元结点 &#x1f35f;不带…

带头结点的单链表的操作(C语言)

初始化 先了解头结点 头结点是一个特殊的结点&#xff0c;它的数据域不存储信息&#xff0c;通常情况下&#xff0c;头指针指向的结点为头结点&#xff0c;由于头结点不存储信息&#xff0c;所以不是数据结构中的实际结点&#xff0c;第一个实际结点其实是head->next指示的…

单链表(不带头结点)

单链表不带头结点结构体设计&#xff1a; //不带头结点的结构体设计&#xff1a; typedef int ELEM_TYPE;//有效数据节点结构体设计 typedef struct Node {ELEM_TYPE data;//数据域 &#xff08;1.头结点&#xff1a;不保存任何数据 2.有效数据节点&#xff1a;保存有效值…

数据结构之不带头结点的单链表

我们都知道不管是单链表、双向链表还是循环链表&#xff0c;都带有头结点&#xff0c;这个头结点相当于一个起始的位置。我们在设计带头结点的单链表的时候&#xff0c;我们会在主函数中设计一个头结点&#xff0c;并把它的指针域置为空&#xff0c;这样我们就可以进行增删查改…

数据结构--带头结点的单链表

单链表分为&#xff1a;带头结点和不带头结点&#xff0c;不带头结点的单链表需要用到二级指针&#xff0c;容易出错。 1、结构体设计 typedef int ELEM_TYPE; //有效数据节点结构体设计&#xff08;头结点借用&#xff09; typedef struct Node {ELEM_TYPE data;//数据域 &…