数字图像处理之目标颜色识别

实验要求

找到目标颜色所在区域

算法实现

  1. 色度空间转换
    1.1 读取图像并滤波
    1.2 根据公式将图像从rgb转换到hsv色度空间
    在这里插入图片描述

  2. 颜色分割
    2.1 利用 createTrackbar()函数建立滑动条,对颜色空间转换后的各通道进行阈值分割
    2.2 根据阈值分割的结果,判断各种颜色的对应阈值
    2.3 针对不同颜色,分别对图像进行阈值分割
    2.4 对阈值分割结果进行数学统计,判断图像的颜色并输出分类结果
    在这里插入图片描述

  3. 目标颜色检测
    3.1 对图像进行预处理,消除噪声并获取二值化图
    3.2 对二值图进行轮廓检测;
    3.3 根据任务目标选择合适的多边形描述轮廓;
    3.4 获取多边形区域后,从原图中截取该区域图像;
    3.5 对多边形区域的图像进行颜色分割,对分割结果进行统计,判断图像的颜色并输出分类结果

代码实现

#include <stdlib.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#define LINEAR_X 0

#define SIZE 3
#define PI 3.1415926
#define HMaxValue 255
#define SMaxValue 255
#define VMaxValue 255
#define oo 1e9+7
using namespace std;
using namespace cv;
int H_min=100, H_max=124, S_min=43, S_max=255, V_min=46, V_max=255;
Mat img_in;
void Gaussian(Mat input, Mat output, double sigma){
	double weight;//权重
	double sum = 0; 
	double Gaussian_Temp[SIZE][SIZE] = {0};//模板
	weight = (2*PI*sigma*sigma);  
	for(int i =0;i <SIZE;i++)  
	{  
		for(int j = 0;j < SIZE;j++)  
		{  
			int x = i - SIZE/2;
			int y = j - SIZE/2;
		    Gaussian_Temp[i][j] =exp(-(x*x+y*y)/(2.0*sigma*sigma))/weight;  
		    sum += Gaussian_Temp[i][j];  
		}  
	}  

	for(int i = 0; i < SIZE;i++)  
	{  
		for(int j = 0;j < SIZE;j++)  
		{  
		    Gaussian_Temp[i][j] = Gaussian_Temp[i][j]/sum;//归一化处理  
		    //printf("%f ",Gaussian_Temp[i][j]);  
		}  
		//printf("\n");  
	}
	
	int rows = output.rows;
	int cols = output.cols;
	int channels = input.channels();
	for(int i=0;i<rows;i++)
	{
		for(int j=0;j<cols;j++)
		{
			int sum3[3]={0};
			int sum1 = 0;
			for(int k=0;k<SIZE;k++)
				for(int t=0;t<SIZE;t++)
				{
					int x=i+k-SIZE/2;
					int y=j+t-SIZE/2;
					if(x<0||y<0||x>=rows||y>=cols)continue;
					double m=Gaussian_Temp[k][t];
					if(channels == 1)sum1+=m*input.at<uchar>(x,y);
					else if(channels == 3)
					{
						Vec3b rgb = input.at<Vec3b>(x,y);
						sum3[0]+=m*rgb[0];
						sum3[1]+=m*rgb[1];
						sum3[2]+=m*rgb[2];
						
					}
				}
			if(channels == 3){
				for(int k=0;k<3;k++){
					if(sum3[k]>255)sum3[k]=255;
					if(sum3[k]<0)sum3[k]=0;
					output.at<Vec3b>(i,j)[k]=sum3[k];
				}
			}
			else {
				if(sum1>255)sum1=255;
				if(sum1<0)sum1=0;
				output.at<uchar>(i,j)=sum1;
			}
		}
	}
}
void RBG2HSV(Mat input,Mat output){
	int rows=input.rows;
	int cols=input.cols;
	//cout<<rows<<" "<<cols<<endl;
	for(int i=0;i<rows;i++){
		for(int j=0;j<cols;j++){
			Vec3b pix=input.at<Vec3b>(i,j);//012:BGR
			float b=1.0*pix[0]/255;
			float g=1.0*pix[1]/255;
			float r=1.0*pix[2]/255;
			float maxrgb=max(r,max(g,b));
			float minrgb=min(r,min(g,b));
			float diff=maxrgb-minrgb;
			float v=maxrgb;
			float s=(diff/v);
			float h;
			if(maxrgb-minrgb<1e-5)h=0;
			else if(maxrgb==r)h=60*(g-b)/diff;
			else if(maxrgb==g)h=60*(b-r)/diff+120;
			else if(maxrgb==b)h=60*(r-g)/diff+240;
			if(h<0)h+=360;
			else if(h>359)h-=360;
			output.at<Vec3b>(i,j)[0]=(int)(h*180/360);
			output.at<Vec3b>(i,j)[1]=(int)(s*255);
			output.at<Vec3b>(i,j)[2]=(int)(v*255);

		}
	}
}
/*
画颜色统计图
*/
void Statistical(Mat input){
    int weigth=210,height=300;
    Mat output=Mat::zeros(height,weigth,CV_8UC3);
	int rows=input.rows;
	int cols=input.cols;
	int colorNum[7]={0};
	int sum=rows*cols;
	for(int i=0;i<rows;i++){
		for(int j=0;j<cols;j++){
			Vec3b pix=input.at<Vec3b>(i,j);//012:HSV
			if(pix[1]<43||pix[2]<46)continue;
			//pix[0]=pix[0]*180/255;
			int color=0;
			if((pix[0]>=0&&pix[0]<=10)||(pix[0]>=156&&pix[0]<=180))color=0;
			else if(pix[0]>=11&&pix[0]<=25)color=1;
			else if(pix[0]>=26&&pix[0]<=34)color=2;
			else if(pix[0]>=35&&pix[0]<=77)color=3;
			else if(pix[0]>=78&&pix[0]<=99)color=4;
			else if(pix[0]>=100&&pix[0]<=124)color=5;
			else if(pix[0]>=125&&pix[0]<=155)color=6;
			colorNum[color]++;
		}
	}
	
    Scalar Color[7]={Scalar(0,0,255),Scalar(0,125,255),Scalar(0,255,255),Scalar(0,255,0),Scalar(255,255,0),Scalar(255,0,0),Scalar(255,0,255)};
	 for(int i=0;i<7;i++){  
	    int h=colorNum[i]*height/sum;
	    rectangle(output,Point(i*30,height),Point((i+1)*30-1, height-h),Color[i],-1);
	 }
	 imshow("color",output);
}
void colorDetection(Mat input){
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy; 
	findContours( input, contours, hierarchy,  RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0) );
	if(contours.size()==0)return;
	int area=0,x=0,y=0,a=0,b=0,c=0,d=0;
	for(int k=0;k<contours.size();k++){
	    RotatedRect rectPoint = minAreaRect(contours[k]);
	    Point2f point[4]; 
	    //将rectPoint变量中存储的坐标值放到 point的数组中  
	    rectPoint.points(point);
		//寻找轮廓的左上角和右下角,算出长宽
	    int max_x=0,max_y=0,min_x=oo,min_y=oo;
        for (int i = 0; i < 4; i++)
        {
		    if (max_x < point[i].x)max_x=int(point[i].x+0.5);
		    if (max_y < point[i].y)max_y=int(point[i].y+0.5);
		    if (min_x > point[i].x)min_x=(int)point[i].x;
		    if (min_y > point[i].y)min_y=(int)point[i].y;
		    
        }   
        if(min_x<0)min_x=0;
    	if(min_y<0)min_y=0;
    	if(max_x>=input.cols)max_x=input.cols-1;
        if(max_y>=input.rows)max_y=input.rows-1;
        if((max_x-min_x)*(max_y-min_y)>area){
        	area=(max_x-min_x)*(max_y-min_y);
        	x=min_x;
        	y=min_y;
        	a=max_x;
        	b=max_y;
        	c=max_x-min_x;
        	d=max_y-min_y;
        }
    }
	
    if(c==0||d==0)return;
	//截取ROI区域
    Mat output=img_in(Rect(x,y,c,d));
    imshow("ROI",output);
    Mat hsv=Mat::zeros(output.size(),CV_8UC3);
    RBG2HSV(output,hsv);
	//统计截取之后的图像各种颜色的含量
    Statistical(hsv);
}
/*
颜色分割
*/
void thresholdSeq(int var,void* usrdata){
	Mat input = *(static_cast<Mat*> (usrdata));
	Mat output=Mat::zeros(input.size(),CV_8UC1);
	int rows=input.rows;
	int cols=input.cols;
	for(int i=0;i<rows;i++){
		for(int j=0;j<cols;j++){
			Vec3b pix=input.at<Vec3b>(i,j);//012:HSV
			if(pix[0]<H_min||pix[0]>H_max)continue;
			if(pix[1]<S_min||pix[1]>S_max)continue;
			if(pix[2]<V_min||pix[2]>V_max)continue;
			output.at<uchar>(i,j)=255;
		}
	}
	imshow("thresholdSeq",output);
	//目标颜色检测
	colorDetection(output);
}
int main(int argc, char **argv)
{
	//读取原始图像
	img_in=imread(argv[1],IMREAD_UNCHANGED);
	//检查是否读取图像
	if(img_in.empty()){
		cout<<"Error! Input image cannot be read...\n";
		return -1;
	}
	
	imshow("src",img_in);
	Mat frOut1=Mat::zeros(img_in.size(),CV_8UC3);
	Mat frOut2=Mat::zeros(img_in.size(),CV_8UC1);
	// 空域滤波函数
	Gaussian(img_in,frOut1,1);
	// 色度空间转换
	RBG2HSV(frOut1,frOut1); 
	//阈值分割
	namedWindow("thresholdSeq");	
	createTrackbar("H_min", "thresholdSeq", &H_min, HMaxValue, thresholdSeq,&frOut1);
	createTrackbar("H_max", "thresholdSeq", &H_max, HMaxValue, thresholdSeq,&frOut1);
	createTrackbar("S_min", "thresholdSeq", &S_min, SMaxValue, thresholdSeq,&frOut1);
	createTrackbar("S_max", "thresholdSeq", &S_max, SMaxValue, thresholdSeq,&frOut1);
	createTrackbar("V_min", "thresholdSeq", &V_min, VMaxValue, thresholdSeq,&frOut1);
	createTrackbar("V_max", "thresholdSeq", &V_max, VMaxValue, thresholdSeq,&frOut1);
	waitKey();
	return 0;
}

运行结果

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值