zoukankan      html  css  js  c++  java
  • OpenCV2邻域和模板操作

    在图像处理中,通过当前位置的邻域像素计算新的像素值是很常见的操作。当邻域包含图像的上几行和下几行时,就需要同时扫描图像的若干行,这就是图像的邻域操作了。至于模板操作是实现空间滤波的基础,通常是使用一个模板(一个的矩形)滑过整幅图像产生新的像素。下面介绍通过使用OpenCV2实现Laplace算子锐化图像,来介绍OpenCV2中对邻域和模板的操作。

    锐化处理主要的目的是突出灰度的过渡部分,通常由微分来定义和实现锐化算子的各种方法。Laplace算子是最贱的各向同性微分算子,常用的Laplace模板如下:

    image

    使用Laplace算子锐化图像时需要注意模板中心的系数,如果中心系数是负的,就需要将原图像减去经过Laplace算子处理后的图像,得到锐化后的结果。如果中心系数是正的,则相反。

    锐化图像时不能以In-Place的方式来完成,需要提供一个输出图像。在对图像遍历时使用两个3个指针:一个指向当前行,一个指向当前行的上一行,一个指向当前行的下一行。而且,由于每个像素值的计算都需要它的上下左右四个相邻像素,所以无法对图像的边界进行计算,需要另作处理。具体实现代码如下:

       1:  /*
       2:      0    -1    0
       3:      -1    4    -1
       4:      0    -1    0
       5:  */
       6:  void sharpen(const Mat & image,Mat & result)
       7:  {
       8:      CV_Assert(image.depth() == CV_8U);
       9:   
      10:      result.create(image.size(),image.type());
      11:   
      12:      const int channels = image.channels() ;
      13:      for(int j = 1 ;j < image.rows - 1 ; j ++){
      14:          const uchar * previous = image.ptr<const uchar>(j - 1) ; // 当前行的上一行
      15:          const uchar * current = image.ptr<const uchar>(j) ; //当前行
      16:          const uchar * next = image.ptr<const uchar>(j + 1) ; //当前行的下一行
      17:   
      18:          uchar * output = result.ptr<uchar>(j) ;  // 输出行
      19:          for(int i = channels ; i < channels * (image.cols - 1) ; i ++) {
      20:              * output ++ = saturate_cast<uchar>( 4 * current[i] - previous[i] - next[i] - current[i - channels] - current[ i + channels]) ;
      21:          }
      22:      }
      23:   
      24:      //对图像边界进行处理
      25:      //边界像素设置为0
      26:      result.row(0).setTo(Scalar(0));
      27:      result.row(result.rows-1).setTo(Scalar(0)) ;
      28:      result.col(0).setTo(Scalar(0));
      29:      result.col(result.cols-1).setTo(Scalar(0));
      30:  }

    这里使用指针遍历整个图像,使用三个指针同时扫描图像的三行,另外使用一个指针指向输出行。在计算输出像素时,使用模板函数saturate_cast<uchar>对计算结果进行调整。这是因为对像素值的计算有可能导致结果超出了像素允许的范围,即小于0或者大于255,当计算结果是浮点数时,该函数会将结果取整至最近的整数。

    由于边界的像素没有完整的邻域,无法使用模板计算其值,需要单独处理。这里只是简单的将其值设为0.

    测试代码:

       1:      Mat image = imread("d:\lenna.jpg") ;
       2:      Mat result ;
       3:      sharpen(image,result) ;
       4:      imwrite("d:\lenna1.jpg",result) ;
       5:      imwrite("d:\lenna2.jpg",image + result) ;

    结果如下:

    imageimage

    这里需要说明,在OpenCV2中对Mat进行了大量的运算符重载,例如上面,两幅图像相加直接使用image + result即可。另外,如位操作符:&,|,^,~;函数max,min,abs;比较操作符:<,<=,>,>=,比较操作符返回一个8位二进制图像。另外矩阵乘法m1 * m2,矩阵求逆 m1.inv(),矩阵转置m.t(),举证的行列式m.determinate(),向量的模v.norm(),向量叉乘v.corss(v1),向量的点乘v.dot(v1)等。

    由于使用模板实现空间滤波在图像处理中非常的常用,在OpenCV中专门定义了一个特殊的函数来完成该处理:
    filter2D.

    函数原型:

       1:  void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT )

    参数:
    src,输入图像
    dst 输出图像,和输入图像有相同的大小和通道
    ddepth 输出图像的depth,如果为负数,则和输入图像的depth相同
    kernel 模板
    anchor 进行卷积运算的中心位置,默认的是kernel的中心
    delta 可选值,加到输出像素上的值
    bordertype 对输出图像边界的处理。

    使用filter2D实现Laplace算子

       1:      Mat kern = (Mat_<char> (3,3) << 1,1,1,
       2:                                      1,-8,1,
       3:                                      1,1,1) ;
       4:      filter2D(image,result,image.depth(),kern) ;
    这里只需要定义好kernel调用filter2D即可,而且OpenCV对该函数进行了优化,其效率要比上面使用指针实现的要高。

  • 相关阅读:
    BZOJ2199[Usaco2011 Jan]奶牛议会——2-SAT+tarjan缩点
    BZOJ3862Little Devil I——树链剖分+线段树
    BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树
    BZOJ1018[SHOI2008]堵塞的交通——线段树
    BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并
    BZOJ4127Abs——树链剖分+线段树
    bzoj 4753 最佳团体
    bzoj 4472 salesman
    bzoj 5369 最大前缀和
    bzoj 1226 学校食堂Dining
  • 原文地址:https://www.cnblogs.com/wangguchangqing/p/3710397.html
Copyright © 2011-2022 走看看