掩码操作是根据核来重新计算每个像素点的值,也就是对该像素点根据周围的像素点做一个加权平均。
就以增强图片对比对来展示吧,使用的是下面的这个公式:
原图与效果图:
就以增强图片对比对来展示吧,使用的是下面的这个公式:
引用opencv中文社区的一句话:
矩阵掩码的思想是:根据掩码矩阵(也称作核)重新计算图像中每个像素的值。掩码矩阵中的值表示近邻像素值(包括该像素自身的值)对新像素值有多大影响。从数学观点看,我们用自己设置的权值,对像素邻域内的值做了个加权平均。
也就是对一个图片中的每一个像素点重新赋值。值的大小受到该像素点周围4个像素点的影响。
看上面公式,I(i,j)表示目标像素点,i和j分别表示像素点的横纵坐标。 I(i-1,j) 、I(i+1,j) 、 I(i,j-1) 、 I(i,j+1)分别表示目标像素点周围的四个像素点了。上面公式的作用就是,让自己增加4倍,然后减去周围像素点的值,所得到的值便是自己新的值。为什么要这样子做呢?假设b = [ I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)],如果目标像素颜色很鲜艳,它周围的像素点颜色不鲜艳,那么通过公式,也就是`5*I(i,j)-b >I(i,j)`,得到的值比原来的值大,也就是目标点会变得更加鲜艳。相反,目标像素点会变得更加不鲜艳。所以,这个掩码操作的作用就是突出像素点,让鲜艳的点更加鲜艳,让昏暗的点更加昏暗。这样操作之后从整个图片上看,图片就有了锐化的效果了。
掩膜操作的源代码:
#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<iostream>
#include<stdio.h>
using namespace cv;
using namespace std;
Mat Myfilter2D(Mat &srcImage)
{
const int nChannels = srcImage.channels();//获取图像的通道数,灰度图是1通道,彩色图是3通道
int nRows = srcImage.rows;
int nCols = (srcImage.cols-1) * nChannels;//因为掩膜的时候最后一列没有掩膜到,所以减少一列
int offset = nChannels;
Mat resultImage(srcImage.size(), srcImage.type());
//对图像进行掩膜,但是上下左右各都少了一行没有处理
for (int i = 1; i < (nRows - 1); i++)
{
//获取邻域指针
const uchar* previous = srcImage.ptr<uchar>(i - 1);//上一行的指针
const uchar* current = srcImage.ptr<uchar>(i);//当前行的指针
const uchar* next = srcImage.ptr<uchar>(i + 1);//下一行的指针
uchar* output = resultImage.ptr<uchar>(i);//输出图像当前行的指针
for (int j = offset; j < nCols; j++)//如果是多通道的话,每一个通道都进行掩膜
{
output[j] = saturate_cast<uchar>(5 * current[j] - (current[j - offset] + current[j + offset] + previous[j] + next[j]));
}
}
//对图像的边界进行处理,因为边界没有掩膜到所以和原图的像素值一样
//先处理上下
const uchar* src_top= srcImage.ptr<uchar>(0);//原图的第0行的指针
uchar* output_top = resultImage.ptr<uchar>(0);//输出图像的第0行指针
const uchar* src_buttom = srcImage.ptr<uchar>(srcImage.rows-1);//原图的最后一行的指针
uchar* output_buttom = resultImage.ptr<uchar>(resultImage.rows-1);//输出图像的最后一行指针
for (int i = 0; i < nChannels * srcImage.cols; ++i)
{
output_top[i] = src_top[i];
output_buttom[i] = src_buttom[i];
}
//在处理左右
for (int i = 1; i < srcImage.rows; ++i)
{
const uchar* src_left = srcImage.ptr<uchar>(i);//原图第一行的指针
uchar* output_left = resultImage.ptr<uchar>(i);//输出图第一行的指针
const uchar* src_right = src_left + nChannels*(srcImage.cols - 1);
uchar* output_right = output_left + nChannels*(resultImage.cols - 1);
for (int j = 0; j < nChannels; ++j)
{
output_left[j] = src_left[j];
output_right[j] = src_right[j];
}
}
return resultImage;
}
int main()
{
Mat srcImage = imread("flower.jpg");
if (!srcImage.data)
{
printf("could not load image...\n");
return -1;
}
imshow("srcImage", srcImage);
Mat srcGray;
cvtColor(srcImage, srcGray, CV_BGR2GRAY);
imshow("srcGray", srcGray);
Mat reultImage1 = Myfilter2D(srcImage);//原图掩膜的结果
Mat reultImage2 = Myfilter2D(srcGray);//灰度图掩膜的结果
imshow("res1", reultImage1);
imshow("res2", reultImage2);
waitKey(0);
return 0;
}
原图与效果图: