opencv 例程讲解5 ---- 如何实现卷积运算

         图像可以看作一个矩阵,在矩阵上面做掩模操作是一个很普遍的事情,它实际上可以看做利用一个小矩阵对一个大矩阵进行卷积运算,这个小矩阵便是掩模,也称核(kernel)。很多功能的实现都依赖于掩模操作,如图像平滑,锐化,以及腐蚀膨胀等形态学的一些操作。下面我们来看下Opencv中的例程——(TUTORIAL) mat_mask_operations。

例程中使用了一个3x3的掩模对图像进行操作,实现锐化效果。先简单介绍下使用到的掩模,如下所示。

可以看出,为得到新图像中(i,j)位置的灰度值,需要借助一个卷积窗口,窗口大小与掩模大小一致,由以(i,j)为中心的图像像素组成,则卷积运算可以看做是卷积窗口中各像素点的加权和,每个像素点的加权大小对应于掩模中相应位置的值。上图中,一次卷积需要1次乘法,4次加减法。由于不只是对当前像素点遍历,还需要借助相邻像素进行计算,所以例程中使用的图像遍历方法是C的[ ] 下标访问方式。相应的,opencv对于掩模操作有自己的函数,filter2D,下面便是性能对比。


源代码中每种方法只允许了一遍,为了测试的准确性,我在程序中加了一个循环,这个结果是100次运算的平均时间。可以看出使用opencv的filter2D函数比自己手工打造的掩模操作性能上提高了39%

下面我们看下手工打造的掩模操作是如何实现的

void Sharpen(const Mat& myImage,Mat& Result)
{
    CV_Assert(myImage.depth() == CV_8U);  // accept only uchar images   // CV_Assert 是cv定义的断言格式,如果条件不符合,会中断程序,抛出异常

    const int nChannels = myImage.channels();
    Result.create(myImage.size(),myImage.type());

    for(int j = 1 ; j < myImage.rows-1; ++j)                             // 第一行和最后一行无法计算
    {
        const uchar* previous = myImage.ptr<uchar>(j - 1);      //   上一行数据的指针
        const uchar* current  = myImage.ptr<uchar>(j    );        //   当前行数据的指针
        const uchar* next     = myImage.ptr<uchar>(j + 1);       //  下一行数据的指针

        uchar* output = Result.ptr<uchar>(j);                            // 输出图像当前列数据的指针

        for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i)   // 同理,忽略第一列和最后一列像素
        {
            *output++ = saturate_cast<uchar>(5*current[i]
                         -current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);         // 计算新值
        }
    }
    // 将边界设为0
    Result.row(0).setTo(Scalar(0));
    Result.row(Result.rows-1).setTo(Scalar(0));
    Result.col(0).setTo(Scalar(0));
    Result.col(Result.cols-1).setTo(Scalar(0));
}

可以看出,例程中利用了3个指针,分别用于定位在3行中的像素,实现对相邻像素的操作。输入图像(my

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值