欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

OpenCV可移植图形工具HighGUI实现图像和视频操作

发布时间:2024/7/23 59 豆豆
生活随笔 收集整理的这篇文章主要介绍了 OpenCV可移植图形工具HighGUI实现图像和视频操作 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

OpenCV把用于操作系统、文件系统以及摄像机等硬件设备交换的函数纳入了HighGUI(High-level Graphical User Interface)模块中。有了HighGUI模块,我们可以方便地打开窗口、显示图像、读出或写入图像相关的文件、鼠标事件和键盘事件。下面将对三部分分别进行介绍。

HighGUI三部分的作用部分作用
硬件部分最主要是对摄像机的操作
文件系统部分主要工作是完成图片的载入和保存
窗口系统GUI创建窗口并将图片放入窗口显示,同时添加响应鼠标和键盘事件功能

图像文件的处理

图像的载入与保存

使用cv::imread()读取图片

cv::Mat cv::imread(const string& filename, int flags=cv::IMREAD_COLOR)

作用:载入图像,若失败不会抛出异常,返回的是空的cv::Mat(可以用cv::Mat::empty()==true来判断)。

flags的取值标志含义默认值
cv::IMREAD_COLOR读取三通道图像,即使输入是灰度图像,也会有三通道,只是每个通道拥有相同的数据
cv::IMREAD_GRAYSCALE读取单通道图像
cv::IMREAD_ANYCOLOR通道数由文件实际通道数(不超过3)
cv::IMREAD_ANYDEPTH允许加载超过8bit深度
cv::IMREAD_UNCHANGED相当于cv::IMREAD_ANYCOLOR和cv::IMREAD_ANYDEPTH组合使用,可保留alpha通道。

使用cv::imwrite()保存图像

bool cv::imwrite(const string& filename, InputArray image, const vector<int>& params=vector<int>())

作用:保存图像,成功返回true,否则返回false。

常用扩展名扩展名格式大小通道
.jpg或.jpegbaseline JPEG8位单通道或三通道
.jp2JPEG20008位或16位单通道或三通道
.tif或.tiffTIFF8位或16位单通道、三通道或四通道
.pngPNG8位或16位单通道、三通道或四通道
.bmpBMP8位单通道、三通道或四通道
.ppm或.pgmNetPBM8位单通道(PGM)和三通道(PPM)
params的使用标志含义取值范围默认值
cv::IMWRITE_JPG_QUALITYJPEG的质量0~10095
cv::IMWRITE_PNG_COMPRESSIONPNG压缩值0~93
cv::IMWRITE_PXM_BINARY对PPM、PGM或PBM文件是否使用二值格式0或11

关于codecs的一些注释

用于图像处理的库通常被叫做codecs(co-mpression and dec-compress libraries-s)。OpenCV对一些图片格式自带编码解码库,对于这些有一下三中选择:

① 不使用这些编码解码库;

② 使用OpenCV所提供的编码解码库;

③ 使用相应的拓展库(如libjpeg、libpng等)。

在Windows系统中默认选②选项,而在OS X或Linux系统上,默认选③选项。

图片的编码与解码

使用cv::imencode()压缩图像

void cv::imencode(const string& ext, InputArray img, vector<uchar>& buf, const vector<int>& params=vector<int>())

作用:对图像进行编码。

参数列表参数含义
ext文件扩展名,用于函数与对应的编码压缩方式相关联。指明格式并帮助系统索引对应编码库
img要被压缩的图像数据
buf用来存储编码压缩后的图像数据的字符数组
params指明要使用编码器的输入参数

使用cv::imdecode()解码文件

cv::Mat cv::imdecode(InputArray buf, int flags=cv::IMREAD_COLOR)

作用:将字节流数据解码成数组形式的图像。

视频处理

使用cv::VideoCapture对象读取视频流

cv::VideoCapture::VideoCapture(const string& filename)

cv::VideoCapture::VideoCapture(int device)

cv::VideoCapture::VideoCapture()

作用:打开视频文件或摄像机。打开成功则cv::VideoCapture::isOpen()会返回true,否则返回false。

构造设备参数时,传入的标识符是相机的域索引和相机索引之和。相机索引是指系统中摄像机设备的索引,从0开始计数。相机域表明我们用何种相机,如下表所示。

