说明

这篇博客只用来记录目前我已经接触过的API,只涉及用法及效果,不涉及背后算法,具体算法我会在其他的博客中进行介绍。随着逐渐学习,我也会对这篇博客进行动态更新,有些内容缺少的就是我也还没弄懂的。

并不会详细解释API,更适合有一定经验的人查阅。

我也只是个初学者,很多内容都是跟着教程的框架进行学习,如果内容上有错误欢迎大家指正与补充。


基础操作

读入

图片

imread()函数

Mat imread( const String& filename, int flags = IMREAD_COLOR );

第一个参数是图片路径

第二个参数是读入色彩模式

常用的模式:

IMREAD_UNCHANGED 按图片原色彩模式读入

IMREAD_GRAYSCALE 按灰度图读入

IMREAD_COLOR 按BGR彩色读入

样例代码

Mat demo;
demo = imread("F://opencv file/picture.jpg" , IMREAD_UNCHANGED);

视频或摄像头

VideoCapture类

使用样例

VideoCapture cap;
cap.open(0); // cap.open("F:\\opencv file/测试视频.mp4");
//以上等价于 VideoCaputure cap(0);
Mat demo;
while(1){
cap>>demo
imshow("demo",demo);
waitKey(30);
}

先创建一个VideoCapture通过open可以打开摄像头或者视频,摄像头的话是使用摄像头的index号,笔记本摄像头默认为0。视频是使用路径。

然后用>>读入到Mat中进行处理,循环输出。

VideoCapture还有一些常用的方法。

cap.get(CV_CAP_PROP_FRAME_WIDTH) //帧宽度
cap.get(CV_CAP_PROP_FRAME_HEIGHT) //帧高度
cap.get(CV_CAP_PROP_FPS);  //帧率 x frames/s
cap.get(CV_CAP_PROP_FRAME_COUNT); //总帧数

输出

图片

imwrite()函数

imwrite( const String& filename, InputArray img,const std::vector<int>& params = std::vector<int>());

第一个参数是输出的文件路径

第二个参数是要输出的图片

视频

VideoWriter类

这部分我还没倒腾明白,之后用到的时候再补齐

颜色

Scalar对象与函数

样例代码

Scalar color = Scalar(255,255,255)  //设置色彩为白色

随机数(随机色彩)

RNG类

样例代码

RNG rng((unsigned)time(NULL));   //声明时需要设定一个种子,一般会设置为当前时间,可以保证每次的种子都不同。
int i = rng.uniform(0,255) //uniform(a,b),可以生成[a,b)之间的随机数,返回值与输入的范围值相同,也可以用强制转换得到多种数据类型

像素范围处理

saturate_cast()函数

用于使数值不超过数据类型允许范围

样例代码

uchar r = saturate_cast<uchar>(400)       //返回255
uchar r = saturate_cast<uchar>(-100) //返回0
uchar r = saturate_cast<uchar>(100)      //返回100

色彩转换

cvtColor()函数

void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是转换模式

常用的有:

CV_BGR2GRAY //BGR转灰度

CV_BGR2HSV //BGR转HSV

样例代码

cvtColor(demo,demo,CV_BGR2GRAY);  //从BGR彩色图转换为灰度图

形态学操作、直方图、边缘检测等API需要输入单通道的图,就可以将彩色图转换为单通道的灰度图,也可以选择将不同的通道分为不同的图像。

通道分离

将多通道的彩色图像,分为多个单通道的图。

split()函数

void split(const Mat& src, Mat* mvbegin)

第一个参数是输入Mat对象地址

第二个参数是分通道输出的Mat对象数组

样例代码

Mat dst[3];          //声明Mat对象数组
split(demo,dst);    //将demo对象的三个通道分别赋给dst数组

要注意分离后的图像都是单通道,直接显示都是灰度图。

通道合并

将多个单通道图像合并为一个多通道的图像

merge()函数

函数原型

void merge(InputArrayOfArrays mv, OutputArray dst);

第一个参数是输入的多个单通道矩阵/图像的阵列,必须有相同深度和尺寸

第二个参数是合并后的矩阵/图像,通道数需要与参数一中的个数一致

样例代码

vector<Mat> channels;  //用于储存分离后的通道
split(image_src, channels);     //分离通道
merge(channels, image_dst);     //合并通道

该函数是上边split()的逆操作,参数也类似。

图像线性混合

addWeighted()函数

函数原型

void addWeighted(InputArray src1, double alpha, InputArray src2,double beta, double gamma, OutputArray dst, int dtype = -1);

第一个参数是输入图像1

第二个参数是图像1所占的比例

第三个参数是输入图像2

第四个参数是图像2所占的比例

第五个参数是偏差值,用0就可以

第六个参数是输出图像

样例代码

addWeighted(image1, 0.4 , image2 , 0.6 , 0 , image_out);

图像线性运算

cvConvertScale()函数

函数原型

cvConvertScale( const CvArr* src, CvArr* dst, double scale ,double shift  );

第一个参数是输入矩阵

第二个参数是输出矩阵

第三个参数是乘数因子

第四个参数是加权值

