c++识别象限标

        最近用到象限标定位,去网上找资料发现这方面的介绍太少了,就用了传统的方法(形状+颜色)进行检测,后期如果发现更好的方法,再来更新。象限标样式如下图所示

        思想是:在每帧图像中进行Hough圆检测,遍历检测到的每一个圆,进行透视变换到一个新图上,在每一个圆中,检测是否同时有黄色和黑色区域,且面积达到一定值,如果有,则是象限标,显示在最终结果图上,并获取圆心,否则不做处理,对最终获取的两个象限表进行距离计算,得出成像画面中的距离值。

 一.打开摄像头循环读取帧

程序如下:

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace std;
using namespace cv;

void main()
{
	Mat frame;
	VideoCapture cap(0);   //0:打开本机摄像头;1:打开外接摄像头
	if (cap.isOpened())
	{
		cap.set(CAP_PROP_FRAME_WIDTH, 1080);  // 设置摄像头的分辨率为1080*960
		cap.set(CAP_PROP_FRAME_HEIGHT, 960);
		while (true)
		{
			cap.read(frame);
			namedWindow("帧", WINDOW_AUTOSIZE);
			imshow("帧", frame);
			if (waitKey(100) == 27)  // 按ESC退出;
			{
				break;
			}

		}
	}

}

二.进行Hough圆检测

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace std;
using namespace cv;

void main()
{
	Mat frame, img_gray, img_blur;
	VideoCapture cap(0);   //0:打开本机摄像头;1:打开外接摄像头
	if (cap.isOpened())
	{
		cap.set(CAP_PROP_FRAME_WIDTH, 1080);  // 设置摄像头的分辨率为1080*960
		cap.set(CAP_PROP_FRAME_HEIGHT, 960);
	}

	vector<Vec3f>circles;
	Vec3f circle;
	Mat img_cont;
	Mat matrix, imgWarp;
	while (true)
	{
		cap.read(frame);
		img_cont = frame.clone();
		cvtColor(frame, img_gray, COLOR_BGR2GRAY);  // 灰度变换
		medianBlur(img_gray, img_blur, 3);  // 中值滤波

		//hough圆检测
		HoughCircles(img_blur, circles, HOUGH_GRADIENT, 1, 10, 100, 30, 5, 50);
		for (size_t i = 0; i < circles.size(); i++)  // 遍历每帧图像所有的圆
		{
			circle = circles[i];
			cv::circle(img_cont, Point(circle[0], circle[1]), circle[2], Scalar(255, 0, 0)); // 画圆
			cv::circle(img_cont, Point(circle[0], circle[1]), 2, Scalar(255, 0, 0));   //画圆心
			float w = circle[2];
			float h = circle[2]; // 透视图的宽高
			//获取每个圆的外接矩形
			Point2f src[4] = { {circle[0] - circle[2],circle[1] - circle[2]},  //矩形左上角坐标
								{circle[0] + circle[2],circle[1] - circle[2]}, //矩形右上角坐标
								{circle[0] - circle[2],circle[1] + circle[2]},  //矩形左下角
								{circle[0] + circle[2],circle[1] + circle[2]},  //矩形右下角

			};
			Point2f dir[4] = { {0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h} };
			matrix = getPerspectiveTransform(src, dir); // 透视变换,实现两张图像同一个点的对应关系
			warpPerspective(frame, imgWarp, matrix, Point(w, h)); // 将检测的圆画在imgWarp上
		}

		cv::namedWindow("帧", WINDOW_AUTOSIZE);
		cv::imshow("帧", frame);

		cv::namedWindow("Hough圆检测", WINDOW_AUTOSIZE);
		cv::imshow("Hough圆检测", img_cont);

		cv::namedWindow("透视图", WINDOW_AUTOSIZE);
		cv::imshow("透视图", imgWarp);
		if (waitKey(100) == 27)  // 按ESC退出;
		{
			break;
		}

		}

}

思想:在每帧图像上进行Hough圆检测,会检测出来许多圆,如下图所示,后续如何过滤出需要的圆?通过颜色检测,所以这里需要在每帧图像上遍历所有的圆,在每个圆内进行颜色检测。所以这里用到了透视变换。

三.颜色检测

在进行颜色检测之前,需要提取出黄黑的HSV值。提取代码如下所示。

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace std;
using namespace cv;

void main()
{
	VideoCapture cap(0);
	if (cap.isOpened())
	{
		cap.set(CAP_PROP_FRAME_WIDTH, 1080);
		cap.set(CAP_PROP_FRAME_HEIGHT, 960);
	}
	Mat frame, img_HSV,mask;
	int hmin = 0, smin = 110, vmin = 150;
	int hmax = 255, smax = 255, vmax = 255;

	namedWindow("HSV调节", (640, 640));
	createTrackbar("Hue Min", "HSV调节", &hmin, 255);
	createTrackbar("Hue Max", "HSV调节", &hmax, 255);
	createTrackbar("Sat Min", "HSV调节", &smin, 255);
	createTrackbar("Sat Max", "HSV调节", &smax, 255);
	createTrackbar("val Min", "HSV调节", &vmin, 255);
	createTrackbar("val Max", "HSV调节", &vmax, 255);

	while (true)
	{
		cap.read(frame);
		cvtColor(frame, img_HSV, COLOR_BGR2HSV); // 进行HSV变换
		Scalar lower(hmin, smin, vmin);
		Scalar upper(hmax, smax, vmax);
		inRange(img_HSV, lower, upper, mask);

		namedWindow("帧", WINDOW_AUTOSIZE);
		imshow("帧", frame);

		namedWindow("HSV", WINDOW_AUTOSIZE);
		imshow("HSV", img_HSV);

		namedWindow("mask", WINDOW_AUTOSIZE);
		imshow("mask", mask);
		if (waitKey(100) == 27)
		{
			break;
		}
	}
}

黄色提取结果如下图所示

 将黄色与黑色的HSV阈值带入代码中。

四.最终代码

#include <opencv2/opencv.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace std;
using namespace cv;

//int hmin = 0, smin = 110, vmin = 153;
//int hmax = 255, smax = 240, vmax = 255;
int area_y, area_d;

RNG rng(12345); // 产生随机颜色

int main()
{
	VideoCapture cap(1);
	if (cap.isOpened())
	{
		cap.set(CAP_PROP_FRAME_WIDTH, 1080);
		cap.set(CAP_PROP_FRAME_HEIGHT, 960);
	}
	Mat frame,img_HSV,mask_yellow,mask_dark,mask,img_gray,img_thresh;

	//namedWindow("阈值调节", (640, 640));
	//createTrackbar("Thresh min", "阈值调节", &Thresh_min, 255);
	//createTrackbar("Thresh max", "阈值调节", &Thresh_max, 255);

	/*namedWindow("Trackbars", (640, 200));
	createTrackbar("Hue Min", "Trackbars", &hmin, 255);
	createTrackbar("Hue Max", "Trackbars", &hmax, 255);
	createTrackbar("sat Min", "Trackbars", &smin, 255);
	createTrackbar("sat Max", "Trackbars", &smax, 255);
	createTrackbar("val Min", "Trackbars", &vmin, 255);
	createTrackbar("val Max", "Trackbars", &vmax, 255);*/

	Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));

	vector<Vec3f>circles;
	Vec3f circle;
	typedef Point_<double> Point2d;
	vector<Point2d> Mypoints;
	Point2d a, b;
	vector<double> center_dis;

	Mat matrix;
	Mat img_cont;
	Mat img_result;
	Mat img_blur, imgWarp;
	while (cap.isOpened())
	{
		cap.read(frame);
		img_cont = frame.clone();
		img_result = frame.clone();

		cvtColor(frame, img_gray, COLOR_BGR2GRAY);
		medianBlur(img_gray, img_blur, 3);//中值滤波

		//霍夫圆检测
		vector<Vec3f>circles;
		HoughCircles(img_blur, circles, HOUGH_GRADIENT, 1, 10, 100, 30, 5, 50);
		for (size_t i = 0; i < circles.size(); i++)//每帧图像,遍历所有圆
		{
			//画出所有的圆
			circle = circles[i];
			cv::circle(img_cont, Point(circle[0], circle[1]), circle[2], Scalar(255, 0, 0)); // 画圆
			cv::circle(img_cont, Point(circle[0], circle[1]), 2, Scalar(255, 0, 0));   // 圆心
			cout << "circle:" << circle << endl;
			float w = circle[2];
			float h = circle[2];  // 透视图像宽高;

			Point2f src[4] = { {circle[0] - circle[2], circle[1] - circle[2]},
								{circle[0] + circle[2],circle[1] - circle[2]},
								{circle[0] - circle[2],circle[1] + circle[2]},
								{circle[0] + circle[2], circle[1] + circle[2]} };//在每帧图像中,每检测到一个圆获取外界矩形坐标

			Point2f dir[4] = { {0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h} }; //
			matrix = getPerspectiveTransform(src, dir);   // 透视变换,实现两张图片同一个点的对应关系
			warpPerspective(frame, imgWarp, matrix, Point(w, h));  //将检测到的圆显示在img_Warp

			//cvtColor(imgWarp, img, COLOR_GRAY2BGR);
			cvtColor(imgWarp, img_HSV, COLOR_BGR2HSV);

			Scalar lower_yellow(21, 116, 144);//象限标黄色区域HSV
			Scalar upper_yellow(84, 175, 255);

			Scalar lower_dark(0, 0, 0);//象限标黑色区域HSV
			Scalar upper_dark(180, 255, 73);

			//在圆上进行HSV
			inRange(img_HSV, lower_yellow, upper_yellow, mask_yellow);   //实现二值化功能,将两个阈值内的像素值设置为白色,不在阈值区间内的像素值设置为黑色
			inRange(img_HSV, lower_dark, upper_dark, mask_dark);
			bitwise_or(mask_yellow, mask_dark, mask);  //按位或

			vector<vector<Point>>contours_y;   // 是一个向量,每一组point点集就是一个轮廓
			vector<Vec4i>hierarchy_y;
			vector<vector<Point>>contours_d;   // 是一个向量,每一组point点集就是一个轮廓
			vector<Vec4i>hierarchy_d;

			findContours(mask_yellow, contours_y, hierarchy_y, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);   // 连通域查找
			findContours(mask_dark, contours_d, hierarchy_d, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
			drawContours(imgWarp, contours_y, -1, color, 1);
			drawContours(imgWarp, contours_d, -1, color, 1);
			area_y = 0;
			area_d = 0;
			for (int i = 0; i < contours_y.size(); i++)
			{
				area_y = contourArea(contours_y[i]); // 计算轮廓的面积
				area_y += area_y;

			}
			for (int i = 0; i < contours_d.size(); i++)
			{
				area_d = contourArea(contours_d[i]); // 计算轮廓的面积
				area_d += area_d;

			}
			cout << "area_y:" << area_y << "area_d:" << area_d << endl;
			if (area_y > 4 and area_d > 4)
			{
				cv::circle(img_result, Point(circle[0], circle[1]), circle[2], Scalar(0, 0, 255)); // 画圆
				cv::circle(img_result, Point(circle[0], circle[1]), 2, Scalar(0, 0, 255));   // 圆心
				Mypoints.push_back(Point(circle[0],circle[1]));
			}
			
		}
		cout << "符合条件的所有圆:" << Mypoints << endl;
		for (int i = 0; i < Mypoints.size(); i++)
		{
			if (i % 2 == 0)  //偶数,第一次为0
			{
				a = Mypoints[i];
			}
			else if (i % 2 != 0)  //奇数
			{
				b = Mypoints[i];
			}
			center_dis.push_back(pow(pow(b.x - a.x, 2) + pow(b.y - a.y, 2),0.5));
			cout << "距离" << center_dis[0] << endl;
			
		}

		namedWindow("原图",WINDOW_AUTOSIZE);
		imshow("原图", frame);

		//namedWindow("透视图", WINDOW_AUTOSIZE); //提取出圆单独显示
		//imshow("透视图", imgWarp);

		//namedWindow("mask", WINDOW_AUTOSIZE);
		//imshow("mask", mask);

		//namedWindow("HSV", WINDOW_AUTOSIZE); // 在提取出来的圆上进行HSV检测
		//imshow("HSV", img_HSV);

		namedWindow("contours", WINDOW_AUTOSIZE);
		imshow("contours", img_cont);

		namedWindow("结果", WINDOW_AUTOSIZE);
		imshow("结果", img_result);

		if (waitKey(10) == 27)
		{
			break;
		}
	
	}
}

 运行结果如图所示。

 这个代码改进的部分还有许多,这里先进行一下记录。后续有时间改进后再来进行补充。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值