相机域常量相机捕捉常数数值相机捕捉常数数值相机捕捉常数数值
cv::CAP_ANY0cv::CAP_DSHOW700cv::CAP_OPENNI21600
cv::CAP_MIL100cv::CAP_PVAPI800cv::CAP_OPENNI2_ASUS1610
cv::CAP_VFW200cv::CAP_OPENNI900cv::CAP_GPHOTO21700
cv::CAP_V4L200cv::CAP_OPENNI_ASUS910cv::CAP_GSTREAMER1800
cv::CAP_V4L2200cv::CAP_ANDROID1000cv::CAP_FFMPEG1900
cv::CAP_FIREWIRE300cv::CAP_XIAPI1100cv::CAP_IMAGES2000
cv::CAP_FIREWARE300cv::CAP_AVFOUNDATION1200cv::CAP_ARAVIS2100
cv::CAP_IEEE11394300cv::CAP_GIGANETIX1300cv::CAP_OPENCV_MJPEG2200
cv::CAP_DC1394300cv::CAP_MSMF1400cv::CAP_INTEL_MFX2300
cv::CAP_QT500cv::CAP_WINRT1410cv::CAP_XINE2400
cv::CAP_UNICAP600cv::CAP_INTELPERC1500  

当传入的标识符为-1时,则OpenCV会弹出一个选择窗口,可手动选择希望使用的相机。

最后一种形式只是直接创建一个VideoCapture对象,无法直接使用,需要调用cv::VideoCapture::open()函数来指定文件名或设备号,和前两种形式一样。

使用cv::VideoCapture::read()从视频流中读取图像

bool cv::VideoCapture::read(OutputArray img)

作用:从文件中读取下一帧数据,并将结果存入img中,并会自动更新。读取成功返回true,读取失败返回false。

使用cv::VideoCapture::operator>>()从视频流读取图像数据

cv::VideoCapture& cv::VideoCapture::operator>>(Mat& img)

作用:重载输入流操作符,从文件中读取下一帧数据,并将结果存入img中。

使用cv::VideoCapture::grab()和cv::VideoCapture::retrieve()从视频流中读取图像数据

bool cv::VideoCapture::grab()

作用:将当前可使用的图像数据拷贝至用户看不到的一个内存缓存区。抓取的图像帧是未处理的,该函数只是设计用于将原始数据尽快获取到电脑。

bool cv::VideoCapture::retrieve(OutputArray image, int channel)

作用:对内部缓存数据进行必要的图像解码、内存分配与拷贝,最后以Mat形式的序列将图像帧返回。

相机属性cv::VideoCapture::get()和cv::VideoCapture::set()

double cv::VideoCapture::get(int propid)

bool cv::VideoCapture::set(int propid, double value)

作用:获取或设置元数据(meta data)。

视频捕捉属性常量ID是否只在摄像头模式下可以使用含义
cv::CAP_PROP_POS_MSEC 视频文件中当前位置(毫秒)或视频捕获时间戳
cv::CAP_PROP_POS_FRAMES 从0开始下一帧的索引
cv::CAP_PROP_POS_AVI_RATIO 视频的相对位置
cv::CAP_PROP_FRAME_WIDTH 视频帧的像素宽度
cv::CAP_PROP_FRAME_HEIGHT 视频帧的像素高度
cv::CAP_PROP_FPS 录制视频的帧速率
cv::CAP_PROP_FOURCC 四个字符代码指示编解码
cv::CAP_PROP_FRAME_COUNT 视频文件的总帧数
cv::CAP_PROP_FORMAT 返回Mat对象的格式(如CV_8UC3)
cv::CAP_PROP_MODE 表示捕捉模式,值是特定于正在使用的视频后端(如DC1394)
cv::CAP_PROP_BRIGHTNESS相机的亮度设置
cv::CAP_PROP_CONCAT相机的对比度设置
cv::CAP_PROP_SATURATION相机的饱和度设置
cv::CAP_PROP_HUE相机的色调设置
cv::CAP_PROP_GAIN相机的增益设置
cv::CAP_PROP_EXPOSURE相机的曝光设置
cv::CAP_PROP_CONVERT_RGB如果非0,获取的图像将被转换为具有三个通道
cv::CAP_PROP_WHITE_BALANCE相机的白平衡设置
cv::CAP_PROP_RECTIFICATION立体相机整流标志(仅适用于DC1934-2.x)

使用cv::VideoWriter对象写入视频

cv::VideoWriter::VideoWriter(const string& filename, int fourcc, double fps, Size frame_size, bool is_color=true)

cv::VideoWriter::VideoWriter()

