基于opencv的珠盘个数检测(c++)

目标:检测该图片上的个数与缺几个并标出来

在这里插入图片描述
效果图:
在这里插入图片描述
算法原理:
先加载原图然后进行转灰度,进行形态学梯度处理,接着二值化,在进行2次形态学处理,提取轮廓(计算面积->寻找最小包围矩形)然后在进行角度纠正,再映射到X,Y寻找缺点

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

using namespace cv;
using namespace std;

void Y_projection(Mat &warp, Mat &src, int max_gap, int &first, int &end);

int main(int argc, char** argv) {

	Mat src = imread("E:/opencv/yuandian.jpg");
	imshow("src", src);

	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);

	//获取自定义核
	Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));

	//形态学梯度(膨胀与腐蚀之差,保留物体的边缘)
	Mat dst;
	morphologyEx(gray, dst, MORPH_GRADIENT, element);
	//imshow("xingtaixuetidu", dst);
	
	//二值化
	Mat binary;
	threshold(dst, binary, 0, 255, THRESH_OTSU | THRESH_BINARY);
	imshow("binary", binary);

	//形态学处理
	Mat element_1 = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
	//开运算(先腐蚀在膨胀,消除小物体,在细点分离物体)
	morphologyEx(binary, binary, MORPH_OPEN, element_1);
	imshow("MORPH_OPEN", binary);
	
	//闭运算(先膨胀在腐蚀,排除小型黑洞连接断点)
	Mat elemetn_2 = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
	morphologyEx(binary, binary, MORPH_CLOSE, elemetn_2);
	imshow("MORPH_CLOSE", binary);

	//提取轮廓
	vector < vector<Point >> contours;
	findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	
	//创建一个和原图像大小的Mat
	Mat result = Mat::zeros(binary.size(), binary.type());
	int total = 0;
	for (size_t i = 0; i < contours.size(); i++) {
		double area = contourArea(contours[i]);
		if (area < 55) {
			continue;
		}
		//寻找最小包围矩形
		RotatedRect rrt = minAreaRect(contours[i]);
		Point2f vertex[4];
		rrt.points(vertex);
		circle(result, rrt.center, 5, (255), -1);
		total += 1;
	}
	imshow("result", result);

Mat warp;
	Mat rotMat = getRotationMatrix2D(Point2f((result.rows - 1) / 2, (result.cols - 1) / 2), 177,-1);
	warpAffine(result, warp, rotMat, result.size());
	warpAffine(src, src, rotMat, src.size());
	imshow("warp", warp);
	imshow("src warp", src);


	/////////
	
	vector<int> bins;
	for (int i = 0; i < warp.rows; i++) {
		int found = 0;
		for (int j = 0; j < warp.cols; j++) {

			if (warp.at<uchar>(i, j) == 255) {
				
				found += 1;
			}
		}
		if (found > 0) {
			bins.push_back(i);
		}
	}
	


	/////////
	vector<int> tbins;
	for (int i = 0; i < (bins.size()-1); i++) {
		
		int gap = bins[i + 1] - bins[i];
		if (gap >= 15) {
			tbins.push_back(bins[i + 1] - (gap/2));
		}	
	}

	int h = warp.rows - 1;

	for (int i = 0; i < tbins.size(); i++) {
		if (i == 0) {
			Y_projection(warp, src, 50, i, tbins[i]);
		}
		else if(i==(tbins.size()-1)){
			Y_projection(warp, src, 50, tbins[i],h);
		}
		else
		{
			int end = tbins[i] - 1;
			Y_projection(warp, src, 50, tbins[i-1], end);
		}
	}
	String number = "number:" + to_string(total);
	putText(src, number,Size(50,50),FONT_HERSHEY_SIMPLEX,1.0,Scalar(0,0,255),2);
	imshow("fianl_src", src);

waitKey(0);
	return 0;
}

void Y_projection(Mat &warp,Mat &src,int max_gap,int &first,int &end) {

	vector<int> y_bins;
	for (int i = 0; i < warp.cols; i++) {
		int found_y = 0;
		for (int j = first; j < end; j++) {

			if (warp.at<uchar>(j, i) == 255) {
			
				found_y += 1;
			}
		}
		if (found_y > 0) {
			y_bins.push_back(i);
		}
	}

	vector<int> y_tbins;
	for (int i = 0; i < y_bins.size()-1; i++) {
		
			int gap = y_bins[i + 1] - y_bins[i];
			if (gap >= 7) {
				y_tbins.push_back(y_bins[i + 1] - (gap/2));
			}
			if (gap >= 50) {
				circle(src, Point(y_bins[i + 1] - (gap / 2),(end-(end-first)/2)), 5, Scalar(0,0,255), -1);
			}
		
		
	}

}

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