学习OpenCV范例(三)——矩阵的掩码操作

来源:互联网 发布:阿里云异地登录 编辑:程序博客网 时间:2024/05/01 05:24

矩阵的掩码操作在图形图像上面来说就是矩阵的卷积运算,使像素点与周围临近的像素点关联起来,可以进行中值滤波,均值滤波,锐化,等等功能,具体想达到怎样的一个功能效果,在OpenCV的其他函数中都有给出,也可以自己给定算子,得到属于自己的滤波器,下面就看看范例的介绍吧。

1、矩阵的掩码操作

矩阵的掩码操作很简单。其思想是:根据掩码矩阵(也称作核)重新计算图像中每个像素的值。掩码矩阵中的值表示近邻像素值(包括该像素自身的值)对新像素值有多大影响。从数学观点看,我们用自己设置的权值,对像素邻域内的值做了个加权平均。

2、测试用例

思考一下图像对比度增强的问题。我们可以对图像的每个像素应用下面的公式:

I(i,j) = 5*I(i,j) - [ I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]\iff I(i,j)*M, \text{where }M = \bordermatrix{ _i\backslash ^j  & -1 &  0 & +1 \cr                     -1 &  0 & -1 &  0 \cr                      0 & -1 &  5 & -1 \cr                     +1 &  0 & -1 &  0 \cr                 }

上面那种表达法是公式的形式,而下面那种是以掩码矩阵表示的紧凑形式。使用掩码矩阵的时候,我们先把矩阵中心的元素(上面的例子中是(0,0)位置的元素,也就是5)对齐到要计算的目标像素上,再把邻域像素值和相应的矩阵元素值的乘积加起来。虽然这两种形式是完全等价的,但在大矩阵情况下,下面的形式看起来会清楚得多。

现在,我们来看看实现掩码操作的两种方法。一种方法是用基本的像素访问方法,另一种方法是用 filter2D 函数。

3、函数实现

#include "stdafx.h"#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>using namespace std;using namespace cv;static void help(){cout << endl<<  "This program shows how to filter images with mask: the write it yourself and the"<< "filter2d way. " << endl<<  "Usage:"                                                                        << endl<< " [image_name -- default lena.jpg] [G -- grayscale] "        << endl << endl;}void Sharpen(const Mat& myImage,Mat& Result);int main( int argc, char* argv[]){help();const char* filename =  "Lena.jpg";Mat I, J, K;printf("GRAUSCAL OR COLOR? please enter G/C");char ch=getchar();if (ch=='G')I = imread( filename, CV_LOAD_IMAGE_GRAYSCALE);elseI = imread( filename, CV_LOAD_IMAGE_COLOR);printf("%s\n",filename);namedWindow("Input", WINDOW_AUTOSIZE);namedWindow("Output", WINDOW_AUTOSIZE);imshow("Input", I);double t = (double)getTickCount();Sharpen(I, J);//实现掩码操作t = ((double)getTickCount() - t)/getTickFrequency();cout << "Hand written function times passed in seconds: " << t << endl;imshow("Output", J);waitKey(0);Mat kern = (Mat_<char>(3,3) <<  0, -1,  0,-1,  5, -1,0, -1,  0);t = (double)getTickCount();filter2D(I, K, I.depth(), kern );//使用滤波器掩码函数t = ((double)getTickCount() - t)/getTickFrequency();cout << "Built-in filter2D time passed in seconds:      " << t << endl;imshow("Output", K);waitKey(0);return 0;}void Sharpen(const Mat& myImage,Mat& Result){CV_Assert(myImage.depth() == CV_8U);  // 只接受unchar类型图片//根据图像的通道数,我们有一个或多个子列。我们用指针在每一个通道上迭代,因此通道数就决定了需计算的元素总数。const int nChannels = myImage.channels();Result.create(myImage.size(),myImage.type());//创建了一个与输入有着相同大小和类型的输出图像。for(int j = 1 ; j < myImage.rows-1; ++j){const uchar* previous = myImage.ptr<uchar>(j - 1);//获取前一行的指针const uchar* current  = myImage.ptr<uchar>(j    );//获取当前行的指针const uchar* next     = myImage.ptr<uchar>(j + 1);//获取下一行的指针uchar* output = Result.ptr<uchar>(j);//输出为当前行的指针//对对应的通道数进行掩码操作for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i){*output++ = saturate_cast<uchar>(5*current[i]-current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);}}//在图像的边界上,我们未对其做任何掩码操作,所以都赋值为0Result.row(0).setTo(Scalar(0));Result.row(Result.rows-1).setTo(Scalar(0));Result.col(0).setTo(Scalar(0));Result.col(Result.cols-1).setTo(Scalar(0));}

4、运行结果

         

          图1、原图像                     图2、Sharpen图像                         图3、Filter2D图像

                            图4、运行时间对比

5、结论

在实现掩码操作的过程中,我们可以自己手动编写函数,也可以调用OpenCV提供的函数如Filter2D来实现,但从两者的运行时间上看,OpenCV提供的函数效率高一些,主要是OpenCV对提供的函数进行了优化。所以没有特殊的情况,直接调用提供的函数就可以啦。

6、使用的类和函数

CV_Assert:

功能:检查运行时的条件,如果条件不成立则抛出异常

结构:

CV_Assert(expr None)
None:检查的条件

filter2D:

功能:对一副图像进行卷积运算

结构:

void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT )
src:输入的图片

dst:输出和src一样的size和channel的图片

ddepth:原图像的深度,src.depth

kernel:卷积核,是一个单通道浮点型的矩阵,如果你想使用不同的核在不同的通道,那么可以使用函数Split()将通道分离,再逐个使用核运算

anchor:核的中心,默认在核的中点处

delta:不知

borderType:不知

这个函数实现的其实是相关运算,如果要进行卷积运算,则将利用flip()函数将卷积核反转一下再进行运算就行了,还有一些资料说卷积核大小不能大于11*11,这个我也不清楚,希望知道的大神们,可以给点意见,如果有错误的地方也希望大家改正过来。




0 0
原创粉丝点击