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

2023-05-16

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

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

OpenCV简介

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

OpenCV的使用基础

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

#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp>   

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

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_(位数)+(数据类型)+(通道数)
Mat type说明

图像元素的存储

1.单通道灰度图 (像素通常为< uchar >类型)
单通道灰度图
2.RGB三通道彩色图 (像素通常为< Vec3b >类型)
rgb图
注意事项:①行号、列号都是从“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_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
Mat_<double> 对应	CV_64F; 	Mat_<uchar>对应	CV_8U
Mat_<char>对应	CV_8S;	Mat_<int>对应	CV_32S
Mat_<float>对应	CV_32F;	Mat_<double>对应	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<height; i++) 
{
	for (int j=0; j<width; 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<height; i++)
 {
	for (int j=0; j<width; j++)
	{
		M.at<Vec3b>(i,j)[0] = M.at<Vec3b>(i,j)[0]*i*j/(height*width);
		M.at<Vec3b>(i,j)[1] = M.at<Vec3b>(i,j)[1]*i*j/(height*width);
		M.at<Vec3b>(i,j)[2] = M.at<Vec3b>(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<height; i++) {
        p = M.ptr<Vec3b>(i);
        for (int j=0; j<width; 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<<"请输入图片文件名“<<endl;
   cin>>imagename;
   Mat img=imread(imagename,IMREAD_COLOR);.
}

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • Linux|奇怪的知识|locate命令---文件管理小工具

    前言 Linux的命令是非常多的 xff0c 有一些冷门的命令 xff0c 虽然很少用 xff0c 但可能会有意想不到的功能 xff0c 例如 xff0c 本文将要介绍的locate命令 xff08 平常很少会想到使用此命令 xff0c f
  • python之装饰器

    引言 软件开发中 xff0c 当需要创建高度重复的代码时 xff0c 需要寻求一种优雅的解决方案 python中的元编程即解决这类问题 xff0c 通过创建函数和类来修改 生成或包装已有的代码 装饰器就是python中用来包装函数的一种机制
  • docker容器中程序退出异常,GPU未释放

    1 问题描述 近期在docker容器中对一批数据通过算法进行清洗时 xff0c 当数据处理完成后发现进程未正常退出 xff0c GPU内存未正常释放 span class token punctuation span root 64 ai6
  • 初识Redis

    什么是Redis Remote Dictionary Server xff0c 即远程字典服务 xff0c 是一款开源的 基于内存也支持持久化的key value数据库 xff0c 提供多种语言API 通常应用于需要处理大规模数据读写的场景
  • python之闭包

    前言 闭包作为python高级特性中的一个 xff0c 初学总觉其披着一层神秘的面纱 xff0c 这里我们来一起揭开这层面纱吧 那什么是闭包呢 xff1f 闭包 xff0c 又称闭包函数 xff0c 和普通的嵌套函数类似 xff0c 闭包中
  • 三个基础排序算法

    排序在计算机算法中非常常见也非常基础 xff0c 不管是准备面试还是纯属兴趣 xff0c 掌握它都很有必要 选择排序 基本思想 xff1a 预置list i 为最小 xff0c 逐个比较range i len list 里的元素 xff0c
  • 数据结构之链表

    和顺序表相对应 xff0c 有个链式存储的数据结构 xff0c 命名曰链表 单链表 节点中只存储后项节点指针的链表 xff0c 称为单链表 定义节点 class LinkNode object def init self data 61 N
  • 数据结构之哈希表

    概念 哈希表是一种数据结构 xff0c 通过哈希函数来组织数据 xff0c 以支持快速插入和搜索 哈希表的关键思想是使用哈希函数将键映射到存储桶 更确切地说 xff0c 当我们插入一个新的键时 xff0c 哈希函数将决定该键应该分配到哪个桶
  • 图片数据清洗

    前言 数据对于深度学习算法模型的效果至关重要 通常 xff0c 在对采集到的大量数据进行标注前需要做一些数据清洗工作 对于大量的数据 xff0c 人工进行直接清洗速度会很慢 xff0c 因此开发一些自动化清洗工具对批量数据首先进行自动清洗
  • PyQt5 多线程实例

    前言 PyQt的所有窗口都在UI主线程中 xff0c 也就是main函数中执行了QApplication exec 的线程中 xff0c 在该线程中执行耗时较长的操作时 xff0c 会导致当前窗口停止响应 为了避免上述情况发生 xff0c
  • 模型评价标准

    机器学习 机器学习是通过一些让计算机可以自动学习的算法 xff0c 从数据中分析获得规律 xff0c 然后利用规律对新样本进行预测 评价标准 为了了解模型的泛化能力 xff0c 即判断模型的好坏 xff0c 我们需要用某个指标来衡量 xff
  • postgresql|数据库|【postgresql-12的基于pg_basebackup的主从复制部署】

    前言 xff1a postgresql数据库说实话是真心好用 xff0c 但 xff0c 想用好是比较困难的 那么 xff0c 造成该数据库使用困难的是它的内置工具非常的多 xff0c 并且整体优化是比较难的 比如 xff0c 自带的备份工
  • windows上的中文文件名上传到linux上乱码问题解决

    问题描述 有很多多层文件夹存放的数据保存在windows上 xff0c 文件夹和文件名均含有中文 xff0c 将这些文件目录传到linux上 xff0c 中文名显示乱码 问题分析 windows上中文默认编码格式是gbk xff0c 而li
  • JAVA 面试题经典(附答案)

    JAVA JAVA8大基本数据类型 J AVA8大基本数据类型 HashMap和Hashtable的比较 Hashtable xff1a 1 Hashtable不允许key或者value为null xff0c 线程安全 xff0c 实现线程
  • u盘写入映像时提示:主引导记录(mbr)写入失败!!

    在使用软件写入U盘镜像时 xff0c 出现下面的提示 xff1a 解决方法是使用DiskGenius重新建立MBR
  • debian SID安装笔记

    1 声卡设置问题 添加了声卡驱动 xff0c 但是进入桌面没有声音 xff1f 一般是没有给用户使用设备的权限 解决方法 xff1a adduser audio eg adduser jerry audio xff08 解决 xff09 你
  • ubuntu下vncserver配置

    Ubuntu下设置VNCServer Virtual Network Computing VNC 是进行远程桌面控制的一个软件 客户端的键盘输入和鼠标操作通过网络传输到远程服务器 xff0c 控制服务器的操作 服务器的图形界面通过网络传输会
  • vsftp配置实例-虚拟用户锁定目录

    一 实验步骤 1 创建用户 创建ftpuser1登录用户 useradd g ftp d share soft s sbin nologin ftpuser1 为ftpuser1设置登录密码 passwd ftpuser1 2 编辑配置文件
  • 基于51的光立方制作

    单片机入门者必然会从点亮一盏LED灯开始 xff0c 如果LED数量比较多 xff0c 就不能使用单个引脚去控制 xff0c 例如光立方 xff0c 利用锁存器和人体的视觉暂留效果就可以占用少量引脚实现光立方 所需材料 xff1a STC8
  • 如何实现无界面Android app

    如何实现无界面Android app 前言代码实现AndroidManifest xmlMainActivity javaMyService java 前言 在Android开发中 xff0c 可能会遇到只需要在后台运行服务 xff0c 不

随机推荐