OpenCV学习(三):矩阵的掩模的操作
上一篇介绍了OpenCV中imread,cvtColor,imshow,imwrite的使用,这一篇打算介绍Mat的像素指针,以及掩模操作。
像素指针
对图像操作,基本都是对图像的每个像素操作,在OpenCV中Mat.ptr<uchar>(int i=0)
可以获取像素的指针,i表示第i行,从第0列开始操作。
这样获取当前行的像素指针const uchar* current = myImage.ptr<uchar>( row )
,那么获取像素点P(row, col)的像素值p(row, col) = current[col]
eg:
Mat inMat = imread("1.png");
uchar u = inMat.ptr<uchar>(0)[0];
上面先载入一张图片到inMat中,然后从inMat中获取第1行第1列的像素并赋给uchar类型的u。
掩模操作
知道了获取图像的像素方法,接下来就可以对图像进行掩模操作,从而提高图片的对比度。
接下来就根据上面图片的公式,来实现图片像素的操作。
Mat inMat = imread("1.png");
if (!inMat.data) { //判断图像是否读取成功
cout << "图像读取失败" << endl;
return;
}
imshow("原图像", inMat);
int channel = inMat.channels(); //获取图像的通道数
int row = inMat.rows;
int col = inMat.cols;
Mat outMat = Mat(inMat.size(), inMat.type());
for (int i = 1; i < row-1; i++) {
for (int j = channel; j < (col-1)*channel; j++) {
outMat.ptr<uchar>(i)[j] = 5 * inMat.ptr<uchar>(i)[j]-
(inMat.ptr<uchar>(i - 1)[j] +
inMat.ptr<uchar>(i + 1)[j] +
inMat.ptr<uchar>(i)[j-channel] +
inMat.ptr<uchar>(i)[j+channel]);
}
}
imshow("掩模之后的图像", outMat);
}
注意:
< 1 >我们在显示图片的时候,可以不用调用namedwindow
来创建窗口,可以直接调用imshow
,来创建并显示窗口图像。
< 2 >像素计算操作时,不能直接从原点(0, 0)到最大点(col, row)来计算计算像素值,否则计算就会超过范围 。
< 3 >在对列进行操作时,别忘了图像的通道值。
运行结果
可以看见掩模之后的图片失真很严重,这是因为我们像素计算之后的值可能为负数或者超过了范围。
此时我们可以用到一个函数saturate_cast< uchar >,当计算的值为负数,或者很大时,可以使我们计算的像素值保证在0~255之间。
更改之后的代码如下
outMat.ptr<uchar>(i)[j] = saturate_cast<uchar>(5 * inMat.ptr<uchar>(i)[j]-
(inMat.ptr<uchar>(i - 1)[j] +
inMat.ptr<uchar>(i + 1)[j] +
inMat.ptr<uchar>(i)[j-channel] +
inMat.ptr<uchar>(i)[j+channel]));
此时运行的结果如下:
可以看见结果好多了
filter2D
对于上面的代码显然是最原始的像素计算方式,此时我们可以使用filter2D达到最简洁的像素计算方式。
< 1 >定义掩模
Mat kernel = (Mat_< char >(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
< 2 >调用filter2D
filter2D(inMat, outMat, inMat.depth(), kernel);
(1)参数一:输入的图像
(2)参数二:输出的图像
(3)参数三:输出的图像深度,一般和输入图像的深度一样,也可以直接填-1,和前面一样
此时附上完整代码
void test4(){
Mat inMat = imread("1.png");
if (!inMat.data) { //判断图像是否读取成功
cout << "图像读取失败" << endl;
return;
}
imshow("原图像", inMat);
int channel = inMat.channels(); //获取图像的通道数
int row = inMat.rows;
int col = inMat.cols;
Mat outMat = Mat(inMat.size(), inMat.type());
for (int i = 1; i < row-1; i++) {
for (int j = channel; j < (col-1)*channel; j++) {
outMat.ptr<uchar>(i)[j] = saturate_cast<uchar>(5 * inMat.ptr<uchar>(i)[j]-
(inMat.ptr<uchar>(i - 1)[j] +
inMat.ptr<uchar>(i + 1)[j] +
inMat.ptr<uchar>(i)[j-channel] +
inMat.ptr<uchar>(i)[j+channel]));
}
}
imshow("掩模之后的图像", outMat);
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(inMat, outMat, inMat.depth(), kernel);
imshow("filter2D变化之后的图像", outMat);
}
运行结果:
可以看见,filter2D和前面的计算结果显示的样子基本一样。
上一篇: HTML/CSS实现的搜索框