OpenCV实战(四)——对象(圆)提取

      现在我们想从一个杂乱的背景中提取出某个规则图像的轮廓,比方说圆。我们如何才能在一张图像中找的圆的轮廓,同时找到它的圆心坐标以及它的面积和周长呢?我的思路是阈值分割+形态学处理+高宽比过滤。大家也可以尝试下霍夫圆检测的思路。

       接下我们编写代码:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace cv;
using namespace std;

Mat src_img, binary_img, dst_img;
int main()
{
	src_img = imread("2018.4.26.png", IMREAD_GRAYSCALE); 
	//灰度读取,在读入图像的同时进行色彩转换,这可以提高运行速度并减少内存的使用
	if (src_img.empty())
	{
		printf("could not load the image...\n");     
		return -1;
	}
	namedWindow("原图", CV_WINDOW_AUTOSIZE);
	imshow("原图", src_img);

	// 图像二值化
	threshold(src_img, binary_img, 0, 255, THRESH_BINARY | THRESH_OTSU);
	imshow("二值图像", binary_img);

	// 形态学操作
	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));   // 构建形态学操作的结构元
	morphologyEx(binary_img, dst_img, MORPH_CLOSE, kernel, Point(-1, -1));      //闭操作
	imshow("闭操作", dst_img);

	kernel = getStructuringElement(MORPH_RECT, Size(5,5), Point(-1, -1));     // 构建形态学操作的结构元
	morphologyEx(dst_img, dst_img, MORPH_OPEN, kernel, Point(-1, -1));                 //开操作
	imshow("开操作", dst_img);

	// 寻找轮廓
	vector<vector<Point>> contours;
	vector<Vec4i> hireachy;
	findContours(dst_img, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());

	Mat result_img = Mat::zeros(src_img.size(), CV_8UC3);     // 创建与原图同大小的黑色背景
	Point circle_center;              //定义圆心坐标
	for (auto t = 0; t < contours.size(); ++t)
	{
		// 面积过滤
		double area = contourArea(contours[t]);     //计算点集所围区域的面积
		if (area < 100)            //晒选出轮廓面积大于100的轮廓
			continue;
		// 横纵比过滤
		Rect rect = boundingRect(contours[t]);            // 求点集的最小直立外包矩形
		float ratio = float(rect.width) / float(rect.height);        //求出宽高比

		if (ratio < 1.1 && ratio > 0.9)       //因为圆的外接直立矩形肯定近似于一个正方形,因此宽高比接近1.0
		{ 
			drawContours(result_img, contours, t, Scalar(0, 0, 255), -1, 8, Mat(), 0, Point());    ////在黑色背景图上画出圆,注意其中参数-1的意义
			printf("圆的面积: %f\n", area);
			double arc_length = arcLength(contours[t], true);         //计算点集所围区域的周长
			printf("圆的周长 : %f\n", arc_length);
			int x = rect.x + rect.width / 2;
			int y = rect.y + rect.height / 2;
			circle_center = Point(x, y);          //得到圆心坐标
			cout << "圆心坐标:" << "宽"<<circle_center.x<<" "<<"高"<< circle_center.y << endl;
			circle(result_img, circle_center, 2, Scalar(0, 255, 255), 2, 8, 0);  
		}
	}
	imshow("结果", result_img);

	Mat circle_img = src_img.clone();
	cvtColor(circle_img, circle_img, COLOR_GRAY2BGR);    //灰度图转化为彩色图
	circle(circle_img, circle_center, 2, Scalar(0, 0, 255), 2, 8, 0);    //在原图上画出圆心
	imshow("最终结果", circle_img);

	waitKey(0);
	return 0;
}

运行程序,如下:




显然结果很准确!

猜你喜欢

转载自blog.csdn.net/weixin_41695564/article/details/80099917
今日推荐