在进行机器学习中,不管是用Haar特征,或者是Hog特征,最后进行的不论是adaboost分类,还是svm分类,都只能是检测出待检测的正样本相近的图片。
比如,为了提高准确性,我们在进行正样本的训练时,必须把正样本置于整个正样本的大部分中,以交通标志中的禁止驶入为例,如下图的就是正确的正样本之一:
我们可以看到,禁止驶入交通标志占了图片面积的大部分。这在训练时,可以尽可能的减少误差。如下图就是个错误的例子:
在这幅图片中,我们只能在右面的一小块区域发现禁止驶入的交通标志。这个是错误的正样本。因为有太多的干扰项。
那么,我们进行实际检测时,不可能只是对如图1的图片进行检测,实际情况中,往往是如图2所示,那么,我们直接用检测方法,毫无疑问的,得到的一定是错误结果。
于是,就得到了,如何从一张图片中提取到我们感兴趣的区域。如图2中,在进行实际检测时,必然是先从这张图片中检测出右上角的禁止驶入的交通标志的区域,然后,在对其进行匹配处理,看是哪个标志,或者是不是交通标志。
这里,我们先以交通标志为例,这篇文章的主要算法思想,也是针对例如交通标志这种的,颜色划分比较明显的进行叙述。
好了,正如上段所说的,我们主要的算法思想是,针对诸如交通这类,因为我们都知道,交通标志主要分为四种颜色,即RGBY,在检测时,我们可以想得到,如果把待检测图片,分成RGBY四种颜色,那么,就能得到交通标志的区域外轮廓。再用边缘检测,可以选择用canny边缘检测,并且求出每个不连通的边缘的最小外界矩形,返回这个矩形的所在位置,就能得到我们感兴趣的区域。
当然,为了方便起见,我们可以直接用opencv中的cvFindCounter()函数,这个函数的第三个矩形,可以返回一个矩形轮廓。我们分别对返回的矩形轮廓进行检测(很明显不会只返回一个轮廓,当然,下面我们会介绍几种尽可能排除掉不希望有的矩形的返回值),最后得到想要的结果。
下面是算法的具体介绍。
首先是说明,我们用的是Hog特征检测和Svm二分类。用的编译环境是vs2010,opencv2.4.9。
然后是,对待检测图片进行分色。我们知道的,原图片一般都是RGB三色通道(CMYK是打印颜色,我们这里先不做考虑),转到RGBY,opencv上没有转的函数,我们可以选用两种方法。一种是直接转,即用RGB直接分离通道,然后得到RGB的通道,Y通道,利用黄颜色是蓝色的补色,利用补色直接转。利用Y=255-B,可以得到最后的黄色的图片的结果。
注:这里的是粗转换,如果想进行准确的RGB转Y或者转CMYK的,要注意的是最好用PS转,因为我们没有进行配置文件的添加和处理,最后会由于CMYK颜色空间比RGB颜色空间小,而得不到正确的图片,具体请参考文章最后的链接,我们可以看出,不能得到和原图一样的效果,是因为颜色被压缩了。
int rgb2cmyk( Mat &image,Mat &cmyk){
if(!image.data){
cout<<"Miss Data"<<endl;
return -1;
}
int nl = image.rows; //行数
int nc = image.cols; //列数
if(image.isContinuous()){ //没有额外的填补像素
nc = nc*nl;
nl = 1; //It is now a 1D array
}
//对于连续图像,本循环只执行1次
for(int i=0;i<nl;i++){
uchar *data = image.ptr<uchar>(i);
uchar *dataCMYK = cmyk.ptr<uchar>(i);
for(int j = 0;j < nc;j++){
uchar b = data[3*j];
uchar g = data[3*j+1];
uchar r = data[3*j+2];
uchar c = 255 - r;
uchar m = 255 - g;
uchar y = 255 - b;
uchar k = min(min(c,m),y);
dataCMYK[