C++ 区别于;“边缘检测”;及;图像轮廓“;
我正在编写以下代码:C++ 区别于;“边缘检测”;及;图像轮廓“;,c++,image,opencv,image-processing,artificial-intelligence,C++,Image,Opencv,Image Processing,Artificial Intelligence,我正在编写以下代码: #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; Mat src, grey; int thresh = 10; const ch
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
Mat src, grey;
int thresh = 10;
const char* windowName = "Contours";
void detectContours(int,void*);
int main()
{
src = imread("C:/Users/Public/Pictures/Sample Pictures/Penguins.jpg");
//Convert to grey scale
cvtColor(src,grey,CV_BGR2GRAY);
//Remove the noise
cv::GaussianBlur(grey,grey,Size(3,3),0);
//Create the window
namedWindow(windowName);
//Display the original image
namedWindow("Original");
imshow("Original",src);
//Create the trackbar
cv::createTrackbar("Thresholding",windowName,&thresh,255,detectContours);
detectContours(0,0);
waitKey(0);
return 0;
}
void detectContours(int,void*)
{
Mat canny_output,drawing;
vector<vector<Point>> contours;
vector<Vec4i>heirachy;
//Detect edges using canny
cv::Canny(grey,canny_output,thresh,2*thresh);
namedWindow("Canny");
imshow("Canny",canny_output);
//Find contours
cv::findContours(canny_output,contours,heirachy,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
//Setup the output into black
drawing = Mat::zeros(canny_output.size(),CV_8UC3);
//Draw contours
for(int i=0;i<contours.size();i++)
{
cv::drawContours(drawing,contours,i,Scalar(255,255,255),1,8,heirachy,0,Point());
}
imshow(windowName,drawing);
}
#包括
#包括
#包括
#包括
使用名称空间std;
使用名称空间cv;
Mat src,灰色;
int thresh=10;
const char*windowName=“等高线”;
空洞探测孔(int,void*);
int main()
{
src=imread(“C:/Users/Public/Pictures/Sample Pictures/Penguins.jpg”);
//转换为灰度
CVT颜色(src、灰色、CV_BGr2灰色);
//消除噪音
cv::高斯蓝(灰色,灰色,大小(3,3),0);
//创建窗口
namedWindow(windowName);
//显示原始图像
姓名(以下简称“原件”);
imshow(“原件”,src);
//创建轨迹栏
cv::createTrackbar(“阈值化”,windowName,&thresh,255,detectContours);
检测孔(0,0);
等待键(0);
返回0;
}
无效检测孔(int,void*)
{
Mat canny_输出、绘图;
矢量等值线;
矢量遗传;
//使用canny算法检测边缘
cv::Canny(灰色,Canny_输出,阈值,2*阈值);
namedWindow(“精明”);
imshow(“Canny”,Canny_输出);
//寻找轮廓
cv::findContours(canny_输出、轮廓、继承、cv_RETR_树、cv_链近似、点(0,0));
//将输出设置为黑色
drawing=Mat::zeros(canny_output.size(),CV_8UC3);
//画轮廓
对于(int i=0;i等高线实际上可以做的不仅仅是“仅”检测边缘。该算法确实可以找到图像的边缘,但也可以将它们放在一个层次结构中。这意味着您可以请求在图像中检测到的对象的外部边界。如果只检查边缘,则(直接)不可能做到这一点
从文档中可以看出,检测轮廓主要用于对象识别,而canny边缘检测器则更具“全局性”操作。如果轮廓算法使用某种精明的边缘检测,我不会感到惊讶。查找边缘和计数之间的主要区别在于,如果运行查找边缘,输出的是新图像。在这张新(边缘图像)图像中,您将突出显示边缘。有许多用于检测边缘的算法
例如,Sobel运算符给出平滑的“模糊”结果。在您的特定情况下,关键是您使用的是Canny边缘检测器。此检测器比其他检测器更进一步。它实际上运行进一步的边缘细化步骤。因此,Canny检测器的输出是二值图像,用1像素宽的线代替边缘
另一方面,等高线
算法处理任意二值图像。因此,如果您在黑色背景上放入白色填充正方形。运行等高线
算法后,您将得到白色空白正方形,只有边框
轮廓检测的另一个额外好处是,它实际上返回一组点!这很好,因为您可以进一步使用这些点进行某些处理
在您的特殊情况下,两幅图像匹配只是巧合。这不是规则,在您的情况下,这是因为Canny算法的独特属性。边缘被计算为图像梯度方向上的极值点。
如果有帮助,可以将其视为一维函数中的最小点和最大点。
关键是,边缘像素是一个局部概念:它们只是指出相邻像素之间的显著差异
轮廓通常是从边缘获得的,但它们的目标是对象轮廓。
因此,它们需要是闭合曲线。
你可以把它们看作是边界(一些图像处理算法和图书馆这样称呼它们)。
从边缘获取轮廓时,需要连接边缘以获得闭合轮廓。轮廓的概念用作处理边缘数据的工具。并非所有边缘都是相同的。但在许多情况下,例如,具有单峰颜色分布(即一种颜色)的对象,边缘是实际轮廓(轮廓、形状)
不仅检测曲线,还检测边缘贴图上连接的任何东西。(连接组件分析)[1]
适用于具有单峰颜色分布的对象(使用简单的阈值很容易找到前景遮罩)。您的示例图像不适用
[1] 数字化二进制文件的拓扑结构分析
Satoshi Suzuki,1985年出版的《按边框排列的图像》。我建议在cv::Canny()之前使用cv::GaussianBlur()。这样可以在保留主边缘的同时去除大部分杂乱。因为findContours()用于二值图像,如果它使用Canny边缘检测器,我会非常惊讶。Sobel不是真正的边缘检测器,它只是提供梯度。Canny却找到了最大梯度,即梯度中的峰值。Canny()的OpenCV实现实际上使用了Sobel()在它的前端。非常感谢你的回复。我真的很感激:)那么,等高线总是在它们开始的地方结束?这有区别吗?是的,等高线是闭合的,而边可能是(多边形的)线条。那么,为什么这两个结果几乎相同?或者,这张图像在显示边缘
和轮廓
之间的差异时不好吗?