作用:创建一个VideoWriter对象,is_color为true则传入彩色图,反之可以传入灰度图。同样第二种形式不能直接使用,需要调用cv::VideoWriter::open()函数进行配置。

判断是否初始化成功,可通过cv::VideoWriter::isOpen()的返回值进行判断。

使用cv::VideoWriter::write()函数完成图像帧的写入

cv::VideoWriter::write(const Mat& img)

作用:完成图像帧的写入,图像必须和cv::VideoWriter具有相同的图像尺寸,如果是彩色必是三通道,反之使用单通道。

使用cv::VideoWriter::operator<<()将图像写入视频

cv::VideoWriter& cv::VideoWriter::operator<<(Mat& img)

作用:重载输出流操作符,将img存入视频文件。

数据存储

作为对标准视频压缩方式的补充,OpenCV提供了一种序列化与反序列化的机制,用于将不同数据类型的数据已YAML或XML格式写入磁盘或者从磁盘读取。这些方法可以用来加载或者保存任何OpenCV的数值变量到一个文件中。

cv::FileStorage的写入

cv::FileStorage::FileStorage(string filename, int flag)

cv::FileStorage::FileStorage()

作用:创建FileStorage对象(代表XML或YAML格式的数据文件),flag指定功能,写入时可为cv::FileStorage::WRITE和cv::FileStorage::APPEND。同样第二种形式不能直接使用,需要调用cv::FileStorage::open()函数进行配置。

写入时可以使用重载输出操作符函数cv::FileStorage::operator<<()进行写入。写完时调用cv::FileStorage::release()关闭该文件。

cv::FileStorage内部数据的存储形式主要有mapping和sequence,在最顶层是一个mapping,其中可以嵌套mapping和sequence。新建mapping或sequence分别使用{}和[]。

#include "stdafx.h" #include <opencv2/opencv.hpp> #include <time.h>// 使用cv::FileStorage创建一个test.yml参数文件 int main() {// 创建FileStorage对象,实现其写入功能cv::FileStorage fs("test.yml", cv::FileStorage::WRITE);// 写入内容fs << "frameCount" << 5;// 获取当前时间并写入time_t rawtime;time(&rawtime);fs << "calibrationDate" << asctime(localtime(&rawtime));// 生成矩阵,并写入cv::Mat cameraMatrix = (cv::Mat_<double>(3, 3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1);cv::Mat distCoeffs = (cv::Mat_<double>(5, 1) << 0.1, 0.01, -0.001, 0, 0);fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs;// 随机生成数及数组并写入fs << "features" << "[";for (int i = 0; i < 3; i++) {int x = rand() % 640;int y = rand() % 480;uchar lbp = rand() % 256;fs << "{:" << "x" << x << "y" << y << "lbp" << "[:";for (int j = 0; j < 8; j++) {fs << ((lbp >> j) & 1);}fs << "]" << "}";}fs << "]";// 关闭文件fs.release();return 0; }

 用记事本打开test.yml文件,内容如下:

cv::FileStorage读取文件

cv::FileStorage::FileStorage(string filename, int flag)

cv::FileStorage::FileStorage()

作用:创建FileStorage对象(代表XML或YAML格式的数据文件),flag指定功能,读取时可为cv::FileStorage::READ。同样第二种形式不能直接使用,需要调用cv::FileStorage::open()函数进行配置。

读取时可以使用重载输出操作符函数cv::FileStorage::operator>>()进行读取,得到的不是直接的数据,而是FileNode对象。若该值是基本数据类型,则可以通过强制类型转换直接获取;若该值是mapping,则通过重载操作符[]并给定所需关键字访问;若该值是sequence,则通过重载操作符[]并给定整型参数访问,也可使用cv::FileStorageIterator迭代器进行访问。

读完时调用cv::FileStorage::release()关闭该文件。

cv::FileNode

FileNode的基本使用在上述内容中已做过介绍,下面将主要针对cv::FileStorageIterator进行介绍。

给定一个FileNode对象,通过cv::FileNode::begin()和cv::FileNode::end()可以分别返回该mapping或者sequence的首元素的迭代器和末尾首元素的迭代器。该迭代器对象可以通过cv::FileStorageIterator::operator*()来进行解引用操作并返回迭代器对应的位置的FileNode对象,并通过自增和自减来控制迭代器。

若其对一个mapping进行遍历,返回的FileNode对象将会有名字属性,可通过cv::FileNode::name()得到。同样,通过cv::FileNode::type()可获得cv::FileNode中定义的枚举类型。

