OpenCv(C++)学习笔记——图像的读取与保存

本文介绍了OpenCV中图像的读取和保存方法。读取图像使用cv::imread()函数,需指定文件名和读取标记,支持多种图像格式。保存图像使用imwrite()函数,基于文件拓展名选择格式,对不同类型图像保存有不同要求,还给出示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:这是第一次写博客,记录自己的学习过程也将自己的经验分享给大家学习。

OpenCv学习笔记一——图像的读取与保存

图像的读取

在OpenCv中,我们使用cv::imread()来读取和加载图像,该函数形式如下:

cv::Mat cv::imread(const cv::String &filename, int flags = 1)

返回类型:Mat,如果读取图像失败则会返回一个空的矩阵对象(Mat::data==NULL)

参数filename:读取图像文件名,可以使用相对路径或者绝对路径,但是必须带有完整的文件名(包括图像格式后缀)

参数flag:一个读取标记,用于选择读取图像的方式,默认值为IMREAD_COLOR,flags值的设定与用什么颜色格式读取有关。

此外:imread()函数支持读取的图像格式有以下几种。
.bmp .dib .jpeg .jpg .jpe .jp2 .png

C++定义说明
IMREAD_GRAYSCALE返回灰色图像
IMREAD_COLOR返回彩色图像BGR
IMREAD_ANYCOLOR以任何可能的颜色格式读取图像
IMREAD_REDUCED_GRAYSCALE_N将图像转换为灰度图像的1/N,N可以为2,4,8
IMREAD_REDUCED_COLOR_N将图像转换为三通道彩色图像的1/N,N可以为2,4,8
IMREAD_IGNORE_ORIENTATION将忽略任何EXIF信息的方向标志旋转图像
IMREAD_ANYDEPTH以任何可能的深度读取图像
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(void)
{
//读取图像
Mat image=imread("D:\\360\\test.jpg",IMREAD_REDUCED_GRAYSCALE_4);//将D:\\360\\test.jpg改成你的图片的储存地址
if(image.data!=NULL)
{
    //显示图像
    imshow("niiubi",image);
    waitKey(0);
}
else
{
    cout<<"can&apos;t open the file!"<<endl;
    getchar();
}
return 0;
}

图像的保存

C语言中,我们使用imwrite()函数来读取图像,该函数的定义如下:

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

const String & filename:需要保存的图像文件名——格式+扩展名

InputArray:要保存的图像

const std::vector < int > & params:表示为特定格式保存的参数编码。

需要注意的是:imwrite是基于文件拓展名选择格式的。通常,使用此功能只能保存8位单通道或者三通道(BGR)的图像,但有以下例外:

·对于PNG、JPEG2000和TIFF格式,可以保存16位无符号(CV_16U)图像。

·32位浮点(CV_32F)图像可以保存为PFM、TIFF、OpenEXR和Radiance HDR格式,可以使用LogLuv高动态编码(每像素四个字节)保存三通道(CV_32FC3)TIFF格式图像。

·可以使用此功能保存alpha通道的PNG格式图像。为此,创建8位(或者16位)四通道BGRA图像,其中alpha通道在最后。完全透明的像素应该将alpha通道的值设置为0,完全不透明的像素应该将alpha像素通道的值设置为255/65535

·Imwrite()函数中特定格式的编码参数及其含义表如表所示:

