利用攝像頭獲取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