1.3 像素指针、像素范围、掩膜操作
像素指针、确保值、filter2D()
1.3.1 获取图像像素指针
CV_Assert(myImage.depth() == CV_8U);
Mat.ptr(int i=0); 获取第0个像素的指针pointers,索引i表示第几行,从0开始计行数。(指针指向一个地址,uchar是一个字节,指针类型是uchar)
const uchar* current= myImage.ptr(row); 获得当前行指针(const常数)
p(row, col) =current[col]; 获取当前像素点P(row, col)的像素值 (row行 column列)
dst(destination)表目的; src(source)表源。
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); //定义输出图像的像素指针
在程序编写中,对于数组和指针等,要特别地小心。因为对于空指针以及数组越界等问题,编译器无法在编译时给出错误提示。
1.3.2 像素范围处理
saturate_cast(); 这个函数的功能是确保RGB值得范围在0~255之间。(saturate使饱和 cast计算,加)
saturate_cast(-100);小于0则返回0
saturate_cast(288);大于255则返回255
saturate_cast(100);0~255则返回原值100
output[col] = saturate_cast(5 * current[col] - (previous[col] + next[col] + current[col - offsetx] + current[col + offsetx]));
//saturate_cast();像素范围处理:小于0则返回0、大于255则返回255、0-255则返回原值
1.3.3 矩阵的掩膜操作
掩膜(mask):用选定的图像、图形或物体,对处理的图像(全部或局部)进行遮挡,来控制图像处理的区域或处理过程。数字图像处理中,掩模为二维矩阵数组,有时也用多值图像,图像掩模主要用于:
①提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。
②屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。
③结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。
④特殊形状图像的制作。
掩膜是一种图像滤镜的模板,实用掩膜经常处理的是遥感图像。当提取道路或者河流,或者房屋时,通过一个n*n的矩阵来对图像进行像素过滤,然后将我们需要的地物或者标志突出显示出来。这个矩阵就是一种掩膜。
矩阵的掩膜:根据掩码矩阵(也称作核)重新计算图像中每个像素的值。掩码矩阵中的值表示近邻像素值(包括该像素自身的值)对新像素值有多大影响。从数学观点看,我们用自己设置的权值,对像素邻域内的值做了个加权平均。
目的:是提高图像对比度。
锐化算子:红色是中心像素5。从上到下,从左到右对每个像素做同样的掩膜处理操作,得到最终结果就是对比度提高之后的输出图像Mat对象。
对比度:图像整体的明暗对比。
锐度:图像边缘像素的对比度。锐化处理的主要目的是突出灰度的过渡部分,补偿轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰。图像的模糊可以通过积分来实现(均值处理与积分类似)。而图像锐化,则需要微分来实现。
清晰度:图像局部像素的对比度+分辨率。
掩膜操作计算方法:
output[col] = 5 * current[col] - (previous[col] + next[col] + current[col - offsetx] + current[col + offsetx]);//掩膜操作的新像素值=某像素值*系数 - 其上下相邻行和左右相邻通道的像素值(RGB是3个通道 )
卷积实现:
int cols = (src.cols-1) * src.channels(); //宽度,RGB有3个通道,每一列还有3个子int offsetx = src.channels(); //开始的列像素,通道函数int rows = src.rows; //高度dst = Mat::zeros(src.size(), src.type()); //dst初始化,构造一个大小和类型跟输入src的一致的对象//从上到下从左到右对每个像素做同样的掩膜处理操作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] - (previous[col] + next[col] + current[col - offsetx] + current[col + offsetx])); //掩膜操作的新像素值=某像素值*系数-其上下相邻行和左右相邻通道的像素值//saturate_cast();像素范围处理:小于0则返回0、大于255则返回255、0-255则返回原值 }
}
初始化一个Mat的对象:
Mat::zeros(size, type);构造一个全是0的矩阵,全黑背景的空白图像,RGB全是0就是黑色,RGB全是255就是纯白。
dst = Mat::zeros(src.size(), src.type()); //dst初始化,构造一个大小和类型跟输入src的一致的对
1.3.4 函数filter2D做掩膜
可直接用opencv的API做掩膜操作来提高对比度。
Mat kernel = (Mat_(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); 定义掩膜/算子/模板/卷积核
filter2D( src, dst, src.depth(), kernel ); 其中src与dst是Mat类型变量,src.depth表示位图深度,有32、24、8等,直接写-1表示与输入图深度一致。(filter滤波器)
//可直接用opencv的API做掩膜操作double t = getTickCount();
Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//定义小数组filter2D(src, dst, src.depth(), kernel); //掩膜,src.depth表示位图深度double timeconsume = (getTickCount() - t) / getTickFrequency(); //计算程序执行时间printf("time consume %.2f", timeconsume);
完整程序:
/*1.3 矩阵掩膜操作*/
#include#include#includeusing namespace cv;
int main(int argc, char** argv) {
Mat src, dst; //图像对象Mat src = imread("E:/OpenCV/testimage/test.jpg");
if (!src.data) {
printf("could not load image...\n");
//cout << "could not load image...\n" << end1; //不可用 return -1;
}
namedWindow("input_image", CV_WINDOW_AUTOSIZE);
imshow("input_image", src);
int cols = (src.cols-1) * src.channels(); //宽度,RGB有3个通道,每一列还有3个子 int offsetx = src.channels(); //开始的列像素,通道函数 int rows = src.rows; //高度 dst = Mat::zeros(src.size(), src.type()); //dst初始化,构造一个大小和类型跟输入src的一致的对象 //从上到下从左到右对每个像素做同样的掩膜处理操作 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] - (previous[col] + next[col] + current[col - offsetx] + current[col + offsetx])); //掩膜操作的新像素值=某像素值*系数-其上下相邻行和左右相邻通道的像素值 } //saturate_cast();像素范围处理:小于0则返回0、大于255则返回255、0-255则返回原值 }
/* //可直接用opencv的API做掩膜操作double t = getTickCount();Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//定义掩膜filter2D(src, dst, src.depth(), kernel); //src.depth表示位图深度double timeconsume = (getTickCount() - t) / getTickFrequency(); //计算程序执行时间printf("time consume %.2f", timeconsume);*/
namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE);
imshow("contrast image demo", dst);
waitKey(0);
return 0;
}