要求:当无人叉车接收到前面给定物资的具体坐标后,将车上物资全部运走,剩下空车,这时候需要对空车再进行一遍扫描,确定空车可以摆放多少件物资,以及摆放物资的大概位置(我理解的这一个步骤获取只是为了在界面上展示好看一点),单单只是普通的空车,计算上面能够摆放多少件物资并不难,难得是有些空车的货箱前半部分会稍微高一点。

为了表达清晰。将普通车型记为 C,将车身前微高一点的车型记为C_h

思路:

大致思路还是利用到了最小外接矩,找到角点。

1、首先要判断车型,即是否是前面稍高的车型(图中红线标记的地方,两侧灰度值明显不同),设置二值化阈值(阈值设置是个重要的点),利用最小外接矩找到车身轮廓的四个角点(图中绿色的点),如果被扫描车型是C_h,阈值设置不当会导致外接矩找到较小矩形的四个角点。

看图:

实现物品识别后播报出来python代码_灰度值

根据绿色角点坐标,找到蓝色点,计算两个蓝色点之间的灰度值,设置阈值,即可判断车型,因为灰度值是通过车高转换得到的,所以就可以根据两点的灰度值来判断具体车型。

部分代码:

A.x = static_cast<int>((rectB[2].x + rectB[3].x) / 2);
A.y = static_cast<int>((rectB[2].y + rectB[3].y) / 2 + 50);
Ag = matGray.at<uchar>(Point(A.x, A.y));  //A点灰度值
circle(matSrc, Point(A.x, A.y), 5, Scalar(255, 0, 0), -1, 8);

B.x = (rectB[1].x + rectB[0].x) / 2;
B.y = (rectB[1].y + rectB[0].y) / 2 - 50;
Bg = matGray.at<uchar>(Point(B.x, B.y));  //B点灰度值
circle(matSrc, Point(B.x, B.y), 5, Scalar(255, 0, 0), -1, 8);

在灰度图中获取某一点的灰度值的时候,遇到了一个没有整明白原因的错误,

Ag = matGray.at<uchar>(Point(A.x, A.y));  //A点灰度值

之前获取多通道的像素值可以直接使用 mat.at<Vec3b>(x,y)[0]直接获取,而获取灰度值的时候,直接敲坐标会报如下错误:Assertion failed <y==0||<data && dims>+1 && <unsigned>y<<unsigned>size.p[0]>>

解决办法,就是用Point ,具体原因,同事说是图片(217*1492)像素值太大,超过电脑的分辨率(1920*1080),将图片倒着就可以了,下午我也以为是这个原因,到了晚上刚刚又实验了一下,竟然通过了,搞不懂~不过总算是找到方法解决了

2、经过对两点灰度值的计算,就可以判定具体车型了,车型C比较简单,这里写一下C_h,

由于车身前面高出来一部分,要根据物资的长宽计算高出来的那一部分可以放多少个,才不会由于摆放的原因,对物资造成损坏

同样的,根据设置阈值,计算高出矩形的最小外接矩,计算长度之后和物资长度进行比较,设定阈值,即可判定高出部分具体可以摆放物资的数量。

车身其余部分,根据车身长度和物资长度等分即可。写到这里突然觉得我得表述能力很有问题~我直接上图把。根据等分点公式,找到红色点,描述完了,突然感觉没有什么技术含量的东西,我搞了两三天,比较low,可是如果可以将简单得问题,实现,并运用到项目中,我也是比较骄傲的。

实现物品识别后播报出来python代码_P4_02

 上一段判断车型的代码吧,感觉现场调参很重要,因为要根据具体车高,调整二值化的阈值。

