当前位置: 首页 > 编程笔记 >

使用opencv识别图像红色区域,并输出红色区域中心点坐标

施恩
2023-03-14
本文向大家介绍使用opencv识别图像红色区域,并输出红色区域中心点坐标,包括了使用opencv识别图像红色区域,并输出红色区域中心点坐标的使用技巧和注意事项,需要的朋友参考一下

适用小白,大佬勿喷

个人配置:vs2013 ; opencv 3.0 ;

直接上效果图

注意:右下角的水印把中心点挡住了,要仔细看才能看到

下面是代码:

#include <iostream>
#include<opencv2\opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#define PI 3.1415926
 
using namespace cv;
using namespace std;
 
void RGB2HSV(double red, double green, double blue, double& hue, double& saturation, double& intensity)
{
	 
	double r, g, b;
	double h, s, i;
 
	double sum;
	double minRGB, maxRGB;
	double theta;
 
	r = red / 255.0;
	g = green / 255.0;
	b = blue / 255.0;
 
	minRGB = ((r<g) ? (r) : (g));
	minRGB = (minRGB<b) ? (minRGB) : (b);
 
	maxRGB = ((r>g) ? (r) : (g));
	maxRGB = (maxRGB>b) ? (maxRGB) : (b);
 
	sum = r + g + b;
	i = sum / 3.0;
 
	if (i<0.001 || maxRGB - minRGB<0.001)
	{
		h = 0.0;
		s = 0.0;
	}
	else
	{
		s = 1.0 - 3.0*minRGB / sum;
		theta = sqrt((r - g)*(r - g) + (r - b)*(g - b));
		theta = acos((r - g + r - b)*0.5 / theta);
		if (b <= g)
			h = theta;
		else
			h = 2 * PI - theta;
		if (s <= 0.01)
			h = 0;
	}
 
	hue = (int)(h * 180 / PI);
	saturation = (int)(s * 100);
	intensity = (int)(i * 100);
}
 
Mat picture_red(Mat input)
{
	
	Mat frame;
	Mat srcImg = input;
	frame = srcImg;
	waitKey(1);
	int width = srcImg.cols;
	int height = srcImg.rows;
 
	int x, y;
	double B = 0.0, G = 0.0, R = 0.0, H = 0.0, S = 0.0, V = 0.0;
	Mat vec_rgb = Mat::zeros(srcImg.size(), CV_8UC1);
	for (x = 0; x < height; x++)
	{
		for (y = 0; y < width; y++)
		{
			B = srcImg.at<Vec3b>(x, y)[0];
			G = srcImg.at<Vec3b>(x, y)[1];
			R = srcImg.at<Vec3b>(x, y)[2];
			RGB2HSV(R, G, B, H, S, V);
			//红色范围,范围参考的网上。可以自己调
			if ((H >= 312 && H <= 360) && (S >= 17 && S <= 100) && (V>18 && V < 100))
				vec_rgb.at<uchar>(x, y) = 255;
			/*cout << H << "," << S << "," << V << endl;*/
		}
	}
	/*imshow("hsv", vec_rgb);*/
	return vec_rgb;
	
 
}
 
void O_x1y1(Mat in, double *x1, double *y1, double *x2, double *y2)
 
