有时候感兴趣的目标具有圆形的特征,我们会希望能计算处以每个像素点为中心的圆形区域的元素和或是均值,这里本人就分享一下自己编写的快速计算任意圆形区域内元素和与均值的程序。程序原理非常简单,就是中心像素点在移动的过程中,区域中改变的只有边缘点,所以我们只需要考虑由这些边缘点的增减所导致的和值的改变即可。废话不多说,下面上代码:
Mat getSumOfElementsInCirCle(Mat& img, int r)
{
Mat elemSumImg = Mat::zeros(img.size(), CV_32F);
Mat paddedImg;
int rows = img.rows;
int cols = img.cols;
copyMakeBorder(img, paddedImg, r, r, r, r, BORDER_CONSTANT, 0);
paddedImg.convertTo(paddedImg, CV_32F);
Mat mask = Mat::ones(img.size(), CV_32F);
copyMakeBorder(mask, mask, r, r, r, r, BORDER_CONSTANT, 0);
Mat validPixNumImg = Mat::zeros(img.size(), CV_32F);
vector<Point2i> vecPosShift;
vector<Point2i> vecPosShiftBorder;
vector<Point2i> vecPosShiftBorder_UpHalf;
vector<Point2i> vecPosShiftBorder_DownHalf;
for (int i = -r; i <= r; i++)
{
for (int j = -r; j <= r; j++)
{
int disSq = i * i + j * j;
if (disSq <= r * r)
{
vecPosShift.push_back(Point2i(j, i));
}
if (disSq >= (r - 0.5)*(r - 0.5) && disSq <= (r + 0.5)*(r + 0.5))
{
vecPosShiftBorder.push_back(Point2i(j, i));
}
}
}
for (auto it = vecPosShiftBorder.begin(); it != vecPosShiftBorder.end(); it++)
{
if (it->y <= 0)
{
vecPosShiftBorder_UpHalf.push_back(*it);
}
if (it->y >= 0)
{
vecPosShiftBorder_DownHalf.push_back(*it);
}
}
for (int j = 0; j < cols; j++)
{
for (auto it = vecPosShift.begin(); it != vecPosShift.end(); it++)
{
elemSumImg.at<float>(0, j) += paddedImg.at<float>(r + it->y, j + r + it->x);
validPixNumImg.at<float>(0, j) += mask.at<float>(r + it->y, j + r + it->x);
}
}
for (int i = r + 1; i < rows + r; i++)
{
for (int j = r; j < cols + r; j++)
{
elemSumImg.at<float>(i - r, j - r) = elemSumImg.at<float>(i - r - 1, j - r);
validPixNumImg.at<float>(i - r, j - r) = validPixNumImg.at<float>(i - r - 1, j - r);
for (auto it = vecPosShiftBorder_UpHalf.begin(); it != vecPosShiftBorder_UpHalf.end(); it++)
{
elemSumImg.at<float>(i - r, j - r) -= paddedImg.at<float>(i - 1 + it->y, j + it->x);
validPixNumImg.at<float>(i - r, j - r) -= mask.at<float>(i - 1 + it->y, j + it->x);
}
for (auto it = vecPosShiftBorder_DownHalf.begin(); it != vecPosShiftBorder_DownHalf.end(); it++)
{
elemSumImg.at<float>(i - r, j - r) += paddedImg.at<float>(i + it->y, j + it->x);
validPixNumImg.at<float>(i - r, j - r) += mask.at<float>(i + it->y, j + it->x);
}
}
}
Mat dstImg;
divide(elemSumImg, validPixNumImg, dstImg);
return dstImg;
}
测试图:
该图是下图中各像素块与参考纹理块求直方图相关性后进行图像反相的结果(参见我上一篇博客),最大值应该在圆心位置附近。
下图是根据程序求得的各圆形区域内局部均值结果:
这样或许看起来仍不显著,我们用ImageWatch插件最大化一下对比度,结果如下:
可以看到,最大值的确在圆心附近,验证了我们的假设。以上就是今天博客的内容,有时间再更新其他内容。