OpenCV的简单使用教程与基本函数(C++版本)

OpenCV的简单使用教程(C++)

OpenCV简介OpenCV的使用基础打开、显示和保存图像图像存储变量 Mat类图像元素的存储读入图像文件创建Mat类复制Mat类图像元素的访问OpenCV画图命令行交互界面

OpenCV简介

OpenCV是一个开源发行的跨平台计算机视觉和机器学习软件库,提供了图像处理和计算机视觉方面的很多通用算法。接下来,我简要介绍一些OpenCV基础且常用的函数(C++接口)。

OpenCV的使用基础

在这里,我就不讲OpenCV的配置问题了。在使用OpenCV接口时,记得在代码开头的预处理命令部分加入:

#include

#include

为了方便和编写可读性高、简洁的代码,墙裂建议使用命名空间:

using namespace cv;// 省去函数前面加cv::的必要性

当然,也可以不使用命名空间,但是在使用时需自己写cv,例如:

cv::Mat img;

打开、显示和保存图像

打开图像:imread 显示图像:imshow 保存图像:imwrite 例如:

int main()

{

char imageName[] = "/test.jpg";

Mat M=imread(imageName,IMREAD_COLOR); // 读入图片

if(M.empty()) // 判断文件是否正常打开

{

fprintf(stderr, "Can not load image %s\n", imageName);

waitKey(6000); // 等待6000 ms后窗口自动关闭

return -1;

}

imshow("image",M); // 显示图片

waitKey();

imwrite("pic.bmp",M); // 存为bmp格式图片

return 0;

}

图像存储变量 Mat类

Mat类包括两个数据部分 (1)矩阵头:大小恒定,包括矩阵大小、存储方法、矩阵存储地址等信息 (2)矩阵指针:大小不定,指向包含了像素值的矩阵(可选择存储方法,采用任何维度存储数据)

// Mat的相关参数

int depth = M.depth(); //元素数据类型,枚举型,0为CV_8U

int channels = M.channels(); //色彩通道数

int nRows = M.rows; //行数,图像高度

int nCols = M.cols; //列数,图像宽度

uchar * data = M.data; //图像地址

int nDims = M.dims; //图像维度

int nElSize = M.elemSize(); //每个像素字节数

int nElSize1 = M.elemSize1(); //每个像素单通道的字节数

int type = M.type(); //元素数据类型及通道数,枚举型

Type:枚举类型 type的命名格式为CV_(位数)+(数据类型)+(通道数)

图像元素的存储

1.单通道灰度图 (像素通常为< uchar >类型) 2.RGB三通道彩色图 (像素通常为< Vec3b >类型) 注意事项:①行号、列号都是从“0”开始;②RGB彩色图的通道顺序反过来了,在OpenCV中是BGR。

读入图像文件

读入图像使用imread函数,用法如下:

Mat M; //只构造了Mat类的矩阵头

M = imread(argv[1], IMREAD_COLOR); // 开辟矩阵空间,并将文件的内容写入

函数声明

Mat imread(const string& filename, int flags);

IMREAD_UNCHANGED -1

IMREAD_GRAYSCALE 0

IMREAD_COLOR 1

IMREAD_ANYDEPTH 2

IMREAD_ANYCOLOR 4

缺省值为1

创建Mat类

使用Mat函数可以创建图像矩阵,并可指定大小

// 利用成员函数 create() 创建图像矩阵

Mat M;

M.create(4,4, CV_8UC2); //4行4列,开辟内存,但未指定像素的初值

cout << "M = "<< endl << " " << M << endl << endl;

// 利用Mat类的构造函数创建图像矩阵

//2维图像—平面图像

Mat M(2,2, CV_8UC3, Scalar(0,0,255)); //2行2列,给定全体像素的值

cout << "M = " << endl << " " << M << endl << endl;

system(" pause "); //用于让命令窗口停留显示

//3维图像—立体图像

(构造3维矩阵时,需先定义一个数组,说明每个维度的尺寸)

int sz[3] = {3,3,3}; //每个维度尺寸都是3

Mat M(3,sz,CV_8UC1,Scalar::all(0)); //高维无法直接用cout显示

//构造指定内容的特殊矩阵

// 用类似matlab的特殊矩阵为第一个通道的矩阵赋值

Mat M = Mat::eye(4, 4, CV_64FC2);

Mat M = Mat::ones(2, 2, CV_32F);

Mat M = Mat::zeros(3,3, CV_8UC1);

//指定每个像素

