我正在尝试识别图像中的所有圆圈。增强对比度后,使用阈值,使用精确边缘我找到所有轮廓并循环遍历它们,结果图像上的区域> 0。结果并不好。请协助...
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void changeGain(cv::Mat&,double,int);
int main(int argc, char** argv)
{
// Load the original image and make a duplication
cv::Mat rawImage = cv::imread("..\\3.png");
cv::Mat duplicateImage= rawImage.clone();
// Add contrast
changeGain(duplicateImage,1.9 ,-240);
// Apply thershold
cv::threshold( duplicateImage, duplicateImage, 150, 200, cv::THRESH_BINARY );
// Use canny edges
cv::Mat img_canny;
cv::Canny(duplicateImage,img_canny,150,200);
// Find all the contours from the canny image
vector<vector<cv::Point>> contours;
findContours(img_canny, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
// Approximate contours to polygons + get circles
vector<vector<Point> > contours_poly;
for( int i = 0; i < contours.size(); i++ )
{
double area = contourArea(contours[i],true);
if (area > 0 )
contours_poly.push_back(contours[i]);
}
// Draw the circles on the image
drawContours(rawImage, contours_poly, -1, Scalar(rand() & 255, rand() & 255, rand() & 255));
// Show result
cv::imshow("Final Result", rawImage);
cv::waitKey(0);
imwrite("..\\contour_result.jpg",rawImage);
}
void changeGain(cv::Mat& image,double alpha, int beta)
{
//cv::Mat new_image = cv::Mat::zeros( image.size(), image.type() );
/// Do the operation new_image(i,j) = alpha*image(i,j) + beta
for( int y = 0; y < image.rows; y++ )
{
for( int x = 0; x < image.cols; x++ )
{
for( int c = 0; c < 3; c++ )
image.at<cv::Vec3b>(y,x)[c] =
cv::saturate_cast<uchar>( alpha*( image.at<cv::Vec3b>(y,x)[c] ) + beta );
}
}
return;
}
这是原始图像
这是显示所有轮廓时的结果
这是仅显示面积> 0的轮廓时的结果
阈值后的图像
首先,考虑使用形态学(https://docs.opencv.org/trunk/d9/d61/tutorial_py_morphological_ops.html)来清理然后阈值化的图像。使用诸如打开然后关闭之类的东西将消除噪声并填充阈值图像中的间隙。
其次,您不需要检测Canny边缘。你可以从阈值中提取轮廓就好了,这就是我正在为我当前的项目做的事情。
第三,我假设你正在寻找圈子,在这种情况下你可以使用minEnclosingCircle
(https://docs.opencv.org/3.3.1/d3/dc0/group__imgproc__shape.html#ga8ce13c24081bbc7151e9326f412190f1)。由于形状是一个圆形,它应该只包围圆形,你可以通过比较轮廓的contourArea
和圆形区域与minEnclosingCircle
返回的半径来确定。如果你的轮廓确实是一个圆圈,这个比例应该接近1.(这也是我目前使用的一种技术)。