最后结果是输入矩阵中的每个元素 乘以乘数加上加权值 得到输出矩阵

cvConvertScaleAbs()函数

参数与上边的API一致,区别是这个API输出时会取绝对值。

归一化

normalize()函数

函数原型

void normalize(InputArray src, InputOutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() )

第一个参数是输入数组/图像

第二个参数是输出数组/图像

第三个参数是用来规范值或者规范范围,并且是下限。

第四个参数是用来规范范围并且是上限 只对NORM_MINMAX有效

第五个参数是归一化的模式

归一到(min,max)范围内:NORM_MINMAX 最小值为0,最大值为1,其他数根据比例计算

根据切比雪夫距离归一:NORM_INF 最大值为1,其他数除以最大值

根据曼哈顿距离归一:NORM_L1 每个数除以所有数和(绝对值)

根据欧几里得距离归一:NORM_L2 每个数除以所有数平方和的开方

样例代码

vector<double>demo = {10,17,20};
normalize(demo,demo, 1 , 255 ,NORM_L1);

画线与图形

线

line()函数

函数原型

void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,int thickness = 1, int lineType = LINE_8, int shift = 0);

第一个参数是输入的图像

第二个参数是线段起始点

第三个参数是线段结束点

第四个参数是线段颜色

第五个参数是线段宽度

第六个参数是线形

样例代码

line(image , Point(50,50) , Point(100,100) , Scalar(255,0,0) , 3 , LINE_8);

矩形

rectangle()函数

函数原型

rectangle(InputOutputArray img, Point pt1, Point pt2,const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);

与上边划线类似,第一个点是矩形左上角,第二个点是矩形右下角

样例代码

rectangle(image , Point(50,50) , Point(100,100) , Scalar(255,0,0) , 3 , LINE_8);

圆形

circle()函数

函数原型

void circle(InputOutputArray img, Point center, int radius, const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0);

第一个参数是输入图像

第二个参数是圆心坐标

第三个参数是半径

第四个参数是颜色

第五个参数是线宽

第六个参数是线形

样例代码

circle(image, Point(50,50) , 20 , Scalar(255,0,0) , 2 , LINE_8);

椭圆

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);

第一个参数是输入图像

第二个参数是椭圆中心点

第三个参数是椭圆的大小(姑且可以认为是可以框住椭圆的矩形尺寸,可以以此确定椭圆的长轴与短轴长度)

第四个参数是椭圆沿逆时针方向旋转的角度

第五、六个参数分别是椭圆开始的角度以及结束的角度(用于画带缺口的椭圆线,角度沿长轴顺时针方向)

第七个参数是颜色

第八个参数是线宽

第九个参数是线形

样例代码

ellipse(image , Point(100,100) , Size(30,60) , 30 , 0 , 180 , Scalar(255,0,0) , 2 , LINE_8);

多边形或折线

polylines()函数

支持一次性画多个多边形

函数原型

void polylines(Mat& img, const Point* const* pts, const int* npts,int ncontours, bool isClosed, const Scalar& color,int thickness = 1, int lineType = LINE_8, int shift = 0 );

第一个参数是画布图像

第二个参数是顶点数组,由于该函数支持同时画多个多边形,所以顶点数组是二维数组,且要将每个数组的头地址再装进一个一维数组中,这里的参数只用最后的一维数组

第三个参数是顶点数量,也是为了画多个图形,所以需要用数组的形式储存顶点数量

第四个参数是多边形的数量

第五个参数是折线是否闭合,真或假

后边的就是颜色、线型之类的了

样例代码

Point points[2][3];
points[0][0] = Point(50,50);
points[0][1] = Point(20,50);
points[0][2] = Point(30,40);
points[1][0] = Point(60,50);
points[1][1] = Point(50,80);
points[1][2] = Point(40,30);
const Point* ptr[]={points[0] , points[1]};
int npts[] = {3,3};
polylines(image , ptr , npts , 2 , ture , Scalar(255,0,0) , 2, LINE_8);

fillPoly()函数

该函数参数与polylines基本一致,区别是该函数是实心多边形,polylines只是边框

函数原型

fillPoly(Mat& img, const Point** pts,const int* npts, int ncontours,const Scalar& color, int lineType = LINE_8, int shift = 0, Point offset = Point() );

和上边很相似,基本只需要五个参数,输入图像,顶点数组,顶点数量,图形数量,填充颜色

文字

putText()函数

函数原型

void putText( InputOutputArray img, const String& text, Point org, int fontFace, double fontScale, Scalar color,
int thickness = 1, int lineType = LINE_8,bool bottomLeftOrigin = false );

第一个参数是输入图像

第二个参数是要输出的字符串

第三个参数是文本框左下角的坐标

第四个参数是字体

第五个参数是尺寸

第六个参数是颜色

样例代码

putText(image , "Hello world" , Point(50,50) , FONT_HERSHEY_COMPLEX , 2 , Scalar(255,0,0));

点操作

  1. at方法

样例代码

uchar value = image.at<uchar>(i,j);   //获得单通道图像i行j列像素点的值
image.at<uchar>(i,j) = 255;  //单通道图像赋值操作
uchar value = image.at<Vec3b>(i,j)[0];   //取出三通道图像i行j列像素点的第一个通道数值。
Vec3b pixel = image.at<Vec3b>(i,j);  //将三通道图像i行j列像素点数组赋给pixel

