目录
- 一.加载,修改,保存图像
- 加载图像:
- 显示图像:
- 修改图像:
- 保存图像:
- Mat类:
- Mat类与Iplimage类
- Mat常用函数:
- Mat常用构造函数:
- 二.图像基本操作:
- 三通道图像的存储方式:
- 获取图像像素指针:
- 像素范围处理:
- 实例1 图像反差操作:
- 实例2 图像伪单通道输出:
- 实例3 转伪灰度图像 :
- 图像混合:
- 图像对比度调整(线性变换点操作)
- 绘制图形与文字:
- 直线绘制:
- 矩形绘制
- 椭圆绘制
- 圆形绘制:
- 绘制填充多边形:
- 文字绘制:
- OpenCV随机数
- 图像掩膜(mask)操作之实现图像对比度调整:
- 计算公式:
一.加载,修改,保存图像
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::namedWindow
与 cv::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个通道为0Mat::eye( Size size, int type)
//左上右下对角元素每个像素的第一个通道为1,其余为0Mat 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位随机整数,默认-1RNG::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
: 在储存目标图像前可选的添加到像素的值,默认值为0intborderType
: 像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。
本人还将掩膜操作的参数进行了更改,也发现了一些有趣的结果:
将中心矩阵5改为4时:中心像素点的灰度值便和中心与四周的差异有关,(呈现的是亮到暗转变的分界线),若想呈现暗到亮转变的分界线,只需对掩膜矩阵取反。
学习记录blog,欢迎交流!若有理解不到位的地方,还望多多谅解