【OpenCV学习1】基本图像操作

一.加载,修改,保存图像

cv::Mat:创建一个矩阵头,用来保存图像

加载图像:

cv::imread
用于加载图像文件并转换为一个Mat对象

Mat src = imread("/home/yht/OpenCV/image/test5.png",1)

第一个参数表示图像地址与图像名,第二个参数表示加载图像类型,IMREAD_UNCHANGED(<0)加载原图
IMREAD_GRAYSCALE(0)加载成灰度图像
IMREAD_COLOR(>0)以RGB形式加载

显示图像:

cv::namedWindowcv::imshow)
namedWindow用于创建一个OpenCV窗口,由opencv自动创建与释放

namedWindow("origin",WINDOW_GUI_EXPANDED);
//前一个参数表示创建窗口名,
//后一个参数表示 显示的格式!

在这里插入图片描述

解释 参数
窗口大小可以改变 WINDOW_NORMAL
窗口大小自适应比列 WINDOW_FREERATIO
窗口大小保持比例 WINDOW_KEEPRATIO
显示色彩变成暗色 WINDOW_GUI_EXPANDED
窗口创建的时候会支持OpenGL WINDOW_OPENGL

cv::imshow:根据窗口名称显示图像到指定窗口上去
imshow函数前没有namedWindow函数则自动执行一个,
但是该函数默认创建窗口的参数为 WINDOW_AUTOSIZE

imshow("origin",src)
//第一个参数:窗口名,第二个参数:读取图像的变量名 

修改图像:

cv::cvtColor
将图像变换到不同的色彩空间

cvtColor(src , changed, CV_BGR2RGB)
//第一个参数:图像变量名(转换前)
//第二个参数:图像 变量名(转换后)
//第三个参数:变换色彩空间

常用色彩空间:
BGR
RGB
BGRA
RGBA
GRAY
XYZ (CIEXYZ)
YCrCb (luma-chroma(akaYCC))
HSV (hue saturation value)
Lab (CIELab)
Luv (CIELuv)
HLS (hue lightness saturation)
YUV

Python+OpenCV图像处理(四)-色彩空间

保存图像:

cv::imwrite

imwrite("/home/yht/OpenCV/image/test1_RGB2BGR.jpg",changed);

Mat类:

Mat类与Iplimage类

Mat对象OpenCV2.0之后引进的图像数据结构、自动分配内存、不存在内存泄漏的问题,是面向对象的数据结构。分了两个部分,头部与数据部分

IplImage是从2001年OpenCV发布之后就一直存在,是C语言风格的数据结构,需要开发者自己分配与管理内存,对大的程序使用它容易导致内存泄漏问题

Mat常用函数:

Mat::empty()
//判断矩阵是否为空

一般情况下Mat dst=src只会复制Mat对象的头和指针部分,要想实现数据拷贝,需使用以下函数:
Mat::clone()Mat::copyTo()//拷贝

dst=src.clone();   
src.copyTo(dst);
//通过clone或copyTo实现完全的数据拷贝

Mat::channels() //图像通道数
Mat::size() //图像尺寸
Mat::cols
Mat::rows //获取行列数
Mat::ptr<uchar>(i)//获取矩阵第(i)行行指针

Mat::type()
//图像的类型,它是一系列的预定义的常量(宏定义),
传入的参数的命名规则为
CV_(位数)+(数据类型)+(通道数)。
CV_<bit_depth>(S|U|F)C<number_of_channels>
具体的有以下值:

参数 C1 C2 C3 C4
CV_8U 0 8 16 24
CV_8S 1 9 17 25
CV_16U 2 10 18 26
CV_16S 3 11 19 27
CV_32S 4 12 20 28
CV_32F 5 13 21 29
CV_64F 6 14 22 30

其中:
bit_depth表示图像位深,位深越大,能存储的值越多,表示的颜色就越多

S= 符号整型U = 无符号整型F = 浮点型
U表示Unsigned无符号整数类型,即其内部元素的值不可以为负数,
S表示Signed有符号整数类型,其值存在负数,
F则表示浮点数类型,即矩阵的内部元素值可以为小数
(32对应单精度float类型,64对应双精度double类型);

之后的C1~C4表示对应的通道数,即有1至4个通道。
如果矩阵的type()是C2,是不能以图像形式显示出来的,因为图像没有双通道。
如:
CV_8UC1 是指一个8位无符号整型单通道矩阵类型,
CV_32FC2是指一个32位浮点型双通道矩阵类型
CV_8UC(n)是指一个8位无符号整型n通道矩阵类型,

