1. 矩阵掩模原理:
矩阵掩模算法feic非常简单,例如将一个3X3的矩阵,一张图像,对图像的每个像素点进行如下操作:

1.分别从左到右,从上到下,每个通道,拿3X3矩阵和原图对应位置做内积,最后得到的值在赋值给zhon中心像素点

简单例子:

通过如下3X3矩阵来做掩模,可以提高图像的对比度

                                          

opencv python掩膜拼接 opencv 矩阵掩膜操作_opencv python掩膜拼接

如上图所示,红色是中心像素,从上到下,从左到右对每个像素做同样的处理操作,得到最终结果就是对比度提高之后的输出图像Mat对象。

开始之前,首先需要知道opencv中图像的存储方式:

还是先看Mat的存储形式。Mat和Matlab里的数组格式有点像,但一般是二维向量,如果是灰度图,一般存放<uchar>类型;如果是RGB彩色图,存放<Vec3b>类型。

单通道灰度图数据存放格式:

                                    

opencv python掩膜拼接 opencv 矩阵掩膜操作_opencv python掩膜拼接_02

                         图1

matlab是从(1,1)到(rows,cols),而opencv是从(0,0)到(rows-1,cols-1);

多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:

                     

opencv python掩膜拼接 opencv 矩阵掩膜操作_彩色图像_03

                            图2

注意通道的顺序反转了:BGR。所以说,在col上,图像的存储是每个通道连续的,每一列有三个通道的数据。所以在处理RGB图像时需要把图像的通道考虑进去。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace cv;

int main(int arc, char** argv)
{
    Mat src, dst;
    src = imread("H:/opencv/milu.png");
    if (!src.data)
    {
        printf("cound not load image...\n");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

   //每一列必须乘以通道数,因为有可能为彩色图像,列数为灰度的三倍
    //由于最外围的一圈像素点没办法进行图像掩模(因为我们算的是模板中心点的值,模板放在最边缘也算不出最外圈的掩模值),所以减1
    int cols = (src.cols - 1)*src.channels();
    int offsetx = src.channels();
  //行为图像的行
    int rows = src.rows;

    dst = Mat::zeros(src.size(), src.type());
   //row从1开始一直取到rows-2结束,表示不要对最外围的像素点掩模
    for (int row = 1; row < rows - 1; row++)
    {
     //通过像素指针,拿到行指针
        const uchar* previous = src.ptr<uchar>(row - 1);
        const uchar* current = src.ptr<uchar>(row);
        const uchar* next = src.ptr<uchar>(row + 1);
        uchar* output = dst.ptr<uchar>(row);
     //col从3开始(注意这里的3是图2中大的第四列了),因为彩色图像会有三个通道,最外围的像素点不掩模
        //每一个像素有BGR三个通道
        //分别对每个像素的BGR都要分别进行掩模操作
        for (int col = offsetx; col < cols; col++)
      
                                          //这里可以依据图2理解
            output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx]
                + previous[col] + next[col]));
        }
    }


    namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE);
    imshow("contrast image demo", dst);

    waitKey(0);
    return 0;
}

使用filter2D来实现只需要几行代码就可以搞定上面所有操作

double t = getTickCount();
    Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    filter2D(src, dst, src.depth(), kernel);
    double timeconsume = (getTickCount() - t) / getTickFrequency();
    printf("time consume %.2f", timeconsume);