OpenCV 学习笔记(二)
我们这里讨论两个常见的操作,一个是 filtering,一个是 histogram。
filtering
如果我们仅仅考虑小的卷积核,如 3×3 的,一种简单的实现就是直接将每点的值根据上下左右的算一遍。我们可以将每行上下的指针也拿到,这样就可以在遍历过程中同时获得对应的位置的 pixel 进行计算了。这个计算过程必然是需要在新的空间存放结果。
cv::Vec3b* prev_row, cur_row = im.ptr<cv::Vec3b> (0), next_row = im.ptr<cv::Vec3b> (1) ;
for (int i = 1 ; i < nlm1 ; ++i) {
prev_row = cur_row ; cur_row = next_row ; next_row = im.ptr<cv::Vec3b> (i+1) ;
cv::Vec3b* cur_output_row = out.ptr<cv::Vec3b> (i) ;
// similar init for column
for (int j = 1 ; j < ncm1 ; ++ j) {
// visit things we need to compute the output
}
}
另一种实现是直接调用 cv::filter2D,这是一个依赖于 FFT 的实现,卷积等于 ifft(fft(img) * fft(kernel)),这样可以在频域直接相乘就 OK 了。
cv::filter2D (src, dst, 3, kernel, cv::Point (-1, -1), BORDER_DEFAULT) ;
当然,OpenCV2 提供给我们的工具远远不止这些,它还提供了抽象类 cv::FilterEngine,对应的一些 filter 的基类(cv::BaseFiler、cv::BaseRowFilter 与 cv::BaseColumnFilter),我们可以通过 cv::create* 系获得对应的 filter engine 实例(一般用 cv::Ptr 封装的指针),或者 get*Kernel 获得某些 filtering 函数的 kernel。同时提供了控制边界外插的方式(cv::borderInterpolate)。在此之上,还封装了一些常用的 filter 函数。下面列出来了几种常见 filtering 方法,
- createBoxFilter 获得的是矩形里面的均值 filter;
- createDerivFilter 获得的是求图片梯度的 filter,这实际上通过 getDerivKernel 然后 getSeparableLinearFilter 获得的,cv::Sobel 和 cv::Scharr 均为这个方法获得的特例;
- createGaussianFilter 获得 Gaussian filter,这是通过 getGaussianKernel 然后 getSeparableLinearFilter 获得的,cv::GaussianBlur 是对它的封装;
- createLinearFilter 是通过 getLinearFilter 然后通过 cv::filter2D 获得的;与 separable linear filter 相比,后者可以 decompose 成为两维 convolution 的直积,因此前者更为 general 一些;
- createMorphologyFilter 是通过 getMorpholologyFilter 然后生成的 filter,cv::dilate、cv::erode 与 cv::morphologyEx 都是这类生成的;相关的还有 getStructuringElement,这个使用的是 sepFilter2D。
- createSeparableLinearFilter 很简单了。
有了这些还有比如 cv::bilateralFilter(保持边的 blur),cv::BuildPyramid 获得 Gaussian pyramid 作用在图像获得的序列。
直方图
直方图就是统计 pixel 分布的一种工具,通常我们会为每个 channel 建立若干 bin,然后在遍历图片的过程中计算出对应的编号,如果这一维最大是 ,当前值为
,取
个 bin,则 bin 编号为
四舍五入即可。我们拿到了编号序列后,根据遍历多维数组的顺序就能计算出来从 hist.data 开始走多远这个值存放的位置了。
为了方便我们计算直方图,OpenCV2.x 提供了 cv::calcHist。同时为了比较两个 histogram 的差距,提供了 cv::compareHist,这个函数支持 correlation、、交集和 Bhattacharyya 距离。
通常根据直方图我们可以做 cv::threshold 将图片变成二值的,也可以用所谓 LUT(look up table)进行变换(类似 PS 中的 curve 操作),函数为 cv::LUT。另有所谓 histogram equalization,保证有 p% 的 pixel 的颜色在 2.55p 以下,这通常用 cumulative histogram 作为 LUT 即可。
最后提一下的是通过 histogram 选择颜色的一种策略,即首先选定一个小区域,获得这个区域的 histogram,然后将此作为 LUT,即落入 bin 的像素取对应颜色在选取区域中的比例,某些颜色比较单一的场景可以通过这种技术选择连续的物体。注意事后一般会 normalize 一下。
histogram 本身在 vision 中的应用非常多,不少 feature 的 descriptor 选择它,同时可以用来做颜色相近的 retrieval 等等。
——————
And the king of Sodom went out to meet him after his return from the slaughter of Chedorlaomer, and of the kings that were with him, at the valley of Shaveh, which is the king’s dale.