目录
- 图像获取
- 从图片文件获取图像
- 从视频文件获取图像
- 图像显示
- 示例代码
- 从图片文件获取图像
- 从视频获取图像
图像获取
OpenCV 支持从图片文件获取图像、从视频文件获取图像以及从摄像头获取图像等方式。
从图片文件获取图像
使用函数imread
可以从图片文件中读取图像,具体用法如下:
Mat cv::imread (const String& filename, int flags = IMREAD_COLOR)
头文件包含:
#include <opencv2/imgcodecs.hpp>
描述:
imread
从指定文件中加载图像并且返回一个矩阵对象。如果图像加载失败(可能的原因:文件丢失、权限问题、不支持或者无效的文件格式),imread
将会返回一个空矩阵(Mat::data==NULL)。
参数 | 描述 |
---|---|
filename | 图片的文件名(含路径) |
– | – |
flags | 读取模式的标志(见cv::ImreadModes ) |
cv::ImreadModes
标志 | 描述 |
---|---|
IMREAD_UNCHANGED | 按原样返回加载的图像(包含alpha通道,否则将被裁剪)。忽略EXIF方向。 |
IMREAD_GRAYSCALE | 始终将图像转换为单通道灰度图像(编解码器内部转换) |
IMREAD_COLOR | 始终将图像转换为3通道BGR彩色图像 |
IMREAD_ANYDEPTH | 当输入图像具有16位/32位深度时,返回16位/32位图像,否则将其转换为8位 |
IMREAD_ANYCOLOR | 以任何可能的颜色格式读取图像 |
IMREAD_LOAD_GDAL | 使用gdal驱动程序加载图像 |
IMREAD_REDUCED_GRAYSCALE_2 | 始终将图像转换为单通道灰度图像,并将图像大小缩小1/2 |
IMREAD_REDUCED_COLOR_2 | 始终将图像转换为3通道BGR彩色图像,并将图像大小缩小1/2 |
IMREAD_REDUCED_GRAYSCALE_4 | 始终将图像转换为单通道灰度图像,并将图像大小缩小1/4 |
IMREAD_REDUCED_COLOR_4 | 始终将图像转换为3通道BGR彩色图像,并将图像大小缩小1/4 |
IMREAD_REDUCED_GRAYSCALE_8 | 始终将图像转换为单通道灰度图像,并将图像大小缩小1/8 |
IMREAD_REDUCED_COLOR_8 | 始终将图像转换为3通道BGR彩色图像,并将图像大小缩小1/8 |
IMREAD_IGNORE_ORIENTATION | 不根据EXIF的方向标志旋转图像 |
目前支持的文件格式如下:
- Windows bitmaps - *.bmp, *.dib (始终支持)
- JPEG files - *.jpeg, *.jpg, *.jpe (见注意事项)
- JPEG 2000 files - *.jp2 (见注意事项)
- Portable Network Graphics - *.png (见注意事项)
- WebP - *.webp (见注意事项)
- AVIF - *.avif (见注意事项)
- Portable image format - *.pbm, *.pgm, *.ppm *.pxm, *.pnm (始终支持)
- PFM files - *.pfm (见注意事项)
- Sun rasters - *.sr, *.ras (始终支持)
- TIFF files - *.tiff, *.tif (见注意事项)
- OpenEXR Image files - *.exr (见注意事项)
- Radiance HDR - *.hdr, *.pic (始终支持)
- Raster and Vector geospatial data supported by GDAL (见注意事项)
注意事项:
-
该函数根据内容而不是文件扩展名来确定图像的类型。
-
针对彩色图像,解码后的图像将会按照BGR的通道顺序存储。
-
当使用IMREAD_GRAYSCALE时,如果编解码器的内部灰度转换可用,将使用编解码器的内部灰度转换。其结果可能和
cvtColor()
的输出不同。 -
在 Microsoft Windows* 操作系统和 MacOSX* 上,默认使用 OpenCV 图像(libjpeg、libpng、libtiff 和 lib jasper)附带的编解码器。因此,OpenCV 始终可以读取 JPEG、PNG 和 TIFF。在 MacOSX 上,还有一个选项是使用本机 MacOSX 图像读取器。但要注意,由于 MacOSX 中嵌入了颜色管理,目前这些本机图像加载器提供的图像具有不同的像素值。
-
在 Linux*、BSD 风格和其他类 Unix 开源操作系统上,OpenCV 查找随操作系统映像提供的编解码器。安装相关软件包(不要忘记开发文件,例如 Debian* 和 Ubuntu* 中的“libjpeg-dev”),以获得编解码器支持,或在 CMake 中打开 OPENCV_BUILD_3RDPARTY_LIBS 标志。
-
如果将 CMake 中的 WITH_GDAL 标志设置为 true,并设置IMREAD_LOAD_GDAL标志去加载图像,则将使用 GDAL 驱动程序来解码图像,支持以下格式:光栅(Raster)、矢量(Vector)。
-
如果图像文件中嵌入了EXIF信息,则将考虑EXIF方向,因此图像将相应地旋转,除非传递了IMREAD_IGNORE_ORIENTATION 或IMREAD_UNCHANGED 标志。
-
使用IMREAD_UNCHANGED标志保留PFM图像中的浮点值。
-
默认情况下,像素数必须小于
2^30
。可以使用系统变量OPENCV_IO_MAX_IMAGE_PIXELS设置限制。
从视频文件获取图像
cv::VideoCapture
是用于从视频文件、图像序列或相机捕获视频的类。要读取视频文件,需要创建cv::VideoCapture
对象。
头文件包含:
#include <opencv2/videoio.hpp>
VideoCapture (const String &filename, int apiPreference=CAP_ANY)
描述:
使用apiPreference打开视频文件、捕获设备或IP视频流进行视频捕获。
参数:
参数 | 描述 |
---|---|
filename | 1. 视频文件名 2.图像序列 3. 视频流URL 4.如果使用GStreamer作为后端,则采用gst-launch工具格式的GStreamer管道字符串。请注意,每个视频流或IP摄像头feed都有自己的URL方案。请参阅源码流文档以了解正确的URL。 |
apiPreference | 首选要使用的Capture API后端。如果多个可用的读取器实现,则可用于执行特定读取器 |
更多的构造函数,参见cv::VideoCapture Class Reference
virtual bool cv::VideoCapture::isOpened() const
描述:
如果视频捕获已经初始化则返回true。如果先前对 VideoCapture 构造函数或VideoCapture::open()的调用成功,则该方法返回 true。
virtual bool cv::VideoCapture::read (OutputArray image)
描述:
抓取、解码并且返回下一个视频帧。该方法/函数将VideoCapture::grab()和VideoCapture::retrieve()组合在一个调用中。这是读取视频文件或从解码中捕获数据的最方便的方法,并返回刚捕获的帧。如果没有捕获到帧(相机已断开连接,或者视频文件中没有更多帧),则该方法返回false,函数返回空图像(使用cv::Mat,用Mat::empty()测试)。
关于VideoCapture::grab()和VideoCapture::retrieve()参见https://docs.opencv.org/4.x/d8/dfe/classcv_1_1VideoCapture.html#ae38c2a053d39d6b20c9c649e08ff0146
参数:
【输出型】视频帧被放置在这个参数中。如果没有抓取到视频帧,则这个参数的图像数据为空。
返回值:
如果抓取到图像返回true,否则,返回false。
virtual double cv::VideoCapture::get(int propId )const
描述:
返回特定的VideoCapture属性。
参数:
参数 | 描述 |
---|---|
propId | 来自 cv::VideoCaptureProperties的属性标识符或视频I/O API后端的附加标志 |
返回值:
所查询的属性的值。当查询不被后端支持的属性时,返回值 0。
图像显示
OpenCV显示图像可以使用High-level GUI提供的imshow
函数,详情如下:
void cv::imshow (const String & winname, InputArray mat)
头文件包含:
#include <opencv2/highgui.hpp>
描述:
在指定窗口中显示图像。
imshow
函数在指定窗口中显示图像。如果窗口是使用cv::WINDOW_AUTOSIZE
标志创建的,则图像将以原始大小显示,但仍受屏幕分辨率的限制。否则,图像将被缩放以适应窗口。该函数可以根据图像的深度缩放图像:
- 如果图像是8位无符号的,则按原样显示。
- 如果图像是16位无符号的,则像素值除以256。也就是说,值域 [0,255*256] 被映射到 [0,255]。
- 如果图像是32位或64位浮点数,则像素值乘以255。也就是说,值域 [0,1] 被映射到 [0,255]。
- 由于所需变换的模糊性,不再处理32位整数图像。使用特定于图像上下文的自定义预处理转换为8位无符号矩阵。(懵逼O0O)
如果窗口是使用 OpenGL 创建的,则 cv::imshow 也支持 ogl::Buffer、ogl::Texture2D 和cuda::GpuMat 作为输入。
如果在此函数之前未创建窗口,则假定使用 cv::WINDOW_AUTOSIZE 创建窗口。
如果你需要显示一个比屏幕分辨率大的图像,你需要在imshow之前调用namedWindow(“”,WINDOW_NORMAL)。
参数:
参数 | 描述 |
---|---|
winname | 窗口名 |
mat | 被显示的图像矩阵 |
注意事项:
在执行此函数后,应调用 cv::waitKey
或 cv::pollKey
来执行 GUI 日常任务,这些任务对于实际显示给定图像并使窗口响应鼠标和键盘事件是必要的。否则,它将不会显示图像,窗口可能会锁定。例如,waitKey(0)
将无限期显示窗口,直到任何按键(它适用于图像显示)。waitKey(25)
将显示一个帧并等待大约 25 毫秒
的按键(适用于逐帧显示视频)。
要删除窗口,请使用 cv::destroyWindow
。
[仅限 Windows 后端] 按 Ctrl+C 可将图像复制到剪贴板。按 Ctrl+S 可显示一个对话框以保存图像。
示例代码
从图片文件获取图像
- 文件结构
- 源码
ImageProcessor.h
#pragma once
#include <string>
namespace opencv_app{ namespace image {
class ImageProcessor {
public:
ImageProcessor(const std::string& filepath, const std::string& filename);
virtual ~ImageProcessor();
public:
bool show(const std::string& window);
private:
std::string filepath;
std::string filename;
};
}}
ImageProcessor.cpp
#include "ImageProcessor.h"
#include "opencv2/opencv.hpp"
using namespace opencv_app::image;
ImageProcessor::ImageProcessor(const std::string& filepath, const std::string& filename)
{
this->filepath = filepath;
this->filename = filename;
}
ImageProcessor::~ImageProcessor()
{
}
bool ImageProcessor::show(const std::string& window)
{
std::string pathname = this->filepath + this->filename;
cv::Mat image = cv::imread(pathname);
if (nullptr == image.data) {
printf("imread %s error\n", pathname.c_str());
return false;
}
cv::imshow(window, image);
cv::waitKey(0);
return true;
}
main.cpp
#include "ImageProcessor.h"
using namespace opencv_app::image;
int main(int argc, char* argv[])
{
if (argc < 3) {
printf("Usage:./imageProcessor [filepath] [filename]\n");
return -1;
}
ImageProcessor imageProc(argv[1], argv[2]);
imageProc.show(argv[2]);
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(image_processor)
find_package(OpenCV REQUIRED)
add_executable(imageProcessor ./main.cpp ./ImageProcessor.cpp)
target_link_libraries(imageProcessor ${OpenCV_LIBS})
从视频获取图像
- 文件结构
- 源码
ImageProcessor.h
#pragma once
#include <string>
namespace opencv_app{ namespace image {
class ImageProcessor {
public:
ImageProcessor(const std::string& filepath, const std::string& filename);
virtual ~ImageProcessor();
public:
bool show(const std::string& window);
private:
std::string filepath;
std::string filename;
};
}}
ImageProcessor.cpp
#include "ImageProcessor.h"
#include "opencv2/opencv.hpp"
#include "opencv2/videoio.hpp"
using namespace opencv_app::image;
ImageProcessor::ImageProcessor(const std::string& filepath, const std::string& filename)
{
this->filepath = filepath;
this->filename = filename;
}
ImageProcessor::~ImageProcessor()
{
}
bool ImageProcessor::show(const std::string& window)
{
std::string pathname = this->filepath + this->filename;
cv::VideoCapture video(pathname);
auto frameTot = video.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_COUNT);
auto frameRate = video.get(cv::VideoCaptureProperties::CAP_PROP_FPS);
printf("frameTot=%f,frameRate=%f\n",frameTot, frameRate);
while(true) {
if (video.isOpened()) {
break;
}
}
while(frameTot) {
cv::Mat image;
if (!video.read(image)) {
printf("grab frame from video %s error\n", pathname.c_str());
continue;
}
cv::imshow(window, image);
cv::waitKey(1000/frameRate);
frameTot--;
}
return true;
}
main.cpp
#include "ImageProcessor.h"
using namespace opencv_app::image;
int main(int argc, char* argv[])
{
if (argc < 3) {
printf("Usage:./imageProcessor [filepath] [filename]\n");
return -1;
}
ImageProcessor imageProc(argv[1], argv[2]);
imageProc.show(argv[2]);
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(image_processor)
find_package(OpenCV REQUIRED)
add_executable(imageProcessor ./main.cpp ./ImageProcessor.cpp)
target_link_libraries(imageProcessor ${OpenCV_LIBS})