vs中opencv如何实现掩膜_OpenCV图像处理之矩阵的掩膜操作

3.矩阵的掩膜操作

OpenCV中的C++类和函数都是定义在命名空间cv之内的,有两种方法可以访问。第一种是,在代码开头的适当位置,加上using namespace cv;这句。

另外一种是在使用OpenCV类和函数时,都加入cv::命名空间。不过这种情况难免会不爽,每用一个OpenCV的类或者函数,都要多敲四下键盘写出cv::,很麻烦。

所以,浅墨推崇大家在代码开头的适当位置,加上using namespace cv;这句。于是和opencv命名空间一了百了了。

改回来就好了,运行结果如下:

知识补充:掩膜操作提高图像的对比度。

一个图像的通道数是N,就表明每个像素点处有N个数,一个a×b的N通道图像,其图像矩阵实际上是b行N×a列的数字矩阵。所以要知道图像矩阵的实际的行列,cols(列数)=图像的cols*通道数,行数rows是一样的图像的rows。

OpenCV中图像的通道可以是1、2、3和4。其中常见的是1通道和3通道,2通道和4通道不常见。

1通道的是灰度图。

3通道的是彩色图像,比如RGB图像。

4通道的图像是RGBA,是RGB加上一个A通道,也叫alpha通道,表示透明度。PNG图像是一种典型的4通道图像。alpha通道可以赋值0到1,或者0到255,表示透明到不透明。

2通道的图像是RGB555和RGB565。2通道图在程序处理中会用到,如傅里叶变换,可能会用到,一个通道为实数,一个通道为虚数,主要是编程方便。RGB555是16位的,2个字节,5+6+5,第一字节的前5位是R,后三位+第二字节是G,第二字节后5位是B,可见对原图像进行压缩了。

框和图像左上角对齐,图像矩阵从(0,0)开始记,最左上角是(0,0),所以中心点一开始坐标是(1,1)。所以row是从1开始,到rows-1结束的,同理col应该也是,肯定到不了最后一个,这里对应的框都是对应图像像素点的,不是图像矩阵,所以是提前在cols中先将图像的cols-1并不是直接在图像矩阵cols上减一,那么对应的图像矩阵的col初始值并非对应图像cols为1,图像矩阵的cols是0,没意义。而是当图像的cols为2,此时图像矩阵的cols是通道值。我们就可以把这个特殊值设出来为offsetx。

中间像素点和左边像素点对应的图像矩阵列数相差应该是通道数,例如3通道相当于左边那个大座位可以坐三个人,行数图像矩阵和图像像素行数是一样的。

一般我们是不会在原图上做修改的,所以用const 来对current进行设定,const是一个C++语言的限定符,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。在此处是用了它修饰指针的功能,

如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;

如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。

因此,推荐使用int const* p,而不是使用const int* p(虽然两者意义完全一样),这样更容易理解。(const其他的功能见https://www.cnblogs.com/chogen/p/4574118.html)

由于设定的current设定是const,因为不可以修改,故在原图像不能输出。

所以我们设一个和src一样大的矩阵元素全是零dst且类型一致,利用指针将算出的像素放到dst中来输出掩膜后的图。

程序:

#include

#include

#include

using namespace cv;

int main(int argc, char** argv ) {

Mat src, dst;

src = imread("F:/VisualStudio2015/Opencvlearning/test2/test2/timg.jpg");

if (!src.data)

{

printf("could not load image...\n");

return -1;

}

namedWindow("input image", CV_WINDOW_AUTOSIZE);

imshow("input image", src);

int cols = (src.cols-1) *src.channels();

int offsetx = src.channels();

int rows = src.rows;

dst = Mat::zeros(src.size(), src.type());

for (int row = 1; row < (rows - 1); row++) {

const uchar*previous = src.ptr(row - 1);

const uchar*current = src.ptr(row);

const uchar*next = src.ptr(row + 1);

uchar*output=dst.ptr(row);

for (int col =offsetx ; col < cols; col++) {

output[col] = 5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]);

}

}

namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE);

imshow("contrast image demo", dst);

waitKey(0);

return 0;

}

会发现图像边缘很不好,似乎因为像素值放进去被截取了,我们利用函数使所有像素值在0-255之间。uchar表示无符号数取值范围即0-255。

输出就是对比度提高后的图片,效果很好。

程序:

#include

#include

#include

using namespace cv;

int main(int argc, char** argv ) {

Mat src, dst;

src = imread("F:/VisualStudio2015/Opencvlearning/test2/test2/timg.jpg");

if (!src.data)

{

printf("could not load image...\n");

return -1;

}

namedWindow("input image", CV_WINDOW_AUTOSIZE);

imshow("input image", src);

int cols = (src.cols-1) *src.channels();

int offsetx = src.channels();

int rows = src.rows;

dst = Mat::zeros(src.size(), src.type());

for (int row = 1; row < (rows - 1); row++) {

const uchar*previous = src.ptr(row - 1);

const uchar*current = src.ptr(row);

const uchar*next = src.ptr(row + 1);

uchar*output=dst.ptr(row);

for (int col =offsetx ; col < cols; col++) {

output[col] =saturate_cast( 5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));

}

}

namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE);

imshow("contrast image demo", dst);

waitKey(0);

return 0;

}

其实opencv带有他的API函数可以实现上述功能

结果图输出是一样的。

*其中filter2D中的第三个参数表示输出的位图深度,例子中填scr.depth()表示和原图的位图深度一样,在你不知道是多少时,也可以选择填-1,就是暗示输出的位图深度和原图像相同,两个都可以,效果一样。当然你也可以选择与原图的位图深度不一样,只是很容易出错。故一般就是-1或src.depth(),其中src是原图代号不同例子不同。

小知识:

getTickcount函数:它返回从操作系统启动到当前所经的计时周期数。 getTickFrequency函数:返回每秒的计时周期数。

getTickCount用来获取我们程序的执行时间的,可以知道此处的API程序执行时间用多久。

第一步获取一开始的执行时间,然后执行了API指令后,用新的执行时间减去一开始的执行时间t,再除以一个当量即getTickFrequency(),就可以表示时间用了多少。再打印出来输出。程序如下:

可以知道那两句API的执行用了0.02秒。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值