编码参数含义
IMWRITE_JPEG_QUALITYJPEG图像质量,其值可以是0~100,越大越好,默认95
IMWRITE_PNG_COMPRESSIONPNG图像的压缩级别,其值可以是0~9,值越大意味着越小的尺寸和越长的压缩时间。如果指定,则策略更改为IMWRITE_PNG_STRATEGY_DEFAULT(Z_DEFAULT_STRATEGY)
IMWRITE_JPEG_QUALITY Python:cv.IMWRITE_JPEG_QUALITY对于JPEG,它可以是从0到100的质量(越高越好)。默认值为95。
IMWRITE_JPEG_PROGRESSIVE Python:cv.IMWRITE_JPEG_PROGRESSIVE启用JPEG功能,0或1,默认为False。
IMWRITE_JPEG_OPTIMIZE Python:cv.IMWRITE_JPEG_OPTIMIZE启用JPEG功能,0或1,默认为False。
IMWRITE_JPEG_RST_INTERVAL Python:cv.IMWRITE_JPEG_RST_INTERVALJPEG重启间隔,0 - 65535,默认为0 - 无重启。
IMWRITE_JPEG_LUMA_QUALITY Python:cv.IMWRITE_JPEG_LUMA_QUALITY单独的亮度质量等级,0 - 100,默认为0 - 不使用。
IMWRITE_JPEG_CHROMA_QUALITY Python:cv.IMWRITE_JPEG_CHROMA_QUALITY单独的色度质量等级,0 - 100,默认为0 - 不使用。
IMWRITE_PNG_COMPRESSION Python:cv.IMWRITE_PNG_COMPRESSION对于PNG,它可以是从0到9的压缩级别。值越高意味着更小的尺寸和更长的压缩时间。如果指定,则策略更改为IMWRITE_PNG_STRATEGY_DEFAULT(Z_DEFAULT_STRATEGY)。默认值为1(最佳速度设置)。
IMWRITE_PNG_STRATEGY Python:cv.IMWRITE_PNG_STRATEGY其中一个品种:: ImwritePNGFlags,默认为IMWRITE_PNG_STRATEGY_RLE。
IMWRITE_PNG_BILEVEL Python:cv.IMWRITE_PNG_BILEVEL二进制级别PNG,0或1,默认为0。
IMWRITE_PXM_BINARY Python:cv.IMWRITE_PXM_BINARY对于PPM,PGM或PBM,它可以是二进制格式标志,0或1.默认值为1。
IMWRITE_EXR_TYPE Python:cv.IMWRITE_EXR_TYPE在OpenCV中,IMWRITE_EXR_TYPE参数可以用来指定EXR图像的压缩类型,其取值可以是以下之一:IMWRITE_EXR_TYPE_HALF:使用半精度浮点数进行压缩。IMWRITE_EXR_TYPE_FLOAT:使用单精度浮点数进行压缩。IMWRITE_EXR_TYPE_UINT:使用无符号整数进行压缩。
IMWRITE_WEBP_QUALITY Python:cv.IMWRITE_WEBP_QUALITY覆盖EXR存储类型(默认为FLOAT(FP32))对于WEBP,它可以是1到100的质量(越高越好)。默认情况下(不带任何参数),如果质量高于100,则使用无损压缩。
IMWRITE_PAM_TUPLETYPE Python:cv.IMWRITE_PAM_TUPLETYPE对于PAM,将TUPLETYPE字段设置为为格式定义的相应字符串值。
IMWRITE_TIFF_RESUNIT Python:cv.IMWRITE_TIFF_RESUNIT对于TIFF,用于指定要设置的DPI分辨率单位; 请参阅libtiff文档以获取有效值。
IMWRITE_TIFF_XDPI Python:cv.IMWRITE_TIFF_XDPI对于TIFF,用于指定X方向DPI。
IMWRITE_TIFF_YDPI Python:cv.IMWRITE_TIFF_YDPI对于TIFF,用于指定Y方向DPI。
IMWRITE_TIFF_COMPRESSION Python:cv.IMWRITE_TIFF_COMPRESSION对于TIFF,用于指定图像压缩方案。请参阅libtiff以获取与压缩格式对应的整数常量。注意,对于深度为CV_32F的图像,仅使用libtiff的SGILOG压缩方案。对于其他支持的深度,可以通过此标志指定压缩方案; LZW压缩是默认值。
IMWRITE_JPEG2000_COMPRESSION_X1000 Python:cv.IMWRITE_JPEG2000_COMPRESSION_X1000对于JPEG2000,用于指定目标压缩率(乘以1000)。该值可以是0到1000.默认值是1000。

给各位一个忠告,这个压缩格式尊嘟太繁杂了,咱们不玩这些花的,记住几个重要的就行了,甚至咱们不记忆这个,到时候有问题直接面向CSDN编程即可。上面加粗的几个是常用格式,可以参考学习