Mat M = (Mat_(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);

Mat_ 对应 CV_64F; Mat_对应 CV_8U

Mat_对应 CV_8S; Mat_对应 CV_32S

Mat_对应 CV_32F; Mat_对应 CV_64F

//利用随机数给矩阵赋值

Mat M = Mat(3, 2, CV_8UC3);

cv::randu(M, Scalar::all(0), Scalar::all(255)); //上限255,下限0

//利用外部数据指针赋值

Mat M(height, width, CV_8UC3, pixels);

//char * pixels;

复制Mat类

当需要复制图像或者生成一张与原图像大小的新图像时,要用使用复制Mat类

//仅复制矩阵头,不复制数据

//共享全部数据

Mat B(A); // 将A的矩阵头复制给B

C = A; // 将A的矩阵头复制给C

//共享部分数据

Mat D(A, Rect(0,0,2,3));

//D为A中以(0,0)为左上角,宽2,高3的矩形部分

Mat E = A(Range::all(),Range(0,3));

//E包括A的每一行,及其中第0列到第2列

//复制矩阵头,且复制一份新数据

//克隆

Mat F = A.clone();

//拷贝

Mat G;

A.copyTo(G);

图像元素的访问

因为灰度图像和彩色图像的通道数不一样,所以两者的访问方式不一样,需要注意。下面我主要讲解彩色图像元素的访问(三通道),灰度图像的访问只需要单通道和用Mat.at< uchar >(j,i)访问即可。 访问方式有三种:data指针、Mat.at(i,j)和Mat.ptr行指针

//1. 使用data指针(unsigned char*)加偏移量

unsigned char* ptr=M.data;

int height = M.rows; //number of rows

int width = M.cols; //number of colums

for (int i=0; i

{

for (int j=0; j

{

ptr[ (i *width +j)*3 +0]=ptr[ (i *width +j)*3 +0]/2;

ptr[ (i *width +j)*3 +1]=ptr[ (i *width +j)*3 +1]/2;

ptr[ (i *width +j)*3 +2]=ptr[ (i *width +j)*3 +2]/2;

}

}

//2. 用Mat.at(i,j)访问坐标(i,j)的图像元素

int height = M.rows; //number of rows

int width = M.cols; //number of colums

for (int i=0; i

{

for (int j=0; j

{

M.at(i,j)[0] = M.at(i,j)[0]*i*j/(height*width);

M.at(i,j)[1] = M.at(i,j)[1]*i*j/(height*width);

M.at(i,j)[2] = M.at(i,j)[2]*i*j/(height*width);

}

}

int height = M.rows; //number of rows

int width = M.cols; //number of colums

Vec3b* p;

for (int i=0; i

p = M.ptr(i);

for (int j=0; j

p[j][0] = p[j][0]*i*j/(height*width);

p[j][1] = p[j][1]*i*j/(height*width);

p[j][2] = p[j][2]*i*j/(height*width);

}

}

OpenCV画图

使用OpenCV可以画出很多的基本图形,应有尽有,比如:画圆、画直线、插入文字等。

// 画圆

Point center = Point(255,255);//圆心

int r = 100; //半径

circle(M,center,r,Scalar(0,0,0));

//参数为:原图像、圆心、半径、颜色、粗细、线型

imshow(“显示图像",img);

// 画椭圆弧线

Size s=Size(20,10);

ellipse(M,center,s,0,10,180,Scalar(0,0,0));

//参数为:原图像、圆心、长短轴、径向夹角(水平面到长轴的夹角)、起始角度(长轴到起始边沿的夹角)、结束角度(长轴到结束点的夹角)、倾斜的矩形(可选项)、颜色、粗细、线性、偏移

// 画线

Point a = Point(600,600);

line(M,a,center,Scalar(255,0,0));

//参数为:原图像、起始点、结束点、颜色、粗细、线型

// 画矩形

rectangle(M,a,center,Scalar(255,0,0));

//参数为:原图像、顶点、对角点、颜色、粗细、大小

// 插入文字

string words= "good luck";

putText(M,words,Point(M.rows/2,M.cols/4),CV_FONT_HERSHEY_COMPLEX,1,Scalar(255,0,0));

//参数为:承载的图片,插入的文字,文字的位置(文本框左下角),字体,大小,颜色

命令行交互界面

OpenCV提供了相关函数,有助于编写交互程序

带输入参数的可执行命令

//主函数增加两个入口参数

int main(int argc,char*argv[])

// argv[0]为命令自身,其后依次为输入参数;argc为数组的元素个数

对于 int _tmain(int argc, _TCHAR* argv[]) //C++版本的main函数

需设值项目属性的generalcharacter setUse Multi-Byte Character Set

//调用变量时

Mat img=imread(argv[1],IMREAD_ANYCOLOR);

// 调试时

在Solution Explore中右键项目(或选中项目后点project菜单)

Properties --> Configuration Properties -> Debugging

在Command Arguments中,输入入口参数(如C:\news.jpg),参数间以空格隔开

//命令窗口调用时

打开项目的debug目录(xxx.exe所在目录)

空白处“Shift+右键”,选择“在此处打开命令窗口”

输入项目名及参数,如 xxx C:\news.jpg

执行过程中的命令行输入交互

// 加入命令行输入提示

cout<<"请选择操作 [1] xx; [2] xx\n";

// 读入选择

int x;

cin>>x;

// 根据选择,提示下一步输入,及执行相应操作

string imagename;

if (x == 1)

{ cout<<"请输入图片文件名“<

cin>>imagename;

Mat img=imread(imagename,IMREAD_COLOR);

….

}

更多详细的OpenCV函数说明,请移步官方文档:

https://docs.opencv.org/3.4/d6/d00/tutorial_py_root.html