之前写过一篇【opencv】带你再学一遍直方图,里面的内容可以看下图。所以今天还要再再再学一个直方图的API:直方图反投影。
直方图反向投影是干啥的呢,它用于图像分割或在图像中查找感兴趣的对象。用什么来查找呢?用直方图。
直方图在一定程度上可以反应图像的特征,我们截取一个有固定特征的样例,比如草地,然后计算该块草地的直方图,然后用这个直方图去和整幅图像的直方图做对比,根据一定的判断条件,就能得出相似的即为草地。
看着就像是语义分割,其实一定意义上这就是语义分割,这不过直方图反向分割的依据是人为计算的(直方图),后者分割的依据是靠在神经网络中学习得来的。
我们先看一下opencv直方图反向计算得API:
void cv::calcBackProject(
const Mat * images, //要进行投影的输入图像的地址,注意该API要求输入的是地址
int nimages,//输入图像的数目
const int * channels,//要进行投影的通道数
InputArray hist,//样本得直方图
OutputArray backProject,//输出得反向投影,为Mat类型
const float ** ranges, //输入直方图得特征空间的取值范围
double scale = 1,
bool uniform = true
)
一:该API得实现原理是什么呢
假设我们现在有一个四行四列得灰度图,它得灰度值如下图:
说这幅图有什么特征呢?直观上看类似于一个边角,但这是直观上,怎么表示出来呢?深度学习是靠神经网络黑箱计算出来得,我们可以用直方图。
那我们就计算这幅灰度图得直方图,如果以组距为1计算直方图并反向投影到原图,得到得为下图:
可以大概表述一下边角得特征:左下角有6个像素值相同得三角形区域,中间斜向下有四个像素值相同得边界线,以此类推。这就是用直方图得到得边角得特征。
那如果以组距为2计算直方图呢?反向投影后为:
可以看到特征描述得更为广泛了,就像深度学习里,提取更高层次得特征,虽然更为普适,但也会忽略掉一些细节特征。
我们就是拿这个反向投影所表达得特征信息,去和整幅图做对比,来得到特征相似得部分,达到分割得效果。
二:利用反向投影进行语义分割
先看一下我们今天要处理得图片:
我们今天要做得就是将这条公路给提取出来。
1,先读取原图以及样本图,并转换为HSV格式。
//【1】读取图片
Mat srcImage = imread("风景图.jpg");
Mat RoiImage = imread("公路2.png");
//【2】转换为HSV图像
Mat HsvImage, RoiImage_HSV;
cvtColor(srcImage, HsvImage, COLOR_BGR2HSV);
cvtColor(RoiImage, RoiImage_HSV, COLOR_BGR2HSV);
为什么转HSV呢?因为HSV表达颜色更为方便区分,我们今天用到得只有前两个通道:H(色调)和S(饱和度),不用V(亮度)。
来看一下我们截取得样本图:
这是我们在公路上随便截取得一块儿样本,可以看到整条公路大概都是这个样子。
2,计算样本图得直方图并进行归一化
//【3】计算公路的直方图
MatND roiHist; //直方图对象
int dims = 2; //特征数目(直方图维度)
float hranges[] = {
0,180 }; //特征空间的取值范围
float Sranges[] = {
0,256 };
const float *ranges[] = {
hranges,Sranges };
int size[] = {
20,32 }; //存放每个维度的直方图的尺寸的数组
int channels[] = {
0,1}; //通道数
calcHist(&RoiImage_HSV,1, channels, Mat(), roiHist, dims, size, ranges);
//【4】直方图归一化
normalize(roiHist, roiHist, 0, 255, NORM_MINMAX);
代码第7行,我们计算H和S通道直方图的组距分别为20和32,我们采用更小的组距来抓取更大的特征区域。
为什么要归一化呢,直方图反向投影到原图后,原图各位置表示的是整幅图中等于该点像素值的数量,归一化后就变成概率了。
3,将计算的归一化后的直方图进行反向投影
//【5】反向投影
Mat proImage; //投影输出图像
calcBackProject(&HsvImage, 1, channels, roiHist, proImage, ranges);
反向投影后的原图:
可以大概看出公路的轮廓了吧?
4,上一篇图像腌膜Mask的常规操作你真的信手拈来吗?介绍了掩码操作,这里我们就要用掩码将公路给抠出来显示:
效果并不是想象中那么好是吧哈,感觉还是语义分割要更准确些。但准确能当女朋友吗?
后期再加上些边缘检测和霍夫直线变换,和一些其他骚操作,就可以提取公路啊,车道线啥的了。
如果觉的有帮助,就点个赞再走吧~
另外我分享了近6G视觉各门类电子书,公众号后台回复【电子书资源】自取呀。