需要注意对遍历多通道图像时使用像素点数组进行操作时,列数为像素点的列数(及图像列数)。直接获取单通道数值进行操作时,列数为像素点的列数*通道数

at函数可读性高,但效率不高,不适合用来遍历图像。

  1. ptr方法

样例代码

const uchar* date_in = image_in.ptr<uchar>(i);    //获取图像第i行像素值的指针,设置为常量是为了保证原图不变,保留副本。
uchar* date_out = image_out.ptr<uchar>(i);
date_out[j] = date_in[j];  //复制像素

需要特别注意,这里是将一行的数据装进数组,也就意味着对于通道的图,一行数据一共有图像列数*通道数个。如果要对单一通道进行操作,遍历时每次应该向下移动通道数个数据。

以这种方法遍历,效率更高。

遍历时,单点像素乘以常数可以调整对比度,加减常数可以调整亮度。

卷积操作

卷积核

想要进行卷积运算需要先定义一个卷积核。

Mat kernel = (Mat_<uchar>(3,3) << 0,1,0,1,-4,1,0,1,0);

上式创建的掩膜为:

0 1 0
1 -4 1
0 1 0

该卷积核可以用来提高对比度。又被成为拉普拉斯算子

sobel算子,可以用于检测边缘
检测横向边缘:

-1 0 1
-2 0 2
-1 0 1

检测纵向边缘

-1 -2 -1
0 0 0
1 2 1

卷积

filter2D()函数

函数原型

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

第一个参数是输入图像

第二个参数是输出图像

第三个参数是图像深度, -1 代表与输入图像一致

第四个参数是卷积核

第五个参数是锚点

样例代码

filter2D(image_in,image_out,-1,kernel);  //使用kernel为卷积核输出image_out

模糊

均值模糊/均值滤波

blur()函数

函数原型

void blur( InputArray src, OutputArray dst,Size ksize, Point anchor = Point(-1,-1),int borderType = BORDER_DEFAULT );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是均值模糊卷积核的大小,全方向模糊一般取3*3或5*5,也可以去单列或者单行的大小以进行单方向的模糊。要注意这个尺寸要确保有中心点存在。(2*2就不存在绝对的中心点)

第四个参数是锚点,默认位卷积核中心

第五个是边缘处理模式,一般用默认

样例代码

blur(image_in , image_out , Size(3,3));

均值模糊无法保留边缘特征,只能整体模糊。

中值模糊/中值滤波

medianBlur()函数

函数原型

void medianBlur( InputArray src, OutputArray dst, int ksize );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是卷积核的大小,固定是正方形,所以只取数字就可以,9就代表9*9的范围

样例代码

medianBlur(image_in , image_out , 3);

中值滤波很适合去除椒盐噪声。

高斯模糊/高斯滤波

高斯

GaussianBlur()函数

函数原型

void GaussianBlur( InputArray src, OutputArray dst, Size ksize,double sigmaX, double sigmaY = 0,int borderType = BORDER_DEFAULT );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是卷积核的大小

第四个参数是x方向上的标准偏差

第五个参数是y方向上的标准偏差

第六个参数是边缘处理模式

样例代码

GaussianBlur(image_in , image_out , Size(3,3) , 0.5 , 0.5);

这种高斯模糊相较于均值模糊可以保留更多细节,但对边缘的保留一样效果不太好。

双边高斯

bilateralFilter()函数

函数原型

void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace,int borderType = BORDER_DEFAULT );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是过滤器的大小,太大的话会影响速度

第四个参数是色彩空间的sigma,大一点可以提高模糊效果

第五个参数是坐标空间的sigma,小一点可以提高边缘保留效果

样例代码

bilateralFilter(image_in , image_out , 5 , 150 , 3);

模糊效果不错,而且可以保留边缘,对人脸处理时,有类似于磨皮的效果。


形态学操作

结构体

getStructuringElement()函数

函数原型

Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));

第一个参数是结构体的形状

预设的形状有:MORPH_RECT 矩形 MORPH_CROSS 十字 MORPH_ELLIPSE 椭圆形

第二个参数是结构体的大小

第三个参数是锚点位置

样例代码

Mat kernel = getStructuringElement(MORPH_RECT , Size(3,3));

运算

morphologyEx()函数

函数原型

void morphologyEx( InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1,int borderType = BORDER_CONSTANT,const Scalar& borderValue = morphologyDefaultBorderValue() );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是操作模式

操作模式有:

膨胀:MORPH_DILATE 锚点处像素值取结构体覆盖下的最大值 扩大亮处

腐蚀:MORPH_ERODE 锚点处像素值取结构体覆盖下的最小值 扩大暗处

开运算:MORPH_OPEN 先腐蚀再膨胀 去掉小亮斑

闭运算: MORPH_CLOSE 先膨胀再腐蚀 去掉小暗斑

顶帽: MORPH_TOPHAT 原图像与开运算后的结果求差 可以观察开运算去除了哪些物体