#include<iostream>
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
cv::Mat GetStructElement(int elem, int size)
{
	int type;
	if (elem == 0) { type = cv::MORPH_RECT; }
	else if (elem == 1) { type = cv::MORPH_CROSS; }
	else if (elem == 2) { type = cv::MORPH_ELLIPSE; }
	return cv::getStructuringElement(type, cv::Size(2 * size + 1, 2 * size + 1), cv::Point(size, size));
}
int main()
{
	Mat matSrc = imread("car_high_up.jpg");

	Mat matGray;
	cvtColor(matSrc, matGray, CV_BGR2GRAY);
	Point2f rectB[4];
	Point2f rectS[4];
	Point2f P0, P1, P2, P3, P4, P5;
	//Big
	Mat matBinaryB;
	threshold(matGray, matBinaryB, 225, 255, CV_THRESH_BINARY);
	Mat elementB = GetStructElement(MORPH_RECT, (30, 30));
	morphologyEx(matBinaryB, matBinaryB, MORPH_CLOSE, elementB);
	Mat matB = matBinaryB.clone();

	vector<vector<Point>> contoursB;
	vector<Vec4i> hierarchyB;
	findContours(matB, contoursB, hierarchyB, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
	
	for (size_t i = 0; i < contoursB.size(); i++)
	{
		double area = contourArea(contoursB[i]);
		if (area > 10000 && area < 200000)
		{
			RotatedRect box = minAreaRect(contoursB[i]);
			box.points(rectB);
			for (int i = 0; i < 4; i++)
			{
				circle(matSrc, Point(rectB[i].x, rectB[i].y), 5, Scalar(255, 0, 0), -1, 8);
			}

			P0.x = ((4 - 1)*rectB[0].x + 1 * rectB[1].x) / 4;
			P0.y = ((4 - 1)*rectB[0].y + 1 * rectB[1].y) / 4;
			circle(matSrc, Point(P0.x, P0.y), 5, Scalar(0, 255, 0), -1, 8);

			P1.x = ((4 - 3)*rectB[0].x + 3 * rectB[1].x) / 4;
			P1.y = ((4 - 3)*rectB[0].y + 3 * rectB[1].y) / 4;
			circle(matSrc, Point(P1.x, P1.y), 5, Scalar(0, 255, 0), -1, 8);

			P2.x = ((4 - 1)*rectB[2].x + 1 * rectB[3].x) / 4;
			P2.y = ((4 - 1)*rectB[2].y + 1 * rectB[3].y) / 4;
			circle(matSrc, Point(P2.x, P2.y), 5, Scalar(0, 255, 0), -1, 8);

			P3.x = ((4 - 3)*rectB[2].x + 3 * rectB[3].x) / 4;
			P3.y = ((4 - 3)*rectB[2].y + 3 * rectB[3].y) / 4;
			circle(matSrc, Point(P3.x, P3.y), 5, Scalar(0, 255, 0), -1, 8);
		}

	}

	//Small
	Mat matBinaryS;
	threshold(matGray, matBinaryS, 220, 255, CV_THRESH_BINARY);
	Mat elementS = GetStructElement(MORPH_RECT, (30, 30));
	morphologyEx(matBinaryS, matBinaryS, MORPH_CLOSE, elementS);
	Mat matS = matBinaryS.clone();

	vector<vector<Point>> contoursS;
	vector<Vec4i> hierarchyS;
	findContours(matS, contoursS, hierarchyS, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
	for (size_t i = 0; i < contoursS.size(); i++)
	{
		double area = contourArea(contoursS[i]);
		if (area > 10000 && area < 200000)
		{
			RotatedRect box = minAreaRect(contoursS[i]);
			box.points(rectS);
			
			circle(matSrc, Point(rectS[3].x, rectS[3].y), 5, Scalar(255, 0, 0), -1, 8);
			circle(matSrc, Point(rectS[0].x, rectS[0].y), 5, Scalar(255, 0, 0), -1, 8);

			P5.x = ((4 - 1)*rectS[0].x + 1 * rectS[3].x) / 4;
			P5.y = ((4 - 1)*rectS[0].y + 1 * rectS[3].y) / 4;
			circle(matSrc, Point(P5.x, P5.y), 5, Scalar(0, 255, 0), -1, 8);

			P4.x = ((4 - 3)*rectS[0].x + 3 * rectS[3].x) / 4;
			P4.y = ((4 - 3)*rectS[0].y + 3 * rectS[3].y) / 4;
			circle(matSrc, Point(P4.x, P4.y), 5, Scalar(0, 255, 0), -1, 8);
		}
	}
	cout << "******************************************************" << endl;
	double dis = sqrt( (rectS[1].x - rectS[0].x) * (rectS[1].x - rectS[0].x) + (rectS[1].y - rectS[0].y) * (rectS[1].y - rectS[0].y));
	if (dis >= 383)  //当凸出来的面积高度大于2.8 米,也就是在像素中大于383时 ,可以放下两个变压器
	{
		for (int i = 1; i < 4; i = i + 2)
		{
			Point2f Pc1,Pc2;
			Pc1.x = ((4 - i)*P2.x + i*P5.x) / 4;
			Pc1.y = ((4 - i)*P2.y + i*P5.y) / 4;
			circle(matSrc, Point(Pc1.x, Pc1.y), 6, Scalar(0, 0, 255), -1, 8);
			Pc2.x = ((4 - i)*P3.x + i*P4.x) / 4;
			Pc2.y = ((4 - i)*P3.y + i*P4.y) / 4;
			circle(matSrc, Point(Pc2.x, Pc2.y), 6, Scalar(0, 0, 255), -1, 8);		
			cout << "	" << "(" << Pc1.x << "," << Pc1.y << ")" << "	" << "(" << Pc2.x << "," << Pc2.y << ")" << endl;
		}
	}
	else
	{
		Point2f Pc1, Pc2;
		Pc1.x = (P2.x + P5.x) / 2;
		Pc1.y = (P2.y + P5.y) / 2;
		circle(matSrc, Point(Pc1.x, Pc1.y), 6, Scalar(0, 0, 255), -1, 8);
		Pc2.x = (P3.x + P4.x) / 2;
		Pc2.y = (P3.y + P4.y) / 2;
		circle(matSrc, Point(Pc2.x, Pc2.y), 6, Scalar(0, 0, 255), -1, 8);
		cout << "	" << "(" << Pc1.x << "," << Pc1.y << ")" << "	" << "(" << Pc2.x << "," << Pc2.y << ")" << endl;
	}

	//确定n的值
	double car_h = sqrt((P5.x - P1.x) * (P5.x - P1.x) + (P5.y - P1.y) * (P5.y - P1.y));
	double T_h = 200;       //最大变压器的像素值
	int N = floor(car_h / T_h);
	int n = N * 2;
	for (int i = 1; i < n; i = i + 2)
	{
		Point2f Pc1,Pc2;
		Pc1.x = ((n - i)*P5.x + i*P1.x) / n;
		Pc1.y = ((n - i)*P5.y + i*P1.y) / n;
		circle(matSrc, Point(Pc1.x, Pc1.y), 6, Scalar(0, 0, 255), -1, 8);
		Pc2.x = ((n - i)*P4.x + i*P0.x) / n;
		Pc2.y = ((n - i)*P4.y + i*P0.y) / n;
		circle(matSrc, Point(Pc2.x, Pc2.y), 6, Scalar(0, 0, 255), -1, 8);
		cout << "	" << "(" << Pc1.x << "," << Pc1.y << ")" << "	" << "(" << Pc2.x << "," << Pc2.y << ")" << endl;
	}

	namedWindow("picture",WINDOW_NORMAL);
	imshow("picture", matSrc);
	waitKey(0);
	return 0;
}

运行结果:

标记后的效果图,即为上图。

实现物品识别后播报出来python代码_实现物品识别后播报出来python代码_03