1、什么是掩膜操作?
- 掩膜操作是一种使用特定物品对某一区域进行掩盖,从而能够对指定区域进行特殊处理的一种操作方式。
2、掩膜操作的作用
- 在进行图像处理中,通过掩膜操作能够提升图像整体的对比度,使得图片更加醒目。
- 第一幅是没有经过掩膜操作的图片:
- 第二幅是经过掩膜操作的图片
由上述两幅图片对比可以发现,第二幅图片纹理更加清晰,对比度更加明显。
3、对OpenCV中掩膜操作算法的理解
(1)掩膜操作的公式:
这个公式所表述的意思其实就是将某个像素值重置,重置之后的值与和该像素相邻的上下左右四个像素值有关,具体的数学关系就是:该点经过掩膜之后像素值 = 五倍的该点原先的像素值 - 与之相邻上面的像素值 - 与之相邻下面的像素值 - 与之相邻左边的像素值 - 与之相邻右边的像素值。
(2)下面通过图像再次讲解:
其中a表示我们要处理的像素点,b、c、d、e分别为与a相邻的上下左右的像素点。
未经过掩膜处理之前,a点的像素值为a,经过掩膜操作处理之后,a点的像素值为A,则
上述3*3表格如果用数字表示,则对应的矩阵应当是:[ 0 -1 0; -1 5 -1; 0 -1 0]
(3)一副图片在计算机中是通过一个庞大的数字矩阵存储。因此,这个3*3的表格就相当于一个掩膜矩阵,通过这个掩膜矩阵,就可以对图片矩阵进行掩膜操作(改变图片矩阵的像素值)。但是,这个掩膜矩阵在图片矩阵中到底是怎样运动的呢?它会改变那些数字?会用到哪些数字呢?
如上图所示,有一个n*m的数字矩阵,掩膜矩阵会改变从第二行到第(n-1)行、第二列到第(m-1)列的像素值,也就是上述中红线区域之内的像素值,靠近矩阵边缘的一行(列)像素值并不会改变。
(4)通道数直接决定图片数字矩阵的列数,影响着后面代码的编写。对于单通道而言,n*m的数字矩阵的列数就是m;但是对于三通道(RGB图片)而言,n*m的数字矩阵的列数就是m*3。这是因为,在三通道矩阵中,每一列中又有三个子列。掩膜矩阵在进行上述的移动是,起始行不便,但是起始列应当从第一列(第三个子列)开始进行移动。
(5) 进行代码编写:
//根据掩膜公式,进行算法编程
Mat dst; //另创建一个Mat对象,用来存储进行掩膜操作之后的图片
dst = Mat::zeros(src.size(), src.type()); //初始化dst对象
//获取原图片的行数以及列数
int src_rows = src.rows;
int src_cols = (src.cols - 1) * src.channels();
int offsetx = src.channels();
//通过指针过去图像的像素并进行掩膜操作
for (int row = 1; row < src_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); //用来保存经过掩膜操作之后的像素
for (int col = offsetx; col < src_cols; col++) { //从第二列到倒数第二列RGB图像每一列又分为三小列
output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx]
+ previous[col] + next[col])); //确保像素值在0~255之间
}
}
4、相关API
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst, -1, kernel);