gpt4 book ai didi

c++ - Opencv:边缘检测、膨胀和质量中心绘图

转载 作者:可可西里 更新时间:2023-11-01 18:17:24 28 4
gpt4 key购买 nike

我的工作是基于带有点阵的图像(图 1),最终结果如图 4 所示。我将逐步解释我的工作。

图。 1张原图

enter image description here

第 1 步:检测每个对象的边缘,包括点和我想删除以获得更好性能的“环”。边缘检测的结果如图2所示。我使用了 Canny 边缘检测器,但它不能很好地处理一些浅灰色的点。 我的第一个问题是如何闭合点的轮廓并尽可能减少其他噪声?

图。 2 边缘检测

enter image description here

第 2 步:膨胀每个对象。没找到好的填洞方法,就直接扩孔了。如图 3 所示,孔似乎被放大了太多,其他噪声也是如此。 我的第二个问题是如何填充或扩大孔以使它们成为相同/相似大小的填充圆?

图。 3 膨胀

enter image description here

第 3 步:找到并画出每个点的质心。如图4所示,由于图像处理粗糙,存在“环”的痕迹,部分圆点显示在两个白色像素中。 想要的结果应该只显示点和一个点的一个白色像素。

图。 4:质量中心

enter image description here

这是这 3 个步骤的代码。谁能帮助我改进工作?

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
using namespace std;
using namespace cv;

// Global variables
Mat src, edge, dilation;
int dilation_size = 2;

// Function header
void thresh_callback(int, void*);

int main(int argc, char* argv)
{
IplImage* img = cvLoadImage("c:\\dot1.bmp", 0); // dot1.bmp = Fig. 1

// Perform canny edge detection
cvCanny(img, img, 33, 100, 3);

// IplImage to Mat
Mat imgMat(img);
src = img;

namedWindow("Step 1: Edge", CV_WINDOW_AUTOSIZE);
imshow("Step 1: Edge", src);

// Apply the dilation operation
Mat element = getStructuringElement(2, Size(2 * dilation_size + 1, 2 * dilation_size + 1),
Point(dilation_size, dilation_size)); // dilation_type = MORPH_ELLIPSE
dilate(src, dilation, element);
// imwrite("c:\\dot1_dilate.bmp", dilation);

namedWindow("Step 2: Dilation", CV_WINDOW_AUTOSIZE);
imshow("Step 2: Dilation", dilation);

thresh_callback( 0, 0 );

waitKey(0);
return 0;
}

/* function thresh_callback */
void thresh_callback(int, void*)
{
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;

// Find contours
findContours(dilation, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

// Get the moments
vector<Moments> mu(contours.size());
for(int i = 0; i < contours.size(); i++) {
mu[i] = moments(contours[i], false);
}

// Get the mass centers
vector<Point2f> mc(contours.size());
for(int i = 0; i < contours.size(); i++) {
mc[i] = Point2f(mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00);
}

// Draw mass centers
Mat drawing = Mat::zeros(dilation.size(), CV_8UC1);
for( int i = 0; i< contours.size(); i++ ) {
Scalar color = Scalar(255, 255, 255);
line(drawing, mc[i], mc[i], color, 1, 8, 0);
}

namedWindow("Step 3: Mass Centers", CV_WINDOW_AUTOSIZE);
imshow("Step 3: Mass Centers", drawing);
}

最佳答案

您可以采取一些措施来改善结果。要减少图像中的噪声,您可以在应用 Canny 运算符之前应用中值模糊。这是一种常见的去噪技术。另外,尽量避免使用 C API 和 IplImage

    cv::Mat img = cv::imread("c:\\dot1.bmp", 0);         // dot1.bmp = Fig. 1

cv::medianBlur(img, img, 7);

// Perform canny edge detection
cv::Canny(img, img, 33, 100);

这显着减少了边缘图像中的噪声量: Canny result

为了更好地保留点的原始大小,您可以使用较小的内核而不是扩张来执行几次形态学闭合迭代。这也将减少点与圆的连接:

// This replaces the call to dilate()
cv::morphologyEx(src, dilation, MORPH_CLOSE, cv::noArray(),cv::Point(-1,-1),2);

这将使用 3x3 内核执行两次迭代,使用 cv::noArray() 表示。

结果更干净,点被完全填满:

Closing result

保留管道的其余部分不变即可得到最终结果。仍然有一些来自圆的虚假质心,但比原来的方法少得多:

Mass centers

如果您想尝试从结果中完全删除圆圈,您可以尝试使用 cv::HoughCircles()并调整参数,直到得到好的结果。这可能会有一些困难,因为整个圆圈在图像中是不可见的,只有片段,但我建议您尝试一下。如果您确实检测到最里面的圆,您可以将它用作掩码来过滤掉外部质量中心。

关于c++ - Opencv:边缘检测、膨胀和质量中心绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17747674/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com