黑帽: MORPH_BLACKHAT 原图像与闭运算后的结果求差 可以观察闭运算的效果

形态学梯度:MORPH_GRADIENT 膨胀后的图减去腐蚀后的图 可以得到图像大致的边缘

第四个参数是结构体

检测直线/字符

通过合理设置结构体,再经过开运算就可以检测直线或者字符

检测水平直线,就设置单行较长的结构体

检测竖直直线,就设置单列较长的结构体

检测较粗字符,可以设置正方形的结构体


阈值

阈值操作

threshold()函数

函数原型

threshold( InputArray src, OutputArray dst,double thresh, double maxval, int type );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是阈值

第四个参数是最大值

第五个参数是操作模式

操作模式有:

二值化:THRESH_BINARY 大于阈值为最大,小于阈值为0

反二值化: THRESH_BINARY_INV 大于阈值为0,小于阈值为最大

截断: THRESH_TRUNC 大于阈值的限制为阈值,小于阈值的保持不变

取零: THRESH_TOZERO 大于阈值的不变,小于阈值的为0

反取零: THRESH_TOZERO_INV 大于阈值的为0,小于阈值的不变

最大类间方差: THRESH_OTSU 通过统计学计算阈值,常用于分离物体与背景

自适应阈值: THRESH_TRIANGLE 根据不同区域自行计算阈值,更多时候用另一个API实现

样例代码

threshold(image_in , image_out , 150 , 255 , THRESH_TOZERO);

adaptiveThreshold()函数

自适应阈值操作

函数原型

void adaptiveThreshold( InputArray src, OutputArray dst,double maxValue, int adaptiveMethod,int thresholdType, int blockSize, double C );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是最大值

第四个参数是自适应类型

平均值:ADAPTIVE_THRESH_MEAN_C 邻域像素平均值减去C作为阈值

高斯值:ADAPTIVE_THRESH_GAUSSIAN_C 邻域像素通过高斯加权平均减去C,sigma值取决与邻域大小

第五个参数是阈值操作模式,只能是THRESH_BINARY或者THRESH_BINARY_INV

第六个参数是计算阈值的邻域大小,3,5,7之类的

第七个参数是偏差值,可以设为0

样例代码

adaptiveThreshold(image_in , image_out , 255 , ADAPTIVE_THRESH_MEAN_C , THRESH_BINARY , 3 , 0);

合理的设置阈值可以分离物体与背景,也可以用于获得物体的大致边缘。

边缘检测

Canny()函数

函数原型

void Canny( InputArray image, OutputArray edges,double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false );

第一个参数是输入图像

第二个参数是输出图像

第三个参数是阈值1 低于这个阈值的点被认为不是边缘

第四个参数是阈值2 高于这个阈值的点被认为是边缘, 处于1与2之间的点会检测是否与边缘点接触,若接触则为边缘点

第五个参数是邻域范围

第六个参数是 是否使用更加精确的计算方法

样例代码

Canny(image_in , image_out , 100 , 200 , 3 , ture);

使用Canny前,要先进行滤波,提高效果


霍夫变换

直线

HoughLinesP()函数

函数原型

void HoughLinesP( InputArray image, OutputArray lines,double rho, double theta, int threshold,double minLineLength = 0, double maxLineGap = 0 );

第一个参数是输入图像

第二个参数是输出的直线两个端点坐标

第三个参数是极坐标中像素的扫描步长

第四个参数是极坐标中角度的扫描步长,一般取 CV_PI/180 也就是一度

第五个参数是阈值,极坐标系中至少要多少个函数相交才会看作直线

第六个参数是直线的最小长度

第七个参数是直线延伸过程中最大的间隔

样例代码

vector<Vec4f> plines ; //设置一个向量用于存放输出
HoughLinesP(image_in , plines , 1 , CV_PI/180 , 20 , 50 , 5);
for (size_t i = 0; i < plines.size(); i++)    //划出直线{Vec4f point = plines[i];    //取出第i个直线的端点数据,四个数据依次为,x0,y0,x1,y1line(image_out, Point(point[0], point[1]), Point(point[2], point[3]), Scalar(255, 255, 0), 2, LINE_AA);}

要先进行Canny边缘检测再进行霍夫直线检测

HoughCircles()函数

函数原型

void HoughCircles( InputArray image, OutputArray circles,int method, double dp, double minDist, double param1 = 100, double param2 = 100,int minRadius = 0, int maxRadius = 0 );

第一个参数是输入图像

第二个参数是输出数据

第三个参数是检测方法,只有CV_HOUGH_GRADIENT

第四个参数设为1

第五个参数是两个圆心之间的最小距离

第六个参数是Canny检测时的高阈值,低阈值默认为高阈值的一半

第七个参数是圆心的阈值,在极坐标系中至少多少个函数的交点会被认为是圆心

第八个参数是圆的最小半径

第九个参数是圆的最大半径

样例代码

