opencv不规则物体宽度测量

头文件:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
#include <math.h>
#define pi 3.1415926

using namespace cv;
using namespace std;

滤波函数:

void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit, int AreaTop, int CheckMode, int NeihborMode)
{
	int RemoveCount = 0;       //记录除去的个数  
							   //记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表检查不合格(需要反转颜色),3代表检查合格或不需检查  
	Mat Pointlabel = Mat::zeros(Src.size(), CV_8UC1);

	if (CheckMode == 1)
	{
		//cout<<"Mode: 去除小区域. ";  
		for (int i = 0; i < Src.rows; ++i)
		{
			uchar* iData = Src.ptr<uchar>(i);
			uchar* iLabel = Pointlabel.ptr<uchar>(i);
			for (int j = 0; j < Src.cols; ++j)
			{
				if (iData[j] < 10)
				{
					iLabel[j] = 3;
				}
			}
		}
	}
	else
	{
		//cout<<"Mode: 去除孔洞. ";  
		for (int i = 0; i < Src.rows; ++i)
		{
			uchar* iData = Src.ptr<uchar>(i);
			uchar* iLabel = Pointlabel.ptr<uchar>(i);
			for (int j = 0; j < Src.cols; ++j)
			{
				if (iData[j] > 10)
				{
					iLabel[j] = 3;
				}
			}
		}
	}

	vector<Point2i> NeihborPos;  //记录邻域点位置  
	NeihborPos.push_back(Point2i(-1, 0));
	NeihborPos.push_back(Point2i(1, 0));
	NeihborPos.push_back(Point2i(0, -1));
	NeihborPos.push_back(Point2i(0, 1));
	if (NeihborMode == 1)
	{
		//cout<<"Neighbor mode: 8邻域."<<endl;  
		NeihborPos.push_back(Point2i(-1, -1));
		NeihborPos.push_back(Point2i(-1, 1));
		NeihborPos.push_back(Point2i(1, -1));
		NeihborPos.push_back(Point2i(1, 1));
	}
	//else cout<<"Neighbor mode: 4邻域."<<endl;  
	int NeihborCount = 4 + 4 * NeihborMode;
	int CurrX = 0, CurrY = 0;
	//开始检测  
	for (int i = 0; i < Src.rows; ++i)
	{
		uchar* iLabel = Pointlabel.ptr<uchar>(i);
		for (int j = 0; j < Src.cols; ++j)
		{
			if (iLabel[j] == 0)
			{
				//********开始该点处的检查**********  
				vector<Point2i> GrowBuffer;                                      //堆栈,用于存储生长点  
				GrowBuffer.push_back(Point2i(j, i));
				Pointlabel.at<uchar>(i, j) = 1;
				int CheckResult = 0;                                               //用于判断结果(是否超出大小),0为未超出,1为超出  

				for (int z = 0; z<int(GrowBuffer.size()); z++)
				{

					for (int q = 0; q<NeihborCount; q++)                                      //检查四个邻域点  
					{
						CurrX = GrowBuffer.at(z).x + NeihborPos.at(q).x;
						CurrY = GrowBuffer.at(z).y + NeihborPos.at(q).y;
						if (CurrX >= 0 && CurrX<Src.cols&&CurrY >= 0 && CurrY<Src.rows)  //防止越界  
						{
							if (Pointlabel.at<uchar>(CurrY, CurrX) == 0)
							{
								GrowBuffer.push_back(Point2i(CurrX, CurrY));  //邻域点加入buffer  
								Pointlabel.at<uchar>(CurrY, CurrX) = 1;           //更新邻域点的检查标签,避免重复检查  
							}
						}
					}

				}
				if ((int(GrowBuffer.size())>AreaLimit)&(int(GrowBuffer.size())<AreaTop)) CheckResult = 2;                 //判断结果(是否超出限定的大小),1为未超出,2为超出  
				else { CheckResult = 1;   RemoveCount++; }
				for (int z = 0; z<int(GrowBuffer.size()); z++)                         //更新Label记录  
				{
					CurrX = GrowBuffer.at(z).x;
					CurrY = GrowBuffer.at(z).y;
					Pointlabel.at<uchar>(CurrY, CurrX) += CheckResult;
				}
				//********结束该点处的检查**********  


			}
		}
	}

	CheckMode = 255 * (1 - CheckMode);
	//开始反转面积过小的区域  
	for (int i = 0; i < Src.rows; ++i)
	{
		uchar* iData = Src.ptr<uchar>(i);
		uchar* iDstData = Dst.ptr<uchar>(i);
		uchar* iLabel = Pointlabel.ptr<uchar>(i);
		for (int j = 0; j < Src.cols; ++j)
		{
			if (iLabel[j] == 2)
			{
				iDstData[j] = CheckMode;
			}
			else if (iLabel[j] == 3)
			{
				iDstData[j] = iData[j];
			}
		}
	}

	//cout<<RemoveCount<<" objects removed."<<endl;  
}