cv::FileNode的成员函数示例说明
cv::FileNode fn文件节点对象的默认构造函数
cv::FileNode fn1(fn0)文件节点对象的复制构造函数,从节点fn0创建节点fn1
cv::FileNode fn1(fs,node)文件节点对象构造函数,从C风格的CvFileStorage*指针和C风格的CvFileNode*指针节点创建FileNode对象

fn[ (string) key ]

fn[ (const char*) key ]

命名子串(映射节点)的STL字符串或C字符串存取器,将秘钥转换为适当的子节点。
fn[ (int) id ]子编号(序列节点)的访问;将ID转换为相应的子节点
fn.type()返回节点类型enum
fn.empty()确定节点是否为空
fn.isNone()确定节点是否为None
fn.isSeq()确定节点是否为序列
fn.isMap()确定节点是否为映射

fn.isInt()

fn.isReal()

fn.isString()

确定节点是否为整数

确定节点是否为浮点数

确定节点是否为字符串

fn.name()如果节点是映射的子节点,返回节点名称
size_t sz= fn.size()如果是序列或映射,返回节点中的元素数量,否则返回1。

(int) fn

(float) fn

(double) fn

(string) fn

从包含整数的节点中提取

从包含32位浮点数的节点中提取

从包含64位浮点数的节点中提取

从包含字符串的节点中提取

cv::FileNode::type()可能的返回值示例说明
cv::FileNode::NONE = 0节点类型为None
cv::FileNode::INT = 1节点包含一个整数

cv::FileNode::REAL = 2

cv::FileNode::FLOAT = 2

节点包含一个浮点数(不分精度)

cv::FileNode::STR = 3

cv::FileNode::STRING = 3

节点包含一个字符串
cv::FileNode::REF = 4节点包含参考(即复合对象)
cv::FileNode::SEQ = 5节点本身是其他节点的序列
cv::FileNode::MAP = 6节点本身是其他节点的映射
cv::FileNode::FLOW = 8节点是序列或映射的紧凑表示
cv::FileNode::USER = 16节点是注册对象(如矩阵)
cv::FileNode::EMPTY = 32节点没有复制给它
cv::FileNode::NAMED = 64节点是映射的子节点(即它有一个名字)

注:一个FileNode除了拥有前8种属性之外还可以同时拥有最后四个中的一个或全部属性。

#include "stdafx.h" #include <opencv2/opencv.hpp>// 使用FileStorage来读取test.yml文件 int main() {// 创建FileStorage对象,实现读取功能cv::FileStorage fs("D:\\personal-data\\opencv\\example8-2\\example8-2\\test.yml", cv::FileStorage::READ);// 对FileNode进行强制类型转换,得到数据int frameCount = (int)fs["frameCount"];// 使用重载>>操作符std::string date;fs["calibrationDate"] >> date;cv::Mat cameraMatrix, distCoeffs;fs["cameraMatrix"] >> cameraMatrix;fs["distCoeffs"] >> distCoeffs;std::cout << "frameCount" << frameCount << std::endl;std::cout << "calibrationDate" << date << std::endl;std::cout << "cameraMatrix" << cameraMatrix << std::endl;std::cout << "distCoeffs" << distCoeffs << std::endl;cv::FileNode features = fs["features"];cv::FileNodeIterator it = features.begin(), it_end = features.end();int idx = 0;std::vector<uchar> lbpval;// 使用迭代器遍历序列for (; it != it_end; ++it, idx++){std::cout << "features #" << idx << ": ";std::cout << "x=" << (int)(*it)["x"] << ", y=" << (int)(*it)["y"] << ", lbp: (";(*it)["lbp"] >> lbpval;for (int i = 0; i < (int)lbpval.size(); i++){std::cout << " " << (int)lbpval[i];}std::cout << ")" << std::endl;}//关闭文件fs.release();return 0; }

运行结果:

frameCount5 calibrationDateMon Aug 20 20:20:03 2018cameraMatrix[1000, 0, 320;0, 1000, 240;0, 0, 1] distCoeffs[0.1;0.01;-0.001;0;0] features #0: x=41, y=227, lbp: ( 0 1 1 1 1 1 0 1) features #1: x=260, y=449, lbp: ( 0 0 1 1 0 1 1 0) features #2: x=598, y=78, lbp: ( 0 1 0 0 1 0 1 0)

 

总结

以上是生活随笔为你收集整理的OpenCV可移植图形工具HighGUI实现图像和视频操作的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。