vector<Vec3f> pcircles;        //设置一个向量存储输出数据
HoughCircles(image_in , pcircles , CV_HOUGH_GRADIENT , 1 , 100 , 120 , 50 , 100 , 200);
for (size_t i = 0; i < pcircles.size(); i++)  //画出所有的圆,输出的数据中三个数据依次为x0,y0,r
{Vec3f circles = pcircles[i];
circle(dst,Point(circles[0],circles[1]),circles[2],Scalar(0,0,255),1,LINE_AA);}

霍夫圆很容易受到椒盐噪声的影响,最好先进行中值滤波


直方图

直方图计算

calcHist()函数

函数原型

void calcHist( const Mat* images, int nimages,const int* channels, InputArray mask,SparseMat& hist, int dims,const int* histSize, const float** ranges,bool uniform = true, bool accumulate = false );

第一个参数是输入的图像数组,也可以是单一图像的指针

第二个参数是图像的个数

第三个参数是通道数的地址,需要计算的通道的下标,可以传入一个数组,如果是单通道就是只有0的数组。

第四个参数是掩膜,如果有的话就是只计算掩膜上非零位置,不使用的话可以输cv::Mat()

第五个参数是输出的直方图数据

第六个参数是直方图的维度,一般来说取1

第七个参数是每一维上直方图个数的指针,一般来说越大直方图越精细

第八个参数是要统计的灰度范围,用一维float数组装入最小值与最大值,再装入一个常量float指针数组。

第九个参数是是否归一化,默认开启

样例代码

int channels = 0;   //设置通道数
float range[] = {0,256};   //将最小值与最大值存入一维float数组
const float* histrange[] = {range};    //将一维数组装入常量float指针数组
int hist_size = 200;   //一共200个直方图
calcHist(image_in , 1 , &channels , Mat() , hist , 1 , &hist_size , histrange); //将直方图数据存入hist
normalize(hist , hist , 0 , image_out.rows , NORM_MINMIX);//进行归一化
double bin_w = (double)image_out.rows/hist_size;
for (int i = 1; i < hist_size; i++)
{line(image_out , Point((i-1)*bin_w , image_out.rows - cvRound(hist.at<float>(i-1))) , Point(i*bin_w , image_out.rows - cvRound(hist.at<float>(i))) , Scalar(255,0,0) , 2 , LINE_AA);
} //cvRound是四舍五入取整

计算出直方图后要对结果数组进行进行归一化,然后循环画出直方图。

直方图对比

compareHist()函数

函数原型

double compareHist( InputArray H1, InputArray H2, int method );

第一个参数是输入直方图1

第二个参数是输入直方图2

第三个参数是对比模式

对比模式有:

相关性比较:CV_COMP_CORREL 概率论中的相关系数,绝对值为1时两图相同,为0时完全不相关

卡方比较: CV_COMP_CHISQR 返回值为0时两图相同,为1时两图无关

十字比较:CV_COMP_INTERSECT 取每个位置两者的最小值累加,不是很好用

巴氏距离:CV_COMP_BHATTACHARYYA 两图相同时为1,不相关时为0,相对而言效果最好

样例代码

double compare_12 = compareHist(hist_1 , hist_2 , CV_COMP_BHATTACHARYYA);

直方图对图像灰度比较敏感,要做比较时,最好先将图像转到HVS空间再进行直方图计算,最后进行比较。HSV图像计算直方图时,需要计算的通道为第一和第二通道。

直方图均衡化

equalizeHist()函数

函数原型

void equalizeHist( InputArray src, OutputArray dst );

第一个参数是输入图像,需要是单通道

第二个参数是输出图像

样例代码

equalizeHist(image_in , image_out);

直方图均衡化可以提高不同光照下的图像效果,使画面呈现出更多细节,增强后续处理的效果。

直方图反向映射

函数原型

calcBackProject( const Mat* images, int nimages,const int* channels, const SparseMat& hist, OutputArray backProject, const float** ranges,double scale = 1, bool uniform = true );

第一个参数是图像的地址

第二个参数是图像个数

第三个参数是通道的角标数组

第四个参数是直方图

第五个参数是输出图像

第六个参数是计算范围,与直方图计算里的那个一样

样例代码

int hist_size = 180;    //直方图个数
float range[] = { 0 , 180 };   //统计范围,这里使用的是HSV图像,所以是0-180
const float* ranges[] = { range };
int channels[2] = { 0,1 }; //统计HSV图像的前两个通道
calcHist(&image_hsv, 1, channels, Mat(), image_hist, 1 , &hist_size, ranges);   //计算出直方图
calcBackProject(&image_hsv, 1, channels, image_hist, hist_back, ranges);    直方图反向映射

直方图匹配

matchTemplate()函数

函数原型

void matchTemplate( InputArray image, InputArray templ,OutputArray result, int method, InputArray mask = noArray() );

第一个参数是待检测图像

第二个参数是用来检测的图像

第三个参数是输出图像

第四个参数是匹配模式

匹配模式有:
平方差匹配法:TM_SQDIFF

归一化平方差匹配法:TM_SQDIFF_NORMED //这两个最佳匹配结果在0处

相关匹配法:TM_CCORR

归一化相关匹配法:TM_CCORR_NORMED //这两个最佳匹配结果在最大处

系数匹配法:TM_CCOEFF

