掩膜定义:
首先我们从物理的角度来看看mask到底是什么过程。
在半导体制造中,许多芯片工艺步骤采用光刻技术,用于这些步骤的图形“底片”称为掩膜(也称作“掩模”),其作用是:在硅片上选定的区域中对一个不透明的图形模板遮盖,继而下面的腐蚀或扩散将只影响选定的区域以外的区域。
用选定的图像、图形或物体,对处理的图像(全部或局部)进行遮挡,来控制图像处理的区域或处理过程。用于覆盖的特定图像或物体称为掩模或模板。光学图像处理中,掩模可以足胶片、滤光片等。
掩膜用处
数字图像处理中,掩模为二维矩阵数组,有时也用多值图像。数字图像处理中,图像掩模主要用于:
- 提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。
- 屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。
- 结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。
- 特殊形状图像的制作。
掩膜是一种图像滤镜的模板,实用掩膜经常处理的是遥感图像。当提取道路或者河流,或者房屋时,通过一个n*n的矩阵来对图像进行像素过滤,然后将我们需要的地物或者标志突出显示出来。这个矩阵就是一种掩膜。
在OpenCV中,掩模操作是相对简单的。大致的意思是,通过一个掩模矩阵,重新计算图像中的每一个像素值。掩模矩阵控制了旧图像当前位置以及周围位置像素对新图像当前位置像素值的影响力度。用数学术语讲,即我们自定义一个权重表。
掩膜运算的一个小实例
以图和掩膜的与运算为例:
原图中的每个像素和掩膜中的每个对应像素进行与运算。比如1 & 1 = 1;1 & 0 = 0;
比如一个3 * 3的图像与3 * 3的掩膜进行运算,得到的结果图像就是:
如果用一句话总结,掩膜就是两幅图像之间进行的各种位运算操作。
掩膜操作实现图像对比度调整
通过掩膜操作实现图像对比度提高。
I(i,j) = 5*I(i,j) - [I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]
红色是中心像素,从上到下,从左到右对每个像素做同样的处理操作,得到最终结果就是对比度提高之后的输出图像Mat对象。
filter2D功能
- filter2D 函数的定义如下:
void filter2D(
InputArray src, //处理的原图,Mat类型变量
OutputArray dst, //处理后的输出图像,Mat类型变量
int ddepth, //ddepth表示位图深度,有32、24、8等
InputArray kernel,//掩膜模板
Point anchor=Point(-1,-1),
double delta=0,
int borderType=BORDER_DEFAULT
);
测量程序运行时间;
有的时候,想知道要我们的程序一共运行了多长时间,这个很常用,也很简单,仅仅需要两个函数即可。
opencv里使用getTickCount()与getTickFrequency()函数记录时间;
-
函数解释:
-
GetTickCount:
它返回从操作系统启动到当前所经过的毫秒数,常常用来判断某个方法执行的时间,其函数原型是DWORD GetTickCount(void),返回值以32位的双字类型DWORD存储,因此可以存储的最大值是(2^32-1) ms约为49.71天,因此若系统运行时间超过49.71天时,这个数就会归0C++版 DWORD k=::GetTickCount(); //获取毫秒级数目 int se = k/1000; // se为秒 cout<<se<<endl; 库文件:kernel32.dll C/C++头文件:winbase.h windows程序设计中可以使用头文件windows.h
-
getTickFrequency()函数:返回CPU的频率,即每秒cpu的滴答数。
#include <opencv2\opencv.hpp> using namespace cv; using namespace std; int main() { //1 记录程序开始运行点 timeStart double timeStart = (double)getTickCount(); //2 此部分为需要测试运行时间的程序 int a = 0; while (a < 50000000) { a++; } //3 记录程序消耗的总时间timeConsume double timeEnd = (double)getTickCount(); double frequency = getTickFrequency(); double timeConsume = (timeEnd - timeStart) / frequency; cout << "运行上面程序共耗时:" << timeConsume << "秒\n" << endl; // 运行上面程序共耗时:0.086982秒 system("pause"); return 0; }
-
掩膜实例:
#include"opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int main() {
//1).empty() 判断文件读取是否正确
//2).rows 获取图像行数(高度)
//3).cols 获取图像列数(长度)
//4).channels() 获取图像通道数
//5).depth() 获取图像位深度
Mat img, dst,dst2;
img = imread("D:/111.jpg", 1);
if (!img.data) {
cerr << "open file error" << endl;
return -1;
}
namedWindow("previous_picture", WINDOW_AUTOSIZE);
imshow("previous_picture", img);
int rows = img.rows;
int offsetX = img.channels(); //图像的通道数
int cols = (img.cols - 1)*img.channels();//获取图像的列数,一定不要忘记图像的通道数
//返回指定的大小和类型的数组 创建一个跟img一样大小 ,类型的图像矩阵
dst = Mat::zeros(img.size(), img.type());
for (int row = 1; row < rows - 1; row++) {
//Mat.ptr<uchar>(int i=0) 获取像素矩阵的指针,索引i表示第几行,从0开始计行数。
//获得当前行指针const uchar* current= img.ptr<uchar>(row );
//获取当前像素点P(row, col)的像素值 p(row, col) =current[col]
//Mat.ptr<uchar>(row):获取第row行的图像像素指针。图像的行数从0开始计数
//获取点P(row, col)的像素值:P(row.col) = Mat.ptr<uchar>(row)[col]
//获取上一行的指针
const uchar* X_previous = img.ptr<uchar>(row - 1);
//获取当前行的指针
const uchar* X = img.ptr<uchar>(row);
//获取下一行的指针
const uchar* X_next = img.ptr<uchar>(row + 1);
//获取待处理图片的当前行的指针
uchar* output = dst.ptr<uchar>(row);
//开始锁定对应行的某一列,找到某个确定的元素
for (int col = offsetX; col < cols; col++) {
//对待处理图片当前行的第col列进行像素处理
//像素范围处理saturate_cast<uchar>
//X[col-offsetx]是当前的像素点的左边那个像素点的位置,因为一个像素点有三个通道
//X[col+offsetx]是当前的像素点的右边那个像素点的位置,因为一个像素点有三个通道
//X_previous[col]表示当前像素点对应的上一行的那个像素点
//X_next[col]表示当前像素点对应的下一行的那个像素点
output[col] = saturate_cast<uchar>(5 * X[col] - (X[col - offsetX] + X[col + offsetX] + X_previous[col] + X_next[col]));
}
}
namedWindow("new_picture1", WINDOW_AUTOSIZE);
imshow("new_picture1", dst);
//opencv提供的方法:
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(img, dst2, img.depth(), kernel);
namedWindow("new_picture2", WINDOW_AUTOSIZE);
imshow("new_picture2", dst2);
waitKey(0);
return 0;
}