示例代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(void)
{
Mat image=imread("D:\\360\\test.jpg",IMREAD_ANYDEPTH);
if(image.data!=NULL)
{
	//显示图像
    imshow("niiubi",image);
    //不指定压缩格式直接保存
    imwrite("D:\\360\\save.jpg",image);
    waitKey(0);
    //销毁所有窗口
    //destroyAllWindows();
}
else
{
    cout<<"can&apos;t open the file!"<<endl;
    getchar();
}
return 0;
}
<think>好的,我现在需要帮助用户解决如何使用OpenCVC++读取海康相机图像的问题。首先,用户提到了他们之前用Python通过RTSP地址成功读取了摄像头数据,但现在需要转成C++实现。同时,用户还引用了三个参考资料,其中提到海康的SDK、OpenCV集成以及可能遇到的实时读取问题。 首先,我得确认用户的需求:他们想通过C++OpenCV来获取海康相机的图像,可能需要结合海康的SDK。因为直接用RTSP在Python中可以,但C++可能需要不同的处理方式,或者用户可能希望更高效的采集方式,比如使用SDK而不是RTSP流。 接下来,查看用户提供的引用内容。引用[1]展示了Python中使用OpenCV的VideoCapture读取RTSP流,但用户现在需要C++版本。引用[2]提到了C++中使用海康SDK,并配置OpenCV路径,说明可能需要通过SDK来获取图像数据,然后转换为OpenCVMat格式。引用[3]指出实时读取时需要注意解码回调函数中的耗时操作,比如imshow和waitKey可能会影响性能,需要避免在回调中处理这些。 那么,可能的解决方案有两种:一种是通过RTSP流用OpenCV直接读取,类似于Python的方式;另一种是使用海康的SDK进行图像采集,然后将数据转换到OpenCV中进行处理。用户可能希望使用SDK的方法,因为更直接或更高效,尤其是当RTSP存在延迟或性能问题时。 首先,考虑RTSP方法。在C++中,OpenCV的VideoCapture同样支持RTSP流,所以用户可以直接使用类似Python的代码结构,替换成C++语法即可。例如: ```cpp cv::VideoCapture cap("rtsp://admin:password@ip:port/path"); if (!cap.isOpened()) { // 处理错误 } cv::Mat frame; cap >> frame; // 处理frame ``` 但用户引用了海康的SDK相关内容,可能希望更底层的集成,或者遇到RTSP流的问题,比如延迟或稳定性。这时候就需要使用海康的SDK来获取图像数据,然后将数据转换为OpenCVMat格式。 根据引用[2],使用海康SDK需要配置包含路径和库文件,正确初始化和登录设备,然后开始预览,并通过回调函数获取数据。在回调中,可能需要将YUV数据转换为RGB,或者处理海康的原始数据格式,然后生成cv::Mat。 此外,引用[3]提到在解码回调中不能有耗时代码,因此用户需要确保在回调函数中尽快处理数据,避免阻塞。例如,将图像保存到缓冲区,然后在另一个线程中进行显示或处理。 可能的步骤包括: 1. 配置海康SDK的开发环境,包含头文件和库。 2. 初始化SDK,登录设备。 3. 设置预览回调函数,接收实时数据。 4. 在回调中将原始数据(可能是YUV或RGB)转换为OpenCVMat。 5. 处理或显示图像,注意不在回调中做耗时操作。 需要注意的是,海康的SDK可能提供不同的数据格式,比如RGB或YUV,需要正确转换。例如,如果数据是YV12格式,可以使用OpenCV的cvtColor函数转换到BGR。 同时,错误处理也很重要,比如检查SDK的返回值,处理断线重连等。 用户的问题可能还包括如何将海康SDK的数据OpenCV整合,所以示例代码需要展示如何从SDK的回调中获取数据,并构造cv::Mat对象。 另外,线程管理可能也是关键,因为实时视频处理需要在单独的线程中运行,避免阻塞主线程。引用[3]提到在回调中不能有imshow和waitKey,所以可能需要将图像传递到另一个线程进行处理和显示。 总结,解决方案有两种途径:使用RTSP流或使用海康SDK。用户可能需要SDK的方法,所以需要详细说明如何集成SDK,初始化,设置回调,数据转换,并处理多线程问题。</think>### 使用OpenCVC++读取海康相机图像的步骤 #### 方法一:通过RTSP协议直接读取(简单但可能存在延迟) ```cpp #include <opencv2/opencv.hpp> int main() { std::string rtsp_url = "rtsp://admin:密码@IP地址:端口/通道路径"; cv::VideoCapture cap(rtsp_url); if (!cap.isOpened()) { std::cerr << "无法打开摄像头" << std::endl; return -1; } cv::Mat frame; while (true) { cap >> frame; if (frame.empty()) break; cv::imshow("RTSP Stream", frame); if (cv::waitKey(1) == 27) break; // ESC键退出 } return 0; } ``` **注意**:此方法依赖网络稳定性,可能遇到解码延迟问题[^1]。 --- #### 方法二:通过海康SDK采集(高性能但步骤复杂) ##### 1. **环境配置** - 下载海康SDK(`HCNetSDK`),将头文件(`.h`)和库文件(`.lib`/`.so`)添加到项目 - 配置OpenCV包含路径(示例路径): ```cpp // 在.pro文件中(QT项目) INCLUDEPATH += E:/opencv3.0/build_VS2013_x64/install/include LIBS += -L E:/opencv3.0/build_VS2013_x64/install/x64/mingw/lib -lopencv_core300 -lopencv_highgui300 ``` ##### 2. **初始化登录** ```cpp #include <HCNetSDK.h> #include <opencv2/opencv.hpp> // 定义回调函数(需声明为静态) void CALLBACK RealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser); int main() { NET_DVR_Init(); // 初始化SDK NET_DVR_DEVICEINFO_V30 deviceInfo; LONG lUserID = NET_DVR_Login_V30("192.168.1.64", 8000, "admin", "password", &deviceInfo); if (lUserID < 0) { std::cerr << "登录失败,错误码:" << NET_DVR_GetLastError() << std::endl; return -1; } // 启动预览 NET_DVR_PREVIEWINFO previewInfo = {0}; previewInfo.hPlayWnd = NULL; previewInfo.lChannel = 1; previewInfo.dwStreamType = 0; // 主码流 LONG lRealHandle = NET_DVR_RealPlay_V40(lUserID, &previewInfo, RealDataCallBack, NULL); if (lRealHandle < 0) { std::cerr << "预览失败,错误码:" << NET_DVR_GetLastError() << std::endl; NET_DVR_Logout(lUserID); NET_DVR_Cleanup(); return -1; } // 保持程序运行 while (true) { cv::waitKey(1000); } } ``` ##### 3. **回调函数处理图像数据** ```cpp void CALLBACK RealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser) { if (dwDataType == NET_DVR_STREAMDATA) { // 转换为OpenCV Mat(假设YV12格式) cv::Mat yv12_frame(1080 + 540, 1920, CV_8UC1, pBuffer); // 根据实际分辨率调整 cv::Mat bgr_frame; cv::cvtColor(yv12_frame, bgr_frame, cv::COLOR_YUV2BGR_YV12); // 在独立线程中显示(避免阻塞回调) std::thread([bgr_frame]() { cv::imshow("SDK Stream", bgr_frame); cv::waitKey(1); }).detach(); } } ``` ##### 4. **资源释放** ```cpp // 退出时清理资源 NET_DVR_StopRealPlay(lRealHandle); NET_DVR_Logout(lUserID); NET_DVR_Cleanup(); ``` --- #### 关键问题解决 1. **解码卡顿**:回调函数中避免直接调用`imshow`,应使用生产者-消费者队列传递帧数据[^3]。 2. **格式转换**:根据SDK返回的数据格式(如YV12、NV12),选择对应的`cv::cvtColor`参数。 3. **多线程同步**:建议使用双缓冲队列或智能指针管理图像数据。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值