归一化相关系数匹配法:TM_CCOEFF_NORMED //这两个最佳匹配结果在1,最差在-1,0为不相关

通常会使用归一化的匹配模式

样例代码

matchTemplate(image_src, temp, temp_out, TM_CCOEFF_NORMED);  //在image_src上寻找与temp图像匹配的部分,并把计算结果输出到temp_out中
normalize(temp_out,temp_out, -1, 1, NORM_MINMAX); //对输出的匹配结果进行归一化
double MinVal = 0, MaxVal = 0;    //用于存储匹配结果中的最大最小值
Point MinLoc(0, 0), MaxLoc(0, 0);   //用于存储匹配结果中最大值与最小值的坐标
minMaxLoc(temp_out, &MinVal, &MaxVal, &MinLoc, &MaxLoc);        //寻找最值坐标
circle(image_src, Point(MaxLoc.x + temp.cols / 2, MaxLoc.y + temp.rows / 2), 30, Scalar(0, 0, 255), 2, 8);    //在原图上的最佳匹配点处画上圆,要注意如果是用平方差匹配要在最小值处画。

轮廓

轮廓发现

findContours()函数

函数原型

void findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode,int method, Point offset = Point());

第一个参数是输入的图像,需要是完成Canny边缘检查的图像

第二个参数是输出的轮廓,包含多个轮廓,每个轮廓又包含很多的点,所以一般用vector<vector(Point)>类型的数据进行储存

第三个参数是拓扑信息,里边存储了每个轮廓与其他轮廓的拓扑关系,后一个轮廓 前一个轮廓 父轮廓 内嵌轮廓,一共四个相关轮廓的索引编号,所以一般用vector<Vec4i>进行储存,拓扑信息与每个轮廓一一对应

第四个参数是轮廓检索模式

轮廓检索模式有:

只检测最外围轮廓: CV_RETR_EXTERNAL 内部轮廓被忽略

检测所有的轮廓: CV_RETR_LIST 检测所有轮廓但检测到的轮廓不建立等级关系,相互独立。所以不存在父轮廓和内嵌轮廓。拓扑信息的第三、四位默认为-1

检测所有的轮廓且建立两个等级关系:CV_RETR_CCOMP 不同轮廓间外围为顶层,如果内围轮廓内部也包括其他轮廓,则它也被视作顶层。

检测所有的轮廓且建立等级树: CV_RETR_TREE 会根据轮廓的关系建立等级树,外围包括内围,内围也可包括其他轮廓。

第五个参数是轮廓的呈现方法

呈现方法有:

获取每个轮廓的每个像素:CV_CHAIN_APPROX_NONE 将相互之间距离不超过1的点全部相连

只取轮廓的拐点像素:CV_CHAIN_APPROX_SIMPLE 对信息进行了压缩

teh-Chinl chain 近似算法:CV_CHAIN_APPROX_TC89_L1

CV_CHAIN_APPROX_TC89_KCOS

轮廓绘制

drawContours()函数

函数原型

void drawContours( InputOutputArray image, InputArrayOfArrays contours,int contourIdx, const Scalar& color, int thickness = 1, int lineType = LINE_8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point() );

第一个参数是绘制的图像

第二个参数是输入的轮廓信息

第三个参数是轮廓的索引号

第七个参数是拓扑信息

第八个参数是最大层数,0代表只绘制当前 ,1代表绘制当前以及内嵌

第九个参数是每个点的偏移量,一般不设置

样例代码

