OpenCV 实例:二值图像分析案例2-检测数量和缺失位置

目标:检测工具盒中工件的个数及缺失工件的位置。

思路:灰度转换,形态学处理,二值化,轮廓处理,拟合圆,位置分析等。

代码:

// CountElement.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

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

int main()
{
    std::cout << "Hello World!\n";

	Mat srcImage = imread("2.jpg");
	namedWindow("原始图");
	imshow("原始图", srcImage);

	Mat grayImage;
	cvtColor(srcImage, grayImage, COLOR_RGB2GRAY);
	//namedWindow("grayImage");
	//imshow("grayImage", grayImage);

	

	Mat kernal = getStructuringElement(MORPH_RECT, Size(3, 3));
	Mat gradientImage;
	morphologyEx(grayImage, gradientImage, MORPH_GRADIENT, kernal);
	namedWindow("gradientImage形态学梯度");
	imshow("gradientImage形态学梯度", gradientImage);

	Mat thresholdImage;
	threshold(gradientImage, thresholdImage, 0, 255, THRESH_OTSU);
	namedWindow("二值化OTSU图");
	imshow("二值化OTSU图", thresholdImage);
	//imwrite("thresholdImage.jpg", thresholdImage);

	

	kernal = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));

	Mat openImage;
	morphologyEx(thresholdImage, openImage, MORPH_OPEN, kernal);
	//namedWindow("openImage");
	//imshow("openImage", openImage);

	kernal = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
	Mat closeImage;
	morphologyEx(openImage, closeImage, MORPH_CLOSE, kernal);
	namedWindow("closeImage");
	imshow("closeImage", closeImage);

	/*Mat cannyImage;
	Canny(closeImage, cannyImage, 50, 100);
	namedWindow("cannyImage");
	imshow("cannyImage", cannyImage);*/

	

	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(closeImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

	Mat resultImage = Mat::zeros(grayImage.rows, grayImage.cols, grayImage.type());
	int total = 0;
	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);
		if (area < 55) continue;

		total++;
		RotatedRect rect = minAreaRect(contours[i]);

		//Point2f rectVertex[4];
		//rect.points(rectVertex);

		circle(resultImage, rect.center, 5, Scalar(255),-1);
	}

	vector<Point> pts;
	for (int i = 0; i < resultImage.rows; i++)
	{
		for (int j = 0; j < resultImage.cols; j++)
		{
			if (resultImage.ptr<uchar>(i)[j] == 255)
			{
				pts.push_back(Point(j, i));
			}
		}
	}

	RotatedRect rect = minAreaRect(pts);
	Point2f rectVertex[4];
	rect.points(rectVertex);

	for (int i = 0; i < 4; i++)
	{
		putText(resultImage, to_string(i), rectVertex[i], FONT_HERSHEY_SIMPLEX, 1.0, Scalar(200));
		line(resultImage, rectVertex[i], rectVertex[(i + 1) % 4], Scalar(100), 2, 8);
	}
	cout << "角度为:" << rect.angle;
	cout << "宽度为:" << rect.size.width;
	cout << "高度为:" << rect.size.height;
	namedWindow("resultImage");
	imshow("resultImage", resultImage);

	Mat matrix = getRotationMatrix2D(rect.center, rect.angle, 1);
	warpAffine(resultImage, resultImage, matrix, resultImage.size());
	warpAffine(srcImage, srcImage, matrix, srcImage.size());
	

	//-----------------------------------------------------------------
	//计算每行工具所在的行数
	vector<int> bins;
	vector<int> tbins;
	for (int i = 0; i < resultImage.rows; i++) {
		int found = 0;
		for (int j = 0; j < resultImage.cols; j++) {

			if (resultImage.at<uchar>(i, j) == 255) {

				found += 1;
			}
		}
		if (found > 0) {
			cout << i<<endl;
			bins.push_back(i);
		}
	}	
	for (int i = 0; i < (bins.size() - 1); i++) {

		int gap = bins[i + 1] - bins[i];
		if (gap >= 15) {
			cout << "tbins: " << bins[i + 1] - (gap / 2)<<endl;
			tbins.push_back(bins[i + 1] - (gap / 2));
		}
	}
	//-----------------------------------------------------------------

	//-----------------------------------------------------------------
	//逐行排查缺失工具的位置
	Mat dstImage;
	srcImage.copyTo(dstImage);
	int h = resultImage.rows - 1;
	for (int i = 0; i < tbins.size(); i++) {
		if (i == 0) 
		{
			//第一排工具所占行数从0到第一个位置
			Y_projection(resultImage, dstImage, 50, i, tbins[i]);
		}
		else if (i == (tbins.size() - 1)) 
		{
			//最后一排工具所占行数从最后一个位置到图片最后一行
			Y_projection(resultImage, dstImage, 50, tbins[i], h);
		}
		else
		{
			//中间行工具所占行数为上下两个位置之间
			int end = tbins[i] - 1;
			Y_projection(resultImage, dstImage, 50, tbins[i - 1], end);
		}
	}
	//-----------------------------------------------------------------



	//namedWindow("resultImage");
	//imshow("resultImage", resultImage);

	putText(dstImage, "numvers: "+to_string(total),Point(50,50), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255,255,255));
	namedWindow("dstImage");
	imshow("dstImage", dstImage);


	waitKey(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 >= 15) {
			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,255,255), -1);
		}
	}

}



发布了93 篇原创文章 · 获赞 2 · 访问量 3063

猜你喜欢

转载自blog.csdn.net/qq_40041064/article/details/104532380
今日推荐