主函数:

  1. 在获得的烟草区域内选取任意一点,以该点画圆,半径逐步增加,设定条件(在该圆中的烟草区域/圆的面积<某阈值),当不符合时,将圆进行空白区域中心的反向半径方向移动,直到满足条件(设定最大移动范围);
  2. 以此方法,在宽度方向上获得最大内接圆,烟草宽度即为圆的直径;
  3. 相同方法取多点,分别检测宽度(阈值),最后计算均值;
int main()
{
	char filename[100];
	for (int w = 1; w <= 1; w++)//
	{
		sprintf_s(filename, "../../准确性/1.bmp", w);//../../重复性/11-%d.bmp
		cout << filename<<"    ";
		Mat imgsrc = imread(filename, 1);
		Mat img_gray, img_by, img_by1;
		cvtColor(imgsrc, img_gray, CV_BGR2GRAY);//彩色转灰度图
		adaptiveThreshold(img_gray, img_by, 255, ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, 9, 10);
		RemoveSmallRegion(img_by, img_by, 100, 3000, 1, 0);

		vector<vector<Point>> contours;
		findContours(img_by, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);//查找最外侧轮廓
		//1最大外接圆
		//int dist = 0;
		//int maxdist = 0;
		//Point center;
		//for (int i = 0; i<imgsrc.cols; i++)
		//{
		//	for (int j = 0; j<imgsrc.rows; j++)
		//	{
		//		dist = pointPolygonTest(contours[0], cv::Point(i, j), true);
		//		if (dist <= 0)
		//			continue;
		//		if (dist>maxdist)
		//		{
		//			maxdist = dist;
		//			center = cv::Point(i, j);
		//		}
		//	}
		//}
		//circle(img_by, center, maxdist, Scalar(0),-1);
		//imshow("zc", img_gray);

		//2
		for (int q = 0; q < contours.size(); q++)
		{
			RNG rng;//随机数
			Point2f point;
			double radius_all = 0;
			for (int p = 0; p < 4; p++)
			{
				int num = rng.uniform(0, contours[q].size());
				point = Point2f(contours[q][num].x, contours[q][num].y);//随机点

				double radius;//半径
				double resulit_limit = 0.9;

				for (radius = 2.0; radius < 5.0; radius += 0.1)//随机圆变化起点
				{
					int baidian_num = 0;
					int baidian_x = 0;
					int baidian_y = 0;
				restart:
					for (int i = point.y - radius; i < point.y + radius; i++)//计算区域在圆内像素个数
						for (int j = point.x - radius; j < point.x + radius; j++)
						{
							if (img_by.at<uchar>(i, j) == 255 && ((point.y - i)*(point.y - i) + (point.x - j)*(point.x - j) < radius*radius))
							{
								baidian_num++;
								baidian_x += j;
								baidian_y += i;
							}
						}
					double result = baidian_num / (pi*radius*radius);//计算占比
					if (result < resulit_limit)//移动圆心位置
					{
						point.x = point.x + (baidian_x / baidian_num - point.x) / 2;//x方向
						point.y = point.y + (baidian_y / baidian_num - point.y) / 2;//y方向
						goto restart;
					}
					else if ((result > resulit_limit) && (result < 1))
					{
						if ((baidian_x / baidian_num - point.x) *(baidian_x / baidian_num - point.x) + (baidian_y / baidian_num - point.y) * (baidian_y / baidian_num - point.y) < 0.5)
							break;
					}
					else if (result == 1)
						continue;//半径自增	
				}
				radius_all += radius;

			}
			cout << radius_all / 4.0 * 2.0 << "  pixels" << endl;
		}


	}

	system("pause");
}

测试图像:

运行结果:

猜你喜欢

转载自blog.csdn.net/qq_36638362/article/details/84561557
今日推荐