图像任意子区域直方图快速计算

当逐像素地对像素进行邻域操作时(比如邻域求和,求邻域图像块的直方图等),运算量就会很大。这个时候可以想到用积分图像,可以这样看,积分图像是占用了前期时间,减少了后期大量重复运算。

下面介绍一种快速计算图像任意子区域直方图的方法,方法实现的过程描述如下:

假设最终得到的直方图箱子数(通俗点就是直方图的横坐标的单位数)为nplanes,nplanes是2的幂;输入的灰度图大小为rows*cols。

首先创建一个rows*cols大小、nplanes个通道的图像planes,可以将每个通道理解为二维的箱子(而通常直方图的箱子都是一维的);

然后将planes的每个通道按一定规则填充二值图像,在当前通道的某位置,若源图像该位置的灰度值属于该箱子则值为1,否则为0;

//将灰度图转化为二值图的多通道图像
//nplanes为通道数,可以是256,128,...必须是2的幂,其实就是减色
void convertToBinaryPlane(const cv::Mat& input,cv::Mat& output,int nplanes)
{
    //屏蔽位数
    int n = 8 - static_cast<int>(log(static_cast<float>(nplanes)) / log(2.0));
    uchar mask = 0xff << n;
    //减色后的输入图像
    cv::Mat reduced;
    reduced=input & mask;
    //计算每个二值平面
    std::vector<cv::Mat> planes;
    for (int i = 0; i < nplanes; i++)
    {
        planes.push_back(reduced==(i<<n)&0x1);
    }
    //创建多通道图像
    cv::merge(planes,output);//planes和output仅仅是形式的区别,一个vector,一个是mat。所以这里output即是叙述中的planes,
}

再计算planes的积分图像。

最后任意划出一块区域,就可以利用积分图像分别计算每个箱子的值,每个箱子只需要计算4次(2次加法2次减法),计算复杂度为nplanes*4。

//后两步包括计算积分图像和计算任意区域直方图,通过一个很巧妙的模板类来实现

template<typename T,int N>
class IntegralImage
{
private:
    cv::Mat integralImage;
public:
    IntegralImage(cv::Mat image)
    {
        //计算积分图像,很耗时,待计算的图像大小为cols*rows*N
        cv::integral(image, integralImage, cv::DataType<T>::type);
    }

    //共N层,每层返回一个数,总的就是一个vector,或者说N行1列的Mat。
    //这样就通过()操作符,实现了就算任意子区域直方图计算
    cv::Vec<T, N> operator()(int x0,int y0,int width,int height)
    {
        return (integralImage.at<cv::Vec<T, N>>(y0 + height, x0 + width) -
            integralImage.at<cv::Vec<T, N>>(y0, x0 + width) -
            integralImage.at<cv::Vec<T, N>>(y0 + height, x0) +
            integralImage.at<cv::Vec<T, N>>(y0, x0));
    }
};

怎么使用上面的方法还有类呢?
例,输入图像为image,求取子区域Rect(x0,y0,width,height)的直方图,直方图的箱子数设为N,代码如下:

//首先创建N个平面的二值图像
cv::Mat planes;
convertToBinaryPlane(image,planes,N);
//然后计算积分图像
IntegralImage<float, N> intHistogram(planes);
//用积分图像计算N个箱子的直方图
cv::Vec<float,N> ROIHist = intHistogram(x0, y0, width, height);

最后总结一句:这个模板类设计得实在是太棒了。目前我还尚未驾驭模板类哪~

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值