cvtColor(image_src, image_gray, CV_BGR2GRAY);
Canny(image_gray, image_canny, 40, 140);
Mat image_out(image_canny.size(),CV_8UC3);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(image_canny, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
for(size_t i = 0; i < contours.size();i++)
{
drawContours(image_out,contours,i,Scalar(255,0,0),1,LINE_AA,hierarchy);
}
imshow("image_out", image_out);

凸包

convexHull()函数

函数原型

void convexHull( InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true );

第一个参数是输入的轮廓数据

第二个参数是输出的凸包数据,数据类型与轮廓数据一样 vector<vector<Point>>

第三个参数是检测的方向,默认为逆时针

第四个参数是操作标识符,一般不用设置

样例代码

vector<vector<Point>> contours ; //用于存储轮廓数据
vector<Vec4i> hierarchy;  //用于存储轮廓的拓扑信息
findContours(image_canny, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_TC89_KCOS);    //发现轮廓
vector<vector<Point>>   convex(contours.size());    //用于存储凸包信息
for (size_t i = 0; i < contours.size(); i++)
{
convexHull(contours[i], convex[i]);     //检测凸包
}
for(size_t i = 0; i < contours.size();i++)
{
drawContours(image_out,convex,i,Scalar(0,0,0),2 , LINE_AA );    //绘制凸包
}
imshow("image_out", image_out);

绘制矩形/椭圆框

压缩点集

approxPolyDP()函数

函数原型

void approxPolyDP( InputArray curve, OutputArray approxCurve,double epsilon, bool closed );

第一个参数是输入点集,一般是轮廓数据

第二个参数是压缩后的点集

第三个参数是压缩精度,代表压缩后曲线与原曲线的最大距离

第四个参数是是否闭合,true是闭合

获得矩形

无角度

boundingRect()函数

函数原型

Rect boundingRect( InputArray points );

参数为点集

返回值为Rect,所以一般用vector<Rect>进行储存

倾斜

minAreaRect()函数

函数原型

RotatedRect minAreaRect( InputArray points );

参数为点集

返回值为RotateRect,包含矩形的四个顶点。一般用vector<RotateRect>进行储存。

需要注意,这个函数对输入点集的个数有要求,至少要有四个点以上。

获得圆

圆形

minEnclosingCircle()函数

函数原型

void minEnclosingCircle( InputArray points, CV_OUT Point2f& center, CV_OUT float& radius );

第一个参数是输入点集

第二个参数是圆心集合

第三个参数是半径集合

椭圆

fitEllipse()函数

函数原型

RotatedRect fitEllipse( InputArray points );

参数是输入点集

返回值与旋转矩形一致,需要注意这个函数的输入点集至少要有六个点,使用时需要进行判断。

样例代码

 //拟合vector<vector<Point>> approx(contours.size());      //存储压缩后的点集
vector<Rect> rect(contours.size());           //存储拟合的无角度矩形
vector<RotatedRect>   rotate(contours.size());        //存储拟合的有角度矩形
vector<RotatedRect>  elipse_(contours.size());        //存储拟合的椭圆
vector<Point2f> css(contours.size());     //存储拟合圆的圆心
vector<float> rad(contours.size());           //存储拟合圆的半径
for(int i=0 ; i<contours.size() ; i++)        //遍历每一个轮廓点集
{approxPolyDP(contours[i], approx[i], 3 , true);        //压缩点集rect[i] = boundingRect(approx[i]);       //拟合无角度矩形rotate[i] = minAreaRect(approx[i]);       //拟合有角度矩形minEnclosingCircle(approx[i], css[i], rad[i]);     //拟合圆if (approx[i].size() > 5) {         //确保点集中至少六个点elipse_[i] = fitEllipse(approx[i]);        //拟合椭圆}}//绘制Point2f rotate_point[4];        //用于取用拟合有角度矩形的四个顶点数据
for (int i = 0; i < approx.size(); i++)       //遍历每个轮廓进行绘制
{rotate[i].points(rotate_point);        //将顶点数据存入rotate_pointrectangle(image_src, rect[i], Scalar(0, 0, 0), 3, LINE_AA);            //绘制无角度矩形circle(image_src, css[i], rad[i], Scalar(100, 0, 100));            //绘制圆ellipse(image_src, elipse_[i], Scalar(0, 100, 100));       //绘制椭圆for (int k = 0; k < 4; k++){line(image_src, rotate_point[k], rotate_point[(k+1)%4],Scalar(0,0,255));       //使用四个顶点数据绘制旋转矩形,(k+1)%4是为了使矩形闭合且不超出边界}}

图像矩以及轮廓面积/长度计算

图像矩

moments()函数与类

通过轮廓数据计算中心距,可以用来拟合轮廓质心

函数原型

Moments moments( InputArray array, bool binaryImage = false );

第一个参数是输入的轮廓数据

第二个参数是是否进行二值化,如果选true,灰度图中非零点均会被看作1

返回值的数据类型为Moments类,一般用vector<Moments>进行储存。

轮廓面积

contourArea()函数

通过轮廓数据计算轮廓面积

函数原型

double contourArea( InputArray contour, bool oriented = false );

第一个参数是输入的轮廓数据

轮廓长度

arcLength()函数

函数原型

double arcLength( InputArray curve, bool closed );

第一个参数是输入的轮廓数据

第二个参数是指定轮廓是否闭合

样例代码

vector<Moments> moment(contours.size());   //用于存储图像矩
vector<Point2f> points(contours.size());  //用于存储拟合的质心for(size_t i = 0; i < contours.size();i++)
{ drawContours(image_out, contours, i, Scalar(0, 0, 0), 2, LINE_AA);        //绘制轮廓moment[i] = moments(contours[i]);    //根据轮廓计算图像矩contourArea(contours[i]);        //根据轮廓计算面积//拟合质心,质心的x为图像矩的m10/m00,y为图像矩的m01/m00,static_cast是为了保证数据类型为floatpoints[i] = Point(static_cast<float>(moment[i].m10 / moment[i].m00), static_cast<float>(moment[i].m01 / moment[i].m00));  circle(image_out, points[i], 2, Scalar(255, 255, 0), 2);        //绘制质心cout << "轮廓" << i << "的面积为" << contourArea(contours[i]) << endl << "长度为" << arcLength(contours[i],true)<<endl;      //输出面积以及轮廓长度
}
imshow("image_out", image_out);

点多边形检测

用于检测点与封闭轮廓的位置关系

pointPolygonTest()函数

函数原型

double pointPolygonTest( InputArray contour, Point2f pt, bool measureDist );

第一个参数是输入轮廓数据

第二个参数是检测点

第三个参数是设定是否要返回距离,如果是true则返回值为该点到轮廓的距离(外部为正,内部为负),如果为false,则返回值1、0、-1分别代表轮廓外,轮廓上、轮廓内

分水岭算法

用于分离图像上的不同部分

这部分的代码 我一直编译失败,查了半天资料也没找出来问题,就先放下了,之后具体用到的时候再补上。

图像处理基础学习笔记——OpenCV已学API汇总相关推荐

  1. 基础学习笔记之opencv(14):随机数发生器绘制文字

    本文主要介绍下opencv中自带的一个随机数发生器的类RNG,这里我用这个类来画一些图形,和基础学习笔记之opencv(13):基本绘图 一文中类似,只是 这里画出来图像的坐标,大小,颜色,角度等所有 ...

  2. Python 基础知识学习笔记——OpenCV(1)

    Python 基础知识学习笔记--OpenCV(1) OpenCV是一个开源的跨平台计算机视觉和机器学习软件库,它轻量而且高效,被广泛的使用. 整理一下OpenCV学习笔记,以防忘记. 文章目录 Py ...

  3. 12月28日 OpenCV 实战基础学习笔记——疲劳检测

    文章目录 前言 一.眨眼疲劳检测 前言 本文为12月28日 OpenCV 实战基础学习笔记--疲劳检测. 一.眨眼疲劳检测 from scipy.spatial import distance as ...

  4. 9月14日计算机视觉基础学习笔记——基本图像处理

    文章目录 前言 一.计算机视觉的由来 二.计算机如何看到图像 三.计算机处理图像的方式.方法 1.直接从 camera 读取 2.从文件读取 3.生成矩阵显示 四.图像处理 1.颜色空间转换 (1). ...

  5. 12月19日 OpenCV 实战基础学习笔记——特征匹配

    文章目录 前言 一.特征匹配 1.Brute-force 蛮力匹配 2.1 对 1 匹配 3.k 对最佳匹配 二.答题卡识别 前言 本文为12月19日 OpenCV 实战基础学习笔记--特征匹配,分为 ...

  6. Python基础学习笔记之(一)

    Python基础学习笔记之(一) zouxy09@qq.com http://blog.csdn.net/zouxy09 前段时间参加微软的windows Azure云计算的一个小培训,其中Pytho ...

  7. 8. SpringBoot基础学习笔记

    SpringBoot基础学习笔记 课程前置知识说明 1 SpringBoot基础篇 1.1 快速上手SpringBoot SpringBoot入门程序制作 1.2 SpringBoot简介 1.2.1 ...

  8. pyTorch——基础学习笔记

    pytorch基础学习笔记博文,在整理的时候借鉴的大量的网上资料,存在和一部分图片定义的直接复制黏贴,在本博文的最后将会表明所有的参考链接.由于参考的内容众多,所以博文的更新是一个长久的过程,如果大佬 ...

  9. ASP.Net MVC开发基础学习笔记(5):区域、模板页与WebAPI初步

    http://blog.jobbole.com/85008/ ASP.Net MVC开发基础学习笔记(5):区域.模板页与WebAPI初步 2015/03/17 · IT技术 · .Net, Asp. ...

最新文章

  1. 一个表对应另一个表中多个主键的查询方法(把一个表当成两个表用)
  2. CVPR 2020 Oral 出炉!5篇 Oral 论文抢先看
  3. Laravel-5.1验证码mews captcha
  4. 戏说 Windows GDI (2)
  5. 【渝粤题库】广东开放大学 java web开发技术 形成性考核
  6. 【渝粤题库】国家开放大学2021春1026西方经济学(本)题目
  7. 幻侠修仙服务器维护,幻侠修仙常见问题_幻侠修仙问答_疑难解答_九游手机游戏...
  8. Docker 服务器安装(一)
  9. 【转】Android bluetooth介绍(三): 蓝牙扫描(scan)设备分析
  10. Linux环境下的jdk安装(大数据环境)
  11. python中的时间和时区详解(datetime / dateutil / pytz)
  12. 百度年龄计算机在线使用,百度年龄计算器app
  13. WPF使用GMap.net框架开发地图应用
  14. on device trainning
  15. 我是如何做研发人员内部培训的
  16. Canvas 画九宫格图片
  17. 论文精读:Faster R-CNN: Towards Real-Time ObjectDetection with Region Proposal Networks
  18. python知网查重_学长学姐使用知网查重的经验之谈
  19. CentOS 安装 laradock 以及运行 Laravel 项目
  20. 失联两天,只为Root掉我的索尼手机?记录刻苦铭心的索尼XZ1折腾之旅

热门文章

  1. PE文件-手工修改重定位表-WinHex-CFF Explorer
  2. IDEA的maven项目生成的文件详解 【.mvn、mvnw、mvnw.cmd、.gitignore、.iml、.idea、pom.xml】
  3. uni-app官方授权广告代理商——AdSet聚合广告平台
  4. 一个老程序员的忠告:不要一辈子靠技术生存
  5. matlab中升余弦滤波器产生函数rcosdesign
  6. C++(笔记)虚方法
  7. (四)Hadoop分布式文件系统Hdfs
  8. 承认吧,程序员就是比你有钱,又比你会过日子
  9. php zip 文件名乱码,如何解决php zip解压乱码的问题
  10. jsp和js之间的参数获取问题