1. 程式人生 > 程式設計 >使用opencv識別影象紅色區域,並輸出紅色區域中心點座標

使用opencv識別影象紅色區域,並輸出紅色區域中心點座標

適用小白,大佬勿噴

個人配置:vs2013 ; opencv 3.0 ;

直接上效果圖

使用opencv識別影象紅色區域,並輸出紅色區域中心點座標

注意:右下角的水印把中心點擋住了,要仔細看才能看到

下面是程式碼:

#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,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,i,color,2,8,Point());//繪製輪廓函式
 
		circle(drawing,mc[i],4,-1,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),3);//給hsv色系的影象申請空間
	IplImage *hue=cvCreateImage(cvGetSize(image),1); //色調
	IplImage *saturation=cvCreateImage(cvGetSize(image),1);//飽和度
	IplImage *value=cvCreateImage(cvGetSize(image),1);//亮度
	IplImage *imgThresholded=cvCreateImage(cvGetSize(hue),1); 
	cvNamedWindow("yuan",1);
	cvCvtColor(image,hsv,CV_BGR2HSV);//將RGB色系轉為HSV色系
	cvShowImage("yuan",image);
	//cvShowImage("hsv",hsv);
	cvSplit(hsv,hue,0 );//分離三個通道
	cvSplit(hsv,saturation,0 );
	cvSplit(hsv,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),1 ); 
	cvCopy(imgThresholded,pContourImg);
	 cvNamedWindow("pContourImg",1);
	 cvShowImage("pContourImg",pContourImg);
	 IplImage* dst = cvCreateImage( cvGetSize(image),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,255 ); 
 
   /*  max_level 繪製輪廓的最大等級。如果等級為0,繪製單獨的輪廓。如果為1,繪製輪廓及在其後的相同的級別下輪廓 
    如果值為2,所有的輪廓。如果等級為2,繪製所有同級輪廓及所有低一級輪廓,諸此種種 
    如果值為負數,函式不繪製同級輪廓,但會升序繪製直到級別為abs(max_level)-1的子輪廓 */ 
   //  cvDrawContours(dst,contour,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,0); 
      cvDrawContours(dst,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);	  
	 //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識別影象紅色區域,並輸出紅色區域中心點座標就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。