// color recognition.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
#include "cv.h"
#include <math.h>
#include "color module.h"
using namespace cv;
using namespace std;
Rect r; //存储车牌位置
CvPoint origin;
IplImage* image=NULL;
int mark = 0; //选择ROI标志
void on_mouse( int event, int x, int y, int flags, void* zhang )
{
if( !image )
return;
CvPoint pt;
if( event == CV_EVENT_LBUTTONDOWN ) //开始点击选择跟踪物体
{
origin = cvPoint( x,y );
r = cvRect( x,y,0,0 );//坐标
r.x = MIN( x,origin.x );
r.y = MIN( y,origin.y );
r.width = r.x + CV_IABS( x - origin.x );
r.height = r.y + CV_IABS( y - origin.y );
r.x = MAX( r.x, 0 );
r.y = MAX( r.y, 0 );
r.width = MIN( r.width, image->width );
r.height = MIN( r.height, image->height );
r.width -= r.x;
r.height -= r.y;
}
if( event == CV_EVENT_LBUTTONUP )
{
pt = cvPoint( x,y );
mark = -1;
r.width = pt.x - r.x;
r.height = pt.y - r.y;
}
}
/*************************************************************************
* 函数名称:
* Color_difference_HSV()
* 参数:
* IplImage* car - 输入原图像
* Rect r - 源图像中划出的颜色识别区域
* 返回值:
* int* type - 指向颜色类型值,返回类型参数
* 说明:
* 该函数用来对图像进行颜色匹配识别。
************************************************************************/
int Color_difference_HSV( cv::Mat car, Rect r)
{
int type = 0;
//复制ROI区域图像
if ( r.width==0 || r.height==0 )
{
return -1;
}
cv::Mat roiImage = cvCreateImage(cvSize(r.width, r.height), 8, 3 );
car(r).copyTo(roiImage);
float hranges_arr[] = {0,180};//像素值的范围
float* hranges = hranges_arr;//用于初始化CvHistogram类
IplImage* roi = &roiImage.operator IplImage();
IplImage* hsv = cvCreateImage(cvGetSize(roi), IPL_DEPTH_8U, 3);//用于存图像的一个中间变量,是用来分通道用的,分成hsv通道
IplImage* h_plane = cvCreateImage( cvGetSize(roi), IPL_DEPTH_8U, 1);
IplImage* s_plane = cvCreateImage( cvGetSize(roi), IPL_DEPTH_8U, 1);
IplImage* v_plane = cvCreateImage( cvGetSize(roi), IPL_DEPTH_8U, 1);
IplImage* planes[] = { h_plane, s_plane };
IplImage* src_tmp1=cvCreateImage(cvGetSize(roi),8,3);
/** H 分量划分为16个等级,S分量划分为8个等级 */
int h_bins = 15, s_bins = 8, v_bins = 8;
int hist_size[] = {h_bins, s_bins};
/** H 分量的变化范围 */
float h_range[] = { 0, 180 };
/** S 分量的变化范围*/
float s_range[] = { 0, 255 };
float* ranges[] = { h_range, s_range };
float* h_ranges[] = { h_range };
float* s_ranges[] = { s_range };
/** 输入图像转换到HSV颜色空间 */
cvCvtColor( roi, hsv, CV_BGR2HSV );
cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );
/** 创建直方图,二维, 每个维度上均分 */
CvHistogram * hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, 1 );
增加部分/
CvHistogram* h_hist = cvCreateHist(1,&h_bins,CV_HIST_ARRAY,h_ranges,1);
CvHistogram* s_hist = cvCreateHist(1,&s_bins,CV_HIST_ARRAY,s_ranges,1);
CvHistogram* v_hist = cvCreateHist(1,&v_bins,CV_HIST_ARRAY,ranges,1);
/** 根据H,S两个平面数据统计直方图 */
cvCalcHist( planes, hist, 0, 0 );
//增加部分//
cvCalcHist( &h_plane, h_hist, 0, 0 ); //统计H方向直方图
cvCalcHist( &s_plane, s_hist, 0, 0 ); //统计S方向直方图
cvCalcHist( &v_plane, v_hist, 0, 0 ); //统计v方向直方图
/** 获取直方图统计的最大值,用于动态显示直方图 */
float max_value,hmax,smax,vmax;
cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );
cvGetMinMaxHistValue( h_hist, 0, &hmax, 0, 0 );
cvGetMinMaxHistValue( s_hist, 0, &smax, 0, 0 );
cvGetMinMaxHistValue( v_hist, 0, &vmax, 0, 0 );
/** 设置直方图显示图像 */
int height = 240;
int width = (h_bins*s_bins*6);
IplImage* hist_img = cvCreateImage( cvSize(width,height), 8, 3 );
cvZero( hist_img );
/** 用来进行HSV到RGB颜色转换的临时单位图像 */
IplImage * hsv_color = cvCreateImage(cvSize(1,1),8,3);
IplImage * rgb_color = cvCreateImage(cvSize(1,1),8,3);
int bin_w = width / (h_bins * s_bins);
int n = 0;
//显示一:综合H,S显示直方图,宽为h_bins*s_bins,并显示相应直方图颜色//
for(int h = 0; h < h_bins; h++)
{
for(int s = 0; s < s_bins; s++)
{
int i = h*s_bins + s;
/** 获得直方图中的统计次数,计算显示在图像中的高度 */
float bin_val = cvQueryHistValue_2D( hist, h, s );
int intensity = cvRound(bin_val*height/max_value); //转化为在显示直方图上的合适高度
cout<<intensity<<endl;
/** 获得当前直方图代表的颜色,转换成RGB用于绘制 */
cvSet2D(hsv_color,0,0,cvScalar(h*180.f / h_bins,s*255.f/s_bins,255,0));
cvCvtColor(hsv_color,rgb_color,CV_HSV2BGR);
CvScalar color = cvGet2D(rgb_color,0,0);
cvRectangle( hist_img, cvPoint(i*bin_w,height),
cvPoint((i+1)*bin_w,height - intensity),
color, -1, 8, 0 );
n++;
}
}
cout<<n<<endl;
//
//显示二: 分别显示H、S、V三通道直方图/
int hist_height = 100;//显示直方图高度
int hist_width = 150;
IplImage* hist_image = cvCreateImage( cvSize(hist_width,hist_height*3),8,3 );
float hidx=0,sidx=0,vidx=0; //保存最高峰值的元素值
for(int i = 0;i < h_bins; i++)
{
float bin_val = cvQueryHistValue_1D(h_hist,i);
int intensity = cvRound(bin_val*hist_height/hmax);
int hbin_w = hist_width/h_bins;
cvRectangle(hist_image,cvPoint(i*hbin_w,hist_height),cvPoint((i+1)*hbin_w - 1, hist_height - intensity),CV_RGB(0,255,0));
float k = i*180.f/h_bins;
if (hmax<=bin_val)
{
hmax = bin_val;
hidx = k;
}
}
cout<<"统计出现最多H的次数:"<<hmax<<" ,H元素的值为:"<<hidx<<endl;
for(int i = 0;i < s_bins; i++)
{
float bin_val = cvQueryHistValue_1D(s_hist,i);
int intensity = cvRound(bin_val*hist_height/smax);
int sbin_w = hist_width/s_bins;
cvRectangle(hist_image,cvPoint(i*sbin_w,2*hist_height),cvPoint((i+1)*sbin_w - 1, 2*hist_height - intensity),CV_RGB(0,255,0));
float k = i*255.f/s_bins;
if (smax<=bin_val)
{
smax = bin_val;
sidx = k;
}
}
cout<<"统计出现最多S的次数:"<<smax<<" ,S元素的值为:"<<sidx<<endl;
for(int i = 0;i < v_bins; i++)
{
float bin_val = cvQueryHistValue_1D(v_hist,i);
int intensity = cvRound(bin_val*hist_height/vmax);
int vbin_w = hist_width/v_bins;
cvRectangle(hist_image,cvPoint(i*vbin_w,3*hist_height),cvPoint((i+1)*vbin_w - 1, 3*hist_height - intensity),CV_RGB(0,255,0));
float k = i*255.f/v_bins;
if (vmax<=bin_val)
{
vmax = bin_val;
vidx = k;
}
}
cout<<"统计出现最多V的次数:"<<vmax<<" ,V元素的值为:"<<vidx<<endl;
cvNamedWindow( "Source", 1 );
cvShowImage( "Source", roi );
cvNamedWindow( "H-S Histogram", 1 );
cvShowImage( "H-S Histogram", hist_img );
cvNamedWindow( "H-S-V Histogram", 1 );
cvShowImage( "H-S-V Histogram", hist_image );
cvReleaseImage(&hsv);
cvDestroyWindow("hsv");
cvReleaseImage(&h_plane);
cvReleaseImage(&s_plane);
cvReleaseImage(&v_plane);
cvReleaseImage(&src_tmp1);
return type;
}
int Color_difference_RGB( cv::Mat car, Rect r )
{
int type = 0;
//复制ROI区域图像
if ( r.width==0 || r.height==0 )
{
return -1;
}
cv::Mat roiImage = cvCreateImage( cvSize(r.width, r.height), 8, 3 );
car(r).copyTo(roiImage);
IplImage* roi = &roiImage.operator IplImage();
IplImage* R = cvCreateImage( cvGetSize(roi), IPL_DEPTH_8U, 1);
IplImage* G = cvCreateImage( cvGetSize(roi), IPL_DEPTH_8U, 1);
IplImage* B = cvCreateImage( cvGetSize(roi), IPL_DEPTH_8U, 1);
// 高斯模糊
//cvSmooth(roi,roi,CV_GAUSSIAN,3,3); //高斯模糊 ,作用
cvCvtPixToPlane(roi,B,G,R,0);//分为3个通道,OpenCV中不管是Windows中Load的还是摄像头取得的都是BGR顺序排列的
cvShowImage("R",R);
cvShowImage("hsv",roi);
cvShowImage("G",G);
cvShowImage("B",B);
//为这四幅图创建对应的直方图结构。
int hist_size = 28; //划分bin的个数
int hist_height = 100;
float range[] = {0,256};
float* ranges[]={range};
CvHistogram* r_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
CvHistogram* g_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
CvHistogram* b_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
//计算直方图,创建用于显示直方图的图像
cvCalcHist( &R, r_hist, 0, 0 );
cvCalcHist( &G, g_hist, 0, 0 );
cvCalcHist( &B, b_hist, 0, 0 );
cvNormalizeHist(r_hist,1.0);
cvNormalizeHist(g_hist,1.0);
cvNormalizeHist(b_hist,1.0);
//开始显示,这里对直方图进行了标准化处理,不然的话无法观察到明显的变化
int scale = 256/hist_size;
IplImage* hist_image = cvCreateImage( cvSize(hist_size*scale,hist_height*3),8,3 );
cvZero(hist_image);
float bmax_value = 0,rmax_value=0,gmax_value=0;
float min_value;
int rmin_idx, rmax_idx,gmin_idx, gmax_idx,bmin_idx,bmax_idx;
float rmax=0,gmax=0,bmax=0; //保存最高峰值
float ridx=0,gidx=0,bidx=0; //保存最高峰值的元素值
cvGetMinMaxHistValue( r_hist, 0,&rmax_value,0,&rmax_idx );
cvGetMinMaxHistValue(g_hist, 0,&gmax_value,0,0);
cvGetMinMaxHistValue(b_hist, 0,&bmax_value,0,0);
//cout<<"R最大值"<<(1-rmax_value)*255<<" "<<rmax_idx<<",G最大值"<<(1-gmax_value)*255<<",B最大值"<<(1-bmax_value)*255<<endl;
for(int i=0;i<hist_size;i++)
{
float bin_val = cvQueryHistValue_1D(r_hist,i);//返回相应bin中的统计值
int intensity = cvRound(bin_val*hist_height/rmax_value);
cvRectangle(hist_image,cvPoint(i*scale,hist_height),cvPoint((i+1)*scale - 1, hist_height - intensity),CV_RGB(255,0,0));
float k = (i+1)*255.f/hist_size;
if (rmax<bin_val)
{
rmax = bin_val;
ridx = k;
}
}
cout<<rmax<<" "<<ridx<<endl;
for(int i=0;i<hist_size;i++)
{
float bin_val = cvQueryHistValue_1D(g_hist,i);
int intensity = cvRound(bin_val*hist_height/gmax_value);
cvRectangle(hist_image,cvPoint(i*scale,2*hist_height),cvPoint((i+1)*scale - 1, 2*hist_height - intensity),CV_RGB(0,255,0));
float k = i*255.f/hist_size;
if (gmax<bin_val)
{
gmax = bin_val;
gidx = k;
}
}
cout<<gmax<<" "<<gidx<<endl;
for(int i=0;i<hist_size;i++)
{
float bin_val = cvQueryHistValue_1D(b_hist,i);
int intensity = cvRound(bin_val*hist_height/bmax_value);
cvRectangle(hist_image,cvPoint(i*scale,3*hist_height),cvPoint((i+1)*scale - 1, 3*hist_height - intensity),CV_RGB(0,0,255));
float k = i*255.f/hist_size;
if (bmax<bin_val)
{
bmax = bin_val;
bidx = k;
}
}
cout<<bmax<<" "<<bidx<<endl;
cvShowImage("ZHIFANGTUr",hist_image);
//颜色判断及匹配
float velue[] = {ridx,gidx,bidx};
float dmin = 100000; //保存最小的距离
int colorIdx = 0;
for(int i=0 ; i <N ; i++)
{
float d = sqrt(pow(colorVelue[i][0]-velue[0],2)+pow(colorVelue[i][1]-velue[1],2)+pow(colorVelue[i][2]-velue[2],2));
if (dmin > d)
{
dmin = d;
colorIdx = i;
}
}
cout<<"colorIdx:"<<colorIdx<<endl;
if (( ridx>150 )&&( ridx<200 )&&( gidx>150 )&&( gidx < 200 )&&(bidx>150)&&(bidx<200)&&
abs(ridx-gidx)<30&&abs(ridx-bidx)<30&&(gidx-bidx)<30)
{
type = 10;
}
else if (( ridx>0 )&&( ridx<150 )&&( gidx>0 )&&( gidx < 150 )&&(bidx>0)&&(bidx<150)&&
abs(ridx-gidx)<30&&abs(ridx-bidx)<30&&(gidx-bidx)<30)
{
type = 0;
}
else if (( ridx>200 )&&( gidx>200 )&&(bidx>200)&&
abs(ridx-gidx)<30&&abs(ridx-bidx)<30&&(gidx-bidx)<30)
{
type = 1 ;
}
else
type = colorIdx;
//cvDestroyWindow("hsv");
cvReleaseImage(&R);
cvReleaseImage(&G);
cvReleaseImage(&B);
cvReleaseImage(&hist_image);
cvReleaseHist(&r_hist);
cvReleaseHist(&g_hist);
cvReleaseHist(&b_hist);
return type;
}
int main(int argc, _TCHAR* argv[])
{
cvNamedWindow( "color recognition", 1 ); //建立视频窗口
IplImage* src = cvLoadImage( "D:\\tu\\2005422443840696.jpg" );
float scale = 0.5;
CvSize img_cvsize;
img_cvsize.width = src->width * scale;
img_cvsize.height = src->height * scale;
image = cvCreateImage( img_cvsize,src->depth,src->nChannels );
//读图像//
//image = cvCreateImage( cvGetSize(src), 8, 3 );
cvResize(src,image,CV_INTER_LINEAR);
cvShowImage( "color recognition", image );//显示视频和直方图
cvWaitKey(1000);
cvSetMouseCallback( "color recognition", on_mouse ); // 设置鼠标回调函数
//车牌区域选择函数//
for ( int i=0;i<4;i++ )
{
if ( mark )
{
cout<<"区域坐标:"<<"x:"<<r.x<<", y:"<<r.y<<", width:"<<r.width<<", height:"<<r.height<<endl;
cout<<"ok"<<endl;
}
cvWaitKey(1000);
cvRectangle( image,cvPoint( r.x,r.y ),cvPoint( r.x+r.width,r.y+r.height ),cvScalar(255,0,255) ,2, 8, 0);
cvShowImage( "color recognition", image );
}
cvShowImage( "color recognition", image );
cout<<"selection is ok"<<endl;
//cvWaitKey(0);
//颜色匹配识别//
int j;
//j = Color_difference_RGB(image,r); //返回颜色类型
j = Color_difference_HSV(image,r);
cout<<"j:"<<j<<endl;
switch (j)
{
case -1:
cout<<"please select ROI first!"<<endl;
break;
case 0:
cout<<"the colorof this car is:黑"<<endl;
break;
case 1:
cout<<"the colorof thiscar is:白"<<endl;
break;
case 2:
cout<<"the colorof thiscar is:红"<<endl;
break;
case 3:
cout<<"the colorof thiscar is:红"<<endl;
break;
case 4:
cout<<"the colorof thiscar is:绿"<<endl;
break;
case 5:
cout<<"the colorof thiscar is:绿"<<endl;
break;
case 6:
cout<<"the colorof thiscar is:蓝"<<endl;
break;
case 7:
cout<<"the colorof thiscar is:蓝"<<endl;
break;
case 8:
cout<<"the colorof thiscar is:黄"<<endl;
break;
case 9:
cout<<"the colorof thiscar is:黄"<<endl;
break;
case 10 :
cout<<"the colorof thiscar is:灰"<<endl;
break;
default:
cout<<"the colorof thiscar is:其他"<<endl;
}
cvWaitKey(0);
cvReleaseImage(&image);
cvReleaseImage(&src);
cvDestroyWindow("color recognition");
return 0;
}