{
	Mat matSrc = in;
	/*Mat matSrc = imread("qwer9.png", 0);*/
 
	GaussianBlur(matSrc, matSrc, Size(5, 5), 0);//高斯滤波,除噪点
 
	vector<vector<Point> > contours;//contours的类型,双重的vector
 
	vector<Vec4i> hierarchy;//Vec4i是指每一个vector元素中有四个int型数据。
 
	//阈值
 
	threshold(matSrc, matSrc, 100, 255, THRESH_BINARY);//图像二值化
 
	//寻找轮廓,这里注意,findContours的输入参数要求是二值图像,二值图像的来源大致有两种,第一种用threshold,第二种用canny
 
	findContours(matSrc.clone(), contours, hierarchy, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
 
	/// 计算矩
 
	vector<Moments> mu(contours.size());
 
	for (int i = 0; i < contours.size(); i++)
 
	{
		mu[i] = moments(contours[i], false);
	}
 
	/// 计算矩中心:
 
	vector<Point2f> mc(contours.size());
 
	for (int i = 0; i < contours.size(); i++)
 
	{
		mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
	}
 
	/// 绘制轮廓
 
	Mat drawing = Mat::zeros(matSrc.size(), CV_8UC1);
 
	for (int i = 0; i < contours.size(); i++)
 
	{
		Scalar color = Scalar(255);
 
		//drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());//绘制轮廓函数
 
		circle(drawing, mc[i], 4, color, -1, 8, 0);
		
	}
	*x1 = mc[0].x;
	*y1 = mc[0].y;
	*x2 = mc[contours.size()-1].x;
	*y2 = mc[contours.size() - 1].y;
	
	imshow("outImage", drawing);
}
 
int main()
{
	
	double xx1, yy1, xx2, yy2;
	double x1, y1, x2, y2;
 
	Mat matSrc = imread("qwer4.png");
 
	Mat middle = picture_red(matSrc);
	O_x1y1(middle, &xx1, &yy1, &xx2, &yy2);
	x1 = xx1;
	y1 = yy1;
	x2 = xx2;
	y2 = yy2;
 
	imshow("原图", matSrc);
	imshow("red", picture_red(matSrc));
 
	cout << "红点:" << x1 << ", " << y1 << "; " << "红点1:" << x2 << ", " << y2 << endl;
	waitKey();
 
	return 0;
}

如有不足,望指点!

补充知识:opencv 识别网球 ,或者绿色的小球 输出重心坐标

我就废话不多说了,大家还是直接看代码吧!

void image_process(IplImage *image)
 {
 int iLowH =26; 
 int iHighH = 69; 
 int iLowS = 42;  
 int iHighS = 206;  
 int iLowV = 0; 
 int iHighV = 198;
  CvMemStorage* storage2 = cvCreateMemStorage();
  CvSeq* contour3 = NULL;
  CvMoments moments; 
  CvMat *region; 
  CvPoint pt1,pt2;
  double m00 = 0, m10, m01, mu20, mu11, mu02, inv_m00; 
  double a, b, c; 
  int xc, yc; 
 
  CvMemStorage* storage = cvCreateMemStorage();
 	CvSeq * circles=NULL;
 
  // Circle cir[6];
  CvPoint P0;
  CvPoint CenterPoint;
  // cvNamedWindow("win1"); 
	//cvShowImage("win1",image);
	//cvNamedWindow("image",CV_WINDOW_AUTOSIZE);//用于显示图像的窗口
	//cvNamedWindow("hsv",CV_WINDOW_AUTOSIZE);	
	//cvNamedWindow("saturation",CV_WINDOW_AUTOSIZE);
	//cvNamedWindow("value",CV_WINDOW_AUTOSIZE);
	//cvNamedWindow("pImg8u",1);
	IplImage *hsv=cvCreateImage(cvGetSize(image),8,3);//给hsv色系的图像申请空间
	IplImage *hue=cvCreateImage(cvGetSize(image),8,1); //色调
	IplImage *saturation=cvCreateImage(cvGetSize(image),8,1);//饱和度
	IplImage *value=cvCreateImage(cvGetSize(image),8,1);//亮度
	IplImage *imgThresholded=cvCreateImage(cvGetSize(hue),8,1); 
	cvNamedWindow("yuan",1);
	cvCvtColor(image,hsv,CV_BGR2HSV);//将RGB色系转为HSV色系
	cvShowImage("yuan",image);
	//cvShowImage("hsv",hsv);
	cvSplit(hsv, hue, 0, 0, 0 );//分离三个通道
	cvSplit(hsv, 0, saturation, 0, 0 );
	cvSplit(hsv, 0, 0, value, 0 );
	int value_1=0;
	 
	cvInRangeS(
	  hsv, 
	  cvScalar(iLowH, iLowS, iLowV), 
	  cvScalar(iHighH, iHighS, iHighV),
	  imgThresholded
	  ); 
	 cvNamedWindow("imgThresholded",1);
	 cvShowImage("imgThresholded",imgThresholded);
 
	 IplImage*pContourImg= cvCreateImage( cvGetSize(image), 8, 1 ); 
	cvCopy(imgThresholded,pContourImg);
	 cvNamedWindow("pContourImg",1);
	 cvShowImage("pContourImg",pContourImg);
	 IplImage* dst = cvCreateImage( cvGetSize(image), 8, 3 ); 
	CvMemStorage* storage3 = cvCreateMemStorage(0); 
	CvSeq* contour = 0; 
	// 提取轮廓 
  int contour_num = cvFindContours(pContourImg, storage3, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); 
  cvZero(dst);    // 清空数组 
  CvSeq *_contour = contour;  
  double maxarea = 100; 
  double minarea = 10; 
  int m = 0; 
  for( ; contour != 0; contour = contour->h_next )  
  {  
 
    double tmparea = fabs(cvContourArea(contour)); 
    if(tmparea < minarea)   
    {  
      cvSeqRemove(contour, 0); // 删除面积小于设定值的轮廓 
      continue; 
    }  
    CvRect aRect = cvBoundingRect( contour, 0 );  
    if ((aRect.width/aRect.height)<1)  
    {  
      cvSeqRemove(contour, 0); //删除宽高比例小于设定值的轮廓 
      continue; 
    }  
    if(tmparea > maxarea)  
    {  
      maxarea = tmparea; 
    }  
    m++; 
    // 创建一个色彩值 
  //  CvScalar color = CV_RGB( 0, 0, 255 ); 
 
   /*  max_level 绘制轮廓的最大等级。如果等级为0,绘制单独的轮廓。如果为1,绘制轮廓及在其后的相同的级别下轮廓 
    如果值为2,所有的轮廓。如果等级为2,绘制所有同级轮廓及所有低一级轮廓,诸此种种 
    如果值为负数,函数不绘制同级轮廓,但会升序绘制直到级别为abs(max_level)-1的子轮廓 */ 
   //  cvDrawContours(dst, contour, color, color, 0, 1, 8);  //绘制外部和内部的轮廓 
  }  
  contour = _contour; 
  int count = 0; double tmparea=0;
  for(; contour != 0; contour = contour->h_next) 
  {  
    count++; 
     tmparea = fabs(cvContourArea(contour)); 
    if (tmparea >= maxarea)  
    {  
      CvScalar color = CV_RGB( 0, 255, 0); 
      cvDrawContours(dst, contour, color, color, -1, 1, 8); 
			cout<<"222"<<endl;
			cout<<"面积为"<<tmparea<<endl;
			cout<<endl;
			CvRect aRect = cvBoundingRect( contour, 0 ); 
			//找重心
			{
				CvPoint2D32f center = cvPoint2D32f(0, 0);
				int countOfPoint = 0;
				for(int i = aRect.x; i < aRect.x + aRect.width; ++i){
					for(int j = aRect.y; j < aRect.y + aRect.height; ++j){
						if(*(image->imageData + image->widthStep * j + i) != 0){
							center.x += i;
							center.y += j;
							countOfPoint++;
						}
					}
				}
 
				center.x /= countOfPoint;
				center.y /= countOfPoint;
				cout<<"重心坐标为x:"<<center.x<<endl;
     		cout<<"重心坐标为y:"<<center.y<<endl;
				cvCircle(dst, cvPoint(center.x, center.y), 5, cvScalar(0, 255), 2);
			}
		}
 // //Threshold the image
 //  cvErode(imgThresholded,imgThresholded);
 //  cvErode(imgThresholded,imgThresholded);
	 //cvErode(imgThresholded,imgThresholded);
	 //cvErode(imgThresholded,imgThresholded);	  
	 //IplImage* pImg8u=cvCloneImage(imgThresholded);
	
	 //cvCanny(pImg8u, pImg8u,40, 50, 5);
	 //cvShowImage("pImg8u",pImg8u);
	 //circles=cvHoughCircles(pImg8u,storage,CV_HOUGH_GRADIENT,
		//2,  //最小分辨率,应当>=1
		//pImg8u->height/15,  //该参数是让算法能明显区分的两个不同圆之间的最小距离
		//80,  //用于Canny的边缘阀值上限,下限被置为上限的一半
		//65,  //累加器的阀值
		//25,   //最小圆半径 
		//50   //最大圆半径
		//);
 }
 
	cvShowImage( "contour", dst );
	}

以上这篇使用opencv识别图像红色区域,并输出红色区域中心点坐标就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。

 类似资料:
  • 在OpenCV python中,假设我们用cv2.imread读取一个图像,并得到一个BGR numpy数组。接下来我们使用cv2.inrange命令生成一个掩码。掩模具有相同的宽度/高度,并且每个掩模像素要么是黑色的,要么是白色的。 我必须先将掩码转换成BGR图像吗?如果是,怎么做? 编辑:我不想像在将蒙版应用到彩色图像中那样将整个蒙版应用到图像上。另一种表达我所想要的方式:将面具视为一个黑白图

  • 我已经在网上搜索过了,我已经找到了一些方法来做我想做的事情,但是与我需要的相比,这些方法在效率上失败了。 我有一个kinect(使用Microsoft SDK),它当前正在获取一个删除背景的人,将结果保存在一个3通道的垫子中,并将该人从背景中删除。现在我需要裁剪图像以只适合那个人,忽略黑色区域。 这里是棘手的部分:我没有很多时间浪费在每个操作上(我还需要做其他几个操作,这应该是实时工作。我目前实现

  • 问题内容: 我正在尝试从图像中提取红色。我有应用阈值的代码,仅保留指定范围内的值: 但是,正如我检查的那样,红色的色相值可以在0到10的范围内,也可以在170到180的范围内。因此,我想保留这两个范围中任何一个的色相值。我尝试将阈值从10设置为170并使用函数,但随后我也获得了所有白色。我认为最好的选择是为每个范围创建一个遮罩并同时使用它们,因此我必须以某种方式将它们合并在一起,然后再继续。 有没

  • 问题内容: 编辑Png图像例如,更改特定区域并在该区域填充颜色。 我想更改仅图像选择区域的颜色。就像第一个用户选择一种颜色,然后他选择一个图像一样,之后他可以用所选颜色更改图像颜色的特定区域。 之后,他也可以保存该图像,这可能吗?像Color公司的网站使用这种东西。 像下面的URL https://www.sherwin- williams.com/visualizer#/active 问题答案:

  • 来自维基百科: 在计算中,红色区域是函数堆栈帧中超出返回地址的固定大小的区域,该函数未保留。被调用方函数可以使用红色区域来存储局部变量,而不会产生修改堆栈指针的额外开销。中断/异常/信号处理程序不得修改此内存区域。系统 V 使用的 x86-64 ABI 要求一个 128 字节的红色区域,该区域直接在返回地址之后开始,并包含函数的参数。OpenRISC 工具链采用 128 字节的红色区域。 从Sys