CV_Assert(srcImg.depth() == CV_8U);
Mat.ptr
获取当前行指针: const uchar* current = srcImg.ptr
获取当前像素点P(row, col) 的像素值 :p(row, col) = current[col];
像素范围处理函数: saturate_cast
这个函数的功能就是确保图像的RGB值范围在0~255之间。
所谓掩膜其实就是一个矩阵,然后根据这个矩阵重新计算图片中像素的值。
掩膜主要有以下用途:
提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。
屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。
结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。
特殊形状图像的制作。
0 | -1 | 0 |
-1 | 5 | -1 |
0 | -1 | 0 |
掩膜操作公式:
I(i,j)=5∗I(i,j)−[I(i−1,j)+I(i+1,j)+I(i,j−1)+I(i,j+1)]I(i,j)=5∗I(i,j)−[I(i−1,j)+I(i+1,j)+I(i,j−1)+I(i,j+1)]
#include
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat srcImg, dstImg;
srcImg = imread("test.jpg");
if (!srcImg.data)
{
cout << "could not load image..." << endl;
return -1;
}
namedWindow("Input image", CV_WINDOW_AUTOSIZE);
imshow("Input image", srcImg);
//【1】记录程序开始点timeStart
double timeStart = (double)getTickCount();//计算时间语句
//方法1:进行矩阵的掩膜操作
//*******************************************************************************************************************************************************//
//1).empty() 判断文件读取是否正确
//2).rows 获取图像行数(高度)
//3).cols 获取图像列数(长度)
//4).channels() 获取图像通道数
//5).depth() 获取图像位深度
int cols = (srcImg.cols - 1) * srcImg.channels(); //获取图像的列数,一定不要忘记图像的通道数
int offsetx = srcImg.channels();//图像的通道数 3
int rows = srcImg.rows;//220
dstImg = Mat::zeros(srcImg.size(), srcImg.type());//返回指定的大小和类型的数组, 创建一个跟src一样大小、类型的图像矩阵
for (int row = 1; row < (rows - 1); row++)
{
//Mat.ptr(int i=0) 获取像素矩阵的指针,索引i表示第几行,从0开始计行数。
//获得当前行指针const uchar* current= myImage.ptr(row );
//获取当前像素点P(row, col)的像素值 p(row, col) =current[col]
//Mat.ptr(row):获取第row行的图像像素指针。图像的行数从0开始计数
//获取点P(row, col)的像素值:P(row.col) = Mat.ptr(row)[col]
const uchar *previous = srcImg.ptr(row - 1);// 获取上一行指针
const uchar *current = srcImg.ptr(row); // 获取当前行的指针
const uchar *next = srcImg.ptr(row + 1); // 获取下一行的指针
uchar *output = dstImg.ptr(row);// 目标对象像素
for (int col = offsetx; col < cols; col++)
{
//像素范围处理saturate_cast
// 1. current[col-offsetx]是当前的像素点的左边那个像素点的位置,因为一个像素点有三个通道
// 2. current[col+offsetx]是当前的像素点的右边那个像素点的位置,因为一个像素点有三个通道
// 3. previous[col]表示当前像素点对应的上一行的那个像素点
// 4. next[col]表示当前像素点对应的下一行的那个像素点
output[col] = saturate_cast(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
}
}
//*******************************************************************************************************************************************************//
//方法2:OpenCV提高了函数filter2D来实现掩膜操作:
/********************************************************************************
Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//定义掩膜
//调用filter2D
filter2D(src, dst, src.depth(), kernel);
********************************************************************************/
double timeconsume = ((double)getTickCount() - timeStart) / getTickFrequency();
cout << "运行上面程序共耗时: " << timeconsume << endl;
//输出 掩膜操作后的图像
namedWindow("contrast image", CV_WINDOW_AUTOSIZE);
imshow("contrast image", dstImg);
imwrite("contrastImg.jpg", dstImg);
waitKey(1000);
//getchar();
return 0;
}
没有使用saturate_cast
我们可以看见掩膜操作后的图像对比度明显提高了,但是美中不足的是出现了一些不好的小斑点。这是因为这项像素点的值的范围不在0~255之间了
使用saturate_cast
而OpenCV使用函数filter2D来实现掩膜操作:
Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//定义掩膜
//调用filter2D
filter2D(srcImg, dstImg, srcImg.depth(), kernel);
Opencv的掩膜函数filter2D,非常简洁明了,易操作!!!