由于以上这些都是定义为整型一些宏定义,因此单纯输出它们并没有实际的意义。

相较于Mat::type(),
Mat::depth()
则表示除去通道数(C1,C2,C3,…)的矩阵的每个单独通道的类型,
如src.type()=CV_8UC3,则src.depth()=CV_8U

cv::Scalar(double v0,double v1,double v2,double v3,) //赋值函数
v0~v3表示通道1~4的灰度值,如果是三通道则依次为BGR。

Mat常用构造函数:

Mat(int rows ,int cols, int type)
Mat(Size size, int type)
Mat(int rows, int cols, int type, const Scalar &s)
Mat::create( int rows, int cols, int type) //创建没有初始化

dst.create(100,100,src.type())

Mat::zeros(Size size, int type) //创建0阵,相当于Scalar(0,0,0)

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

Mat::ones(Size size, int type)
//相当于Scalar(1,0,0)每个像素的第一个通道为1,其余n-1个通道为0
Mat::eye( Size size, int type) //左上右下对角元素每个像素的第一个通道为1,其余为0
Mat c=(Mat::_<double>(3,3)<<0,-1,0,-1,5,-1,0,-1,0) //自定义核
Mat::convertTo(Mat InputArray, type) //图像type转换

二.图像基本操作:

三通道图像的存储方式:

矩阵的行数不变,每一列包含三个子列,分别存储RGB对应的灰度值,因此size便是[行,列×3]

获取图像像素指针:

行指针:
Mat.ptr<uchar>(i) //获取行指针,i表示第几行

uchar *current = src.ptr(row); 

之所以用uchar是因为图像的灰度值在0~255之间,用无符号字符型正好够用current[col]指向行指针的列,即像素点

像素范围处理:

saturate_cast<uchar>:saturate_cast<uchar>(n)
//若n<0,返回0
//若n大于255,返回255
//若n在0~255之间,返回它本身
//功能是确保像素灰度在0~255之间

像素指针:

灰度图像:(CV_8UC1):
img.at<uchar>(row,col)

img.at<uchar>(Point(x,y))
三通道图像:
img.at<Vec3b>(row,col)[i](i=0,1,2)
其中<>参数为Vec+通道+类型:
Vec3b //uchar
Vec3i //int
Vec3f //float

实例1 图像反差操作:
void My_bitwise_not(Mat &dst, int channel) //图像反差
{
    
    
 for(int row=0;row<dst.rows;row++)
 {
    
    
  for(int col=0;col<dst.cols;col++){
    
     
   int B = dst.at<Vec3b>(row,col)[0]; //三通道像素指针(RGB)
   int G = dst.at<Vec3b>(row,col)[1];
   int R = dst.at<Vec3b>(row,col)[2]; 
   
   dst.at<Vec3b>(row,col)[0]=255-B;
   dst.at<Vec3b>(row,col)[1]=255-G;
   dst.at<Vec3b>(row,col)[2]=255-R;
  }
 }
 imshow("My_SingleChannel",dst);
 waitKey(0);
}
 

在这里插入图片描述
以上代码可以通过调用OpenCV图像位操作函数CV::bitwise_not()实现:

bitwise_and()是对二进制数据进行“与”操作,
即对图像(灰度图像或彩色图像均可)每个像素值进行按位二进制“与”操作
同理:
bitwise_or()是对二进制数据进行“或”操作,
bitwise_xor是对二进制数据进行“异或”操作,
bitwise_not是对二进制数据进行“非”操作

实例2 图像伪单通道输出:
void My_SingleChannel(Mat &dst, int channel) //伪单通道(channel:B0,G1,R2)
{
    
    
	for(int row=0;row<dst.rows;row++)
	{
    
    
		for(int col=0;col<dst.cols;col++){
    
     
			int B = dst.at<Vec3b>(row,col)[0]; //三通道像素指针(RGB)
			int G = dst.at<Vec3b>(row,col)[1];
			int R = dst.at<Vec3b>(row,col)[2]; 
			
			for(int i=0;i<3;i++)  //除了输出通道外全部置0
				if(i!=channel) dst.at<Vec3b>(row,col)[i]= 0; 
		}
	}
	imshow("My_SingleChannel",dst);
	waitKey(0);
}
	

在这里插入图片描述

实例3 转伪灰度图像 :
void My_Gray(Mat &dst) //转伪灰度图像
{
    
    
	for(int row=0;row<dst.rows;row++)
	{
    
    
		for(int col=0;col<dst.cols;col++)
		{
    
     
			int B = dst.at<Vec3b>(row,col)[0]; //三通道像素指针(RGB)
			int G = dst.at<Vec3b>(row,col)[1];
			int R = dst.at<Vec3b>(row,col)[2]; 
			
			//int temp = max(B,max(G,R));  //取RGB中最大值
			int temp = min(B,min(G,R));  //取RGB中最小值
			dst.at<Vec3b>(row,col)[0]=temp; 
			dst.at<Vec3b>(row,col)[1]=temp;
			dst.at<Vec3b>(row,col)[2]=temp;
		}
	}
	imshow("My_Gray",dst);
	waitKey(0);
}

在这里插入图片描述

图像混合:

线性混合操作:
在这里插入图片描述
alpha的取值范围为0~1;
输出像素=两幅图像像素加权之和,总权值=1,保证输出范围不超过255;
宏观上体现为图像混合。
在这里插入图片描述代码实现:

void Pic_Mixed(Mat src1, Mat src2, double Weight, Mat& dst) //图像混合
{
    
    	
    dst = Mat::zeros(src1.size(), src1.type());	
    double beta = 1 - Weight;	
    //Show_Pic(src1);	
    //Show_Pic(src2);	
    if (src1.size == src2.size && src1.type() == src2.type()) {
    
    
        for (int row = 0;row < src1.rows;row++) {
    
    
            for (int col = 0;col < src1.cols;col++) {
    
    
                if (src1.channels() == 1) {
    
    
            	    int Gray1 = src1.at<uchar>(row, col); //单通道
            	    int Gray2 = src2.at<uchar>(row, col);
            	    dst.at<uchar>(row, col) = saturate_cast<uchar>(Gray1 * Weight + Gray2 * beta);				
            	}				
            	else if (src1.channels() == 3) {
    
    
            	    for (int i = 0;i < 3;i++) {
    
    
            	       int B_G_R_1 = src1.at<Vec3b>(row, col)[i]; //三通道像素指针(RGB)
                       int B_G_R_2 = src2.at<Vec3b>(row, col)[i];						
                       //核心代码:
                       dst.at<Vec3b>(row, col)[i] = saturate_cast<uchar>(B_G_R_1 * Weight + B_G_R_2 * beta);
                    }				
                }			
            }		
        }		
        addWeighted(src1, Weight, src2, 1 - Weight, 0.0, dst);//OPenCV API
        imshow("output", dst);		
        waitKey(0);	
    }	
    else cout << '\n' << "wrong size!!" << endl;
} 

opencv图像混合相关 API:
void cv::addWeighted(cv::InputArray src1, double alpha, cv::InputArray src2, double beta, double gamma, cv::OutputArray dst, int dtype = -1)

参数1:src1,第一个原数组.
参数2:alpha,第一个数组元素权重
参数3:src2第二个原数组
参数4:beta,第二个数组元素权重
参数5:gamma,图1与图2作和后补充添加的数值。
参数6:dst,输出图片

addWeighted(src1, 0.6, src2, 1-0.6, 0.0, dst); 

图像对比度调整(线性变换点操作)

在这里插入图片描述
输出=输入像素×权值

a>1:像素与像素间差值扩大,图像对比度增强
0<a<1:像素与像素间差值减小,图像对比度减弱

代码实现:

void Contrast(Mat src, Mat &dst, double Weight) //对比度调整(线性)
{
    
    
    dst = Mat::zeros(src.size(), src.type());
    //Show_Pic(src);
     for(int row=0;row<src.rows;row++){
    
    
         for(int col=0;col<src.cols;col++){
    
    
             if(src.channels()==1){
    
    
                 int Gray = src.at<uchar>(row,col); //单通道
                 dst.at<uchar>(row,col)=saturate_cast<uchar>(Gray*Weight);
             } 
             else if(src.channels()==3){
    
    
                 for(int i =0 ;i<3;i++){
    
    
                     int B_G_R = src.at<Vec3b>(row,col)[i]; //三通道像素指针(RGB)
                     //核心代码:
                     dst.at<Vec3b>(row,col)[i]=saturate_cast<uchar>(B_G_R*Weight-50);
                 }
             } 
         }
     }
     imshow("output",dst);
     waitKey(0);
}

在这里插入图片描述

绘制图形与文字:

CV::Point()
表示2D平面上的一个点坐标:

Point p;
p.x=a;
p.y=b;
//或:
Point p = Point(a,b); 

CV::Scalar()

Scalar color = Scalar (b,g,r)  //色彩
直线绘制:

cv::line()

函数原型:
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
参数声明:
· InputOutputArray img:输出图像
· Point pt1:线段的端点
· Point pt2:线段的第二端点
· const Scalar& color:直线颜色
· int thickness = 1:直线粗细程度
· int lineType :直线类型
包括:
LINE_4
LINE_8
LINE_AA
LINE_MAX
使用LINE_8 CPU不需要过多的计算,运行效率会高些
·int shift = 0:点坐标的小数点位数
在这里插入图片描述

矩形绘制

cv::rectangle()
函数原型:
void rectangle(CV_IN_OUT Mat& img, Rect rec, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
函数声明:
· CV_IN_OUT Mat& img:输出图像
· Rect rec: 矩形的位置和长宽
· const Scalar& color:矩形颜色
· int thickness = 1:线宽
·int lineType = LINE_8:直线类型
·shift:点坐标的小数点位数

椭圆绘制

cv::ellipse()
函数原型:
void ellipse(InputOutputArray img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
函数声明:
· img 图像
· center 椭圆心
· axes 椭圆x轴长度的一半,y轴长度的一半 (半长轴)
· angle 椭圆旋转角度
· startAngle 绘制的起始角度
· endAngle 绘制的终止角度
· color 椭圆颜色
· thickness 线宽
· linetype 线型
· shift 坐标小数点位数

圆形绘制:

cv::circle()

函数原型:
void circle(InputOutputArray img, Point center, int radius, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
函数声明:
·img 图像
· center 圆心
· radius 半径
· color 颜色
· thickness 线宽
·linetype 线型
· shift 坐标点的小数点位数

绘制填充多边形:

· void fillPoly(img,ppt,npt,1,Scalar color,lineType);
函数参数:
·img 图像
·ppt多边形的顶点集
·npt绘制的多边形顶点数目为
·要绘制的多边形数量为1
·color多边形的颜色

文字绘制:

cv::putText()

函数原型:
void putText(cv::InputOutputArray img, const cv::String &text, cv::Point org, int fontFace, double fontScale, cv::Scalar color, int thickness = 1, int lineType = 8, bool bottomLeftOrigin = false)
函数参数:
参数1:Mat& img,待写字的图片
参数2:,const string& text,待写入的文本
参数3: Point org, 第一个字符左下角坐标
参数4:int fontFace,字体类型
参数5:double fontScale,字体大小
参数6:Scalar color,字体颜色
参数7:int thickness,字体粗细,我们下面代码使用的是4号
参数8:int lineType,线型

OpenCV支持的文字字体包括以下几种:

Identifier
cv::FONT_HERSHEY_SIMPLEX
cv::FONT_HERSHEY_PLAIN
cv::FONT_HERSHEY_DUPLEX
cv::FONT_HERSHEY_COMPLEX
cv::FONT_HERSHEY_TRIPLEX
cv::FONT_HERSHEY_COMPLEX_SMALL
cv::FONT_HERSHEY_SCRIPT_SIMPLEX
cv::FONT_HERSHEY_SCRIPT_COMPLEX
OpenCV随机数

RNG可以产生3种随机数
RNG(int seed) 使用种子seed产生一个64位随机整数,默认-1
RNG::uniform( ) 产生一个均匀分布的随机数
RNG::gaussian( ) 产生一个高斯分布的随机数

RNG::uniform(a, b) 返回一个[a,b)范围的均匀分布的随机数,a,b的数据类型要一致,而且必须是int、float、double中的一种,默认是int。

RNG::gaussian( σ) 返回一个均值为0,标准差为σ的随机数。
如果要产生均值为λ,标准差为σ的随机数,可以λ+ RNG::gaussian( σ)

高斯分布可视化
在这里插入图片描述

图像绘制代码实现:

void MyShapeDraw(Mat &src, int param) //画图
{
    
    
    int x,y,z,w,h,A,B,C;Scalar color;
    Point p1,p2;
    Size s;
    Rect rect;
    
    switch(param){
    
    
        case 1:
            cout<<"输入端点1:\n";
            cin>>x>>y;
            p1=Point(x,y);
            cout<<"输入端点2:\n";
            cin>>x>>y;p2=Point(x,y);
            cout<<"输入色彩:\n";
            cin>>x>>y>>z;
            color=Scalar(x,y,z);
            line(src, p1,p2, color,1,LINE_8);
            break;
        case 2:
            cout<<"输入端点:\n";
            cin>>x>>y;
            cout<<"输入宽高:\n";
            cin>>w>>h;
            rect=Rect(x, y, w, h);
            cout<<"输入色彩:\n";
            cin>>x>>y>>z;
            color=Scalar(x,y,z);
            rectangle(src, rect ,color,1,LINE_8); 
            break; 
        case 3:
            cout<<"输入椭圆心:\n";
            cin>>x>>y;p1=Point(x,y);
            cout<<"输入半长轴x,y:\n";
            cin>>x>>y;
            s=Size(x,y);
            cout<<"输入旋转角和绘制起始角和终止角C,A,B:\n";
            cin>>C>>A>>B;cout<<"输入色彩:\n";
            cin>>x>>y>>z;color=Scalar(x,y,z);
            ellipse(src, p1, s,C,A,B,color,1,LINE_8); 
        case 4:
            cout<<"输入圆心\n";
            cin>>x>>y;p1= Point(x,y);
            cout<<"输出半径\n";
            cin>>C;
            cout<<"输入色彩:\n";
            cin>>x>>y>>z;
            color=Scalar(x,y,z);
            circle(src, p1, C, color, 1,LINE_8);
            break;
        case 5:
        {
    
    
            Point Pts[1][4];
            int WINDOW_SIZE=src.rows;
            Pts[0][0] = Point(10,20);
            Pts[0][1] = Point(20,30);
            Pts[0][2] = Point(30,90);
            Pts[0][3] = Point(90,160); 
            cout<<"输入色彩:\n";
            cin>>x>>y>>z;
            color=Scalar(x,y,z);
            const Point* ppt[1]={
    
    Pts[0]};
            int npt[]={
    
    4};
            fillPoly(src,ppt,npt,1,color,LINE_8);
            break;
        }
        case 6:
        {
    
     
            char Text[Maxsize];
            cout<<"输入文字\n";
            cin>>Text;
            cout<<"输入文字左端点:\n";
            cin>>x>>y;
            p1=Point(x,y);
            cout<<"输入色彩:\n";
            cin>>x>>y>>z;
            color=Scalar(x,y,z);
            putText(src, Text, p1,CV_FONT_HERSHEY_COMPLEX, 2.0, color, 2, LINE_AA);
            break;
        }
        case 7:
        {
    
    
            for(int i = 0;i<10000;i++){
    
    
                RNG rng(getTickCount());
                p1.x=(rng.uniform(0,src.cols));
                p2.x=(rng.uniform(0,src.cols));
                p1.y=(rng.uniform(0,src.rows));
                p2.y=(rng.uniform(0,src.rows)); color=Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));
                line(src, p1, p2, color, 1, LINE_8);
                //imshow("output",src);
                //waitKey(20);
                cout<<' '<<rng.gaussian(20);
            }
        } 
        case 8: //高斯分布
        {
    
    
            int Sigma;
            cout<<"输入标准差σ\n";
            cin>>Sigma;
            for(int i=0;i<100000;i++){
    
    
                if(src.channels()==1){
    
    
                    RNG rng(getTickCount());//单通道
                    int row = src.rows/2+rng.gaussian(Sigma);
                    int col = src.cols/2+rng.gaussian(Sigma);
                    src.at<uchar>(row,col)=rng.uniform(0,255);
                } 
                else if(src.channels()==3){
    
    
                    RNG rng(getTickCount());
                    int row = src.rows/2+rng.gaussian(Sigma);
                    int col = src.cols/2+rng.gaussian(Sigma);
                    for(int i =0;i<3;i++){
    
    
                        int B_G_R = src.at<Vec3b>(row,col)[i]; //三通道像素指针(RGB)
                        src.at<Vec3b>(row,col)[i]=rng.uniform(0,255);
                        imshow("Gaussian Distribution",src);
                        waitKey(1);
                    }
                } 
            }
        } 
    } 
}   

图像掩膜(mask)操作之实现图像对比度调整:

个人对掩膜操作的理解:通过一个掩膜矩阵,来重新计算图像中每一个像素的值,而掩膜矩阵就相当于一个权重表,向我们告知周围某些像素对当前像素的影响力度。
(感觉和卷积操作有点类似,掩膜矩阵相当于一个卷积核)

提升图像对比度的掩膜矩阵:
[[0,-1,0]
[-1,5,-1]
[0,-1,5]]
在这里插入图片描述

计算公式:

I (i , j)=5 * I (i , j) - [ I ( i-1 , j) + I (i+1 , j) + I (I , j-1) + I(i , j+1) ]
即:掩膜操作后中心像素值=5×掩膜操作前心像素值-相邻四边像素值

个人通俗的理解:如果周围像素点的灰度值总体高于(亮)中心像素点,则让中心像素点的灰度值再低一些(暗淡一些);如果周围像素点的灰度值总体低于(暗)中心像素点,则让中心像素点的灰度值再高一些(明亮一些);宏观上便是图像对比度提高。

代码实现:

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv; 

int main()
{
    
    
    Mat src, dst;
    src = imread("/home/yht/OpenCV/image/test1.jpg",1);
    
    if(!src.data){
    
     //和src.empty()差不多
        cout<<"not found!"<<endl;
        return -1;
    } 
    else{
    
    
        imshow("origin",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++){
    
     
        //从1开始的原因是保证3×3掩膜核不会超出图像边界 
        uchar *previous = src.ptr(row-1);//上一行指针
        uchar *current = src.ptr(row);//当前行指针
        uchar *next = src.ptr(row+1);//下一行指针
        uchar *output = dst.ptr(row); //指向新矩阵,存储结果 
        
        for(int col=offsetx;col<cols;col++){
    
     //列从3(除去第一列的RGB)开始,原因一样
            //output[col] = 5*current[col]-(current[col-offsetx]+current[col+offsetx]+previous[col]+next[col]); 
            //output[col]或current[col]表示当前行指针指向指定列,即当前像素点
            //添加saturate_cast<uchar>保证RGB范围在0~255之间:
            //掩膜操作公式代码实现:
            output[col] = saturate_cast<uchar>(5*current[col]-(current[col-offsetx]+current[col+offsetx]+previous[col]+next[col]));
            }
        } 
            
    //以上操作可以替换为:
    /*
    Mat kernel = (Mat_<char>(3,3)<<0,-1,0,-1,5,-1,0,-1,0); 
    //定义掩膜
    filter2D(src,dst,-1,kernel); 
    //直接调用cv::filter2D函数进行掩膜操作
    */ 
    imshow("output",dst); 
    waitKey(0);
}

实现效果:
在这里插入图片描述
事实上,我们可以调用OpenCV自带的API接口cv::filter2D函数实现掩膜操作:

Mat kernel = (Mat_<char>(3,3)<<0,-1,0,-1,5,-1,0,-1,0); //定义掩膜
filter2D(src,dst,src.depth(),kernel); //直接调用cv::filter2D函数进行掩膜操作

其中src是处理前矩阵,dst是处理后,都是Mat类变量。
src.depth表示位图深度,有32,24,8等(uchar就是8),若为空或-1则表示和输入图像一致

filter2D函数参数:

void filter2D
(
InputArray src,
OutputArray dst,
int depth,
InputArray kernel,
Point anchor=Point(-1,-1),
double delta=0,
int borderType=BORDER_DEFAULT
);

参数说明:(一般只写前5个参数)
InputArray src: 输入图像
OutputArray dst: 输出图像,和输入图像具有相同的尺寸和通道数量
int depth: 目标图像深度,如果没写将生成与原图像深度相同的图像。当depth输入值为-1时,目标图像和原图像深度保持一致。
InputArray kernel: 卷积核(或者是相关核),一个单通道浮点型矩阵。如果想在图像不同的通道使用不同的kernel,可以先将图像通道事先分开。
Point anchor: 内核的基准点(anchor),其默认值为(-1,-1)说明位于kernel的中心位置。基准点即kernel中与进行处理的像素点重合的点。
double delta: 在储存目标图像前可选的添加到像素的值,默认值为0int
borderType: 像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。

参考博客:OpenCV学习5:掩膜mask操作

本人还将掩膜操作的参数进行了更改,也发现了一些有趣的结果:

将中心矩阵5改为4时:中心像素点的灰度值便和中心与四周的差异有关,(呈现的是亮到暗转变的分界线),若想呈现暗到亮转变的分界线,只需对掩膜矩阵取反。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

学习记录blog,欢迎交流!若有理解不到位的地方,还望多多谅解

猜你喜欢

转载自blog.csdn.net/SESESssss/article/details/105620644