利用摄像头获取YUV422 640*480,然后变换为YUV444 320*240,这种操作可以一定程度上增加图像本身的清晰度(当然相对与直接获取320*240的图像)。
在 YCrCb 颜色空间中,Y 值主要表征亮度,颜色主要由Cr 和 Cb 决定,因而直方图由原本灰度图像的一维变为彩色图像的 CrCb 维。考虑到二维空间上搜索峰值比较复杂,为了简化问题,将 Cr 和 Cb 的取值范围 0-255 均分为 32 份,其颜色落在同一区间的所有像素点累计在一起,只要搜索其中累计点数最多的“块”即可,同时也大大减少了搜索时间。
通过大量实验表明,比赛中的几种重要颜色的CrCb分量在不同的光照变动并不明显,完全可以在特定范围内进行搜索。每一个峰值应该都有与之对应的物体。因此根据峰值出现的Cr和Cb取值范围就可以回到图像中找到对应的像素点,完成图像分割的工作。下图1为根据实验得到的二维直方图。从图中可以看出黄色与橙色有交叉。
在实际处理时需要考虑各种可能的情况:如果区域内出现两个峰值,可以据 Cr 的数值加以判断;如果有一个峰值,则要结合图像中其他颜色出现的情况,如果有相当数量的粉色像素点,说明是球门柱的黄色;如果该峰值点数很多,说明是球门的黄色,否则是球的橙色。图2为分割的实验结果。这种方法对于黄色蓝色橙色的分割效果比较好,在光照变化不是很明显的情况下可以有效的找到目标区域。
C++源程序:
// CvTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <highgui.h>
#include <cv.h>
#include <fstream>
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
int hist[32][32]={0};
CvScalar ptr = {};
ofstream outfile;
outfile.open("new.txt",ios::out);
IplImage* src = cvLoadImage("show8.jpg", 1);
IplImage* YUVImage = cvCreateImage(cvGetSize(src),8,3);
CvPoint ycount={};
int yColorNumber = 0;
CvPoint ocount={};
int oColorNumber = 0;
CvPoint bcount={};
int bColorNumber = 0;
CvPoint ycenter={};
CvPoint ocenter = {};
CvPoint bcenter = {};
cvCvtColor( src, YUVImage, CV_RGB2YCrCb );
for (int x=0;x<YUVImage->width;x++)
{
for (int y=0;y<YUVImage->height;y++)
{
ptr = cvGet2D(YUVImage,y,x);
hist[((unsigned)ptr.val[1])/8][((unsigned)ptr.val[2])/8]++;
//blue max point(20,10)
if ((unsigned)ptr.val[1]>149 && (unsigned)ptr.val[1]<175 && (unsigned)ptr.val[2]>50 && (unsigned)ptr.val[2]<90 )
{
ptr.val[0]=255;
ptr.val[1]=0;
ptr.val[2]=0;
cvSet2D(src,y,x,ptr);
bcount.x = bcount.x + x;
bcount.y = bcount.y + y;
bColorNumber++;
continue;
}
//yellow max point(12,16)
if ((unsigned)ptr.val[1]>80 && (unsigned)ptr.val[1]<110 && (unsigned)ptr.val[2]>80 && (unsigned)ptr.val[2]<159)
{
ptr.val[0]=0;
ptr.val[1]=255;
ptr.val[2]=255;
cvSet2D(src,y,x,ptr);
ycount.x = ycount.x + x;
ycount.y = ycount.y + y;
yColorNumber++;
continue;
}
//origion max point(8,23)
if ((unsigned)ptr.val[1]>40 && (unsigned)ptr.val[1]<105 && (unsigned)ptr.val[2]>160 && (unsigned)ptr.val[2]<250)
{
ptr.val[0]=0;
ptr.val[1]=67;
ptr.val[2]=255;
cvSet2D(src,y,x,ptr);
ocount.x = ocount.x + x;
ocount.y = ocount.y + y;
oColorNumber++;
continue;
}
//green max point(16,13)
if ((unsigned)ptr.val[1]>128 && (unsigned)ptr.val[1]<150 && (unsigned)ptr.val[2]>85&& (unsigned)ptr.val[2]<125)
{
ptr.val[0]=0;
ptr.val[1]=255;
ptr.val[2]=0;
cvSet2D(src,y,x,ptr);
continue;
}
}
}
for (int i=0;i<32;i++)
{
for (int j=0;j<32;j++)
{
if (hist[i][j]!=0)
{
printf("(x,y) (%d ,%d) :%d\n",i,j,hist[i][j]);
}
outfile<<hist[i][j]<<endl;
}
}
ycenter.x = ycount.x/yColorNumber;
ycenter.y = ycount.y/yColorNumber;
ocenter.x = ocount.x/oColorNumber;
ocenter.y = ocount.y/oColorNumber;
bcenter.x = bcount.x/bColorNumber;
bcenter.y = bcount.x/bColorNumber;
cvCircle(src,ycenter,4,CV_RGB(255,100,0),-1,8,0);
cvCircle(src,ocenter,4,CV_RGB(0,255,255),-1,8,0);
cvCircle(src,bcenter,4,CV_RGB(255,0,0),-1,8,0);
cv::namedWindow("image",CV_WINDOW_AUTOSIZE);
cv::imshow("image",src);
cvWaitKey(0);
outfile.close();
return 0;
}
matlab程序:生成2维直方图
function [ output_args ] = Untitled3( input_args )
%UNTITLED3 Summary of this function goes here
% Detailed explanation goes here
m=32;
n=32;
[i,j]=ndgrid(1:m,1:n);
count=0;
fp=fopen('new.txt');
B=fscanf(fp,'%f');
A = zeros(32,32);
for ii=1:32
for jj=1:32
A(ii,jj)=B(jj+count);
end
count = count+32;
end
%A=rand(m,n)./(0.1+abs(i/500-.5))./(0.1+abs(j/40-.5))
bar3(A)
axis([0,n,0,m])
camproj perspective
view(-8,10)
xlabel('Cr')
ylabel('Cb')
zlabel('统计值')
end