(小白一只,刚刚步入视觉领域,因为导师的项目需要用c++,所以想通过博客记录我的学习历程,有不对之处请大神及时指正,千万不要留有情面【笑哭】)
前言
学习过冈萨雷斯的《数字图像处理》的小伙伴们对掩模的功能肯定了解,掩模其实就是一个奇数乘奇数(如3*3,5*5,7*7等)的一个窗口,我们将窗口滑过整幅图像,并同时进行乘加操作,便可得到新的图像,主要用于滤波或锐化等操作。
正题
如何用Opencv进行掩模操作
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat src, dst,dst1;//定义MAT头
src = imread("2.jpg");//读取图像
if (!src.data) {
cout << "Sorry,your arrys is error!" << endl;
return -1;
} //判断图片是否为空
namedWindow("Input Mat", CV_WINDOW_AUTOSIZE);
imshow("Dog", src);//显示图像
int channels_us = src.channels();//读取图像通道数
int rows = src.rows;//读取图像行数
int cols = (src.cols - 1)*channels_us;//读取图像列数,并乘以通道数
dst = Mat::zeros(src.size(), src.type());//初始化dst
double t0 = getTickCount();//定时
for (int row = 1; row < (rows-1); row++)//!!!重点
{
uchar* output = dst.ptr<uchar>(row);//指针读取图像行
const uchar* last = src.ptr<uchar>(row-1);
const uchar* current = src.ptr<uchar>(row);
const uchar* next = src.ptr<uchar>(row+1);
//掩模为:
/*
[ 0 -1 0
-1 5 -1
0 -1 0]
*/
for (int j = channels_us; j < cols; j++)
{
output[j] =saturate_cast<uchar> (5 * current[j] - (current[j - channels_us] + current[j + channels_us] + last[j] + next[j]));
}
}
t0 = (double)(getTickCount() - t0) / getTickFrequency();
imshow("output dog", dst);
cout << "自己写的函数所用时间为:" << t0<<"s" << endl;
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
double t1 = getTickCount();
filter2D(src, dst1, src.depth(), kernel);
t1 = (double)(getTickCount() - t1) / getTickFrequency();
cout << "Opencv自带的的函数所用时间为:" << t1 << "s" << endl;
imshow("output2 dog", dst1);
waitKey(0);
}
1,自己写程序
注意事项:
(1),用指针访问像素,很快,还可以用迭代器,经测试用指针比较方便并比较容易理解。
(2),dst在进行赋值前需进行初始化操作
dst = Mat::zeros(src.size(), src.type());//初始化dst
(3),掩模进行乘加操作后需将数据进行转化,用saturate_cast<uchar>()
这个函数功能是:saturate_cast<uchar>(x),若x大于uchar的最大值,即255,则返回255;若x小于uchar的最小值,即0,则返回0。
(4),掩模操作时,需要注意行和列的最大值和最小值(可以去查掩模处理像素的工作原理),即没有进行边缘操作。
2,采用Opencv自带的filter2D函数,程序如上
注意事项:
(1),需提前定义一个核,即[0,-1,0;-1,5,-1;0,-1,0];
(2),图像深度,与原函数一致即可。
(3),Opencv中,核不会进行180°的旋转,单一般的滤波的核都是对称的,若不对称,则需要考虑180°旋转。
(4),filter2D是边缘拷贝,通过边缘拷贝补全矩阵进行计算。
3,运行时间比较
差不多处理时间是三倍多,不过opencv的函数已经优化了很多年很多代,建议今后直接用filter2D函数。
若有错误请及时指正!