Opencv加载、显示、保存图像
一、Opencv加载图像
1、所用函数原型:
Mat cv::imread(const String & filename,
int flags = IMREAD_COLOR)
功能介绍:函数imread从指定的文件中加载一个图像并返回它。如果图像不能被读取(因为文件丢失、权限不当、不支持或无效格式),函数返回一个空矩阵(Mat::data==NULL)
参数 filename:指定希望读取图像的路径,可以为相对路径和绝对路径
参数 flags:指定读取图像的格式。该值枚举自 cv::ImreadModes,默认值为1。具体见下表
枚举类型 | 枚举值 | 类型描述 |
---|---|---|
IMREAD_UNCHANGED | -1 | 将加载的图像按原样返回,包括alpha通道。会忽略EXIF方向 |
IMREAD_GRAYSCALE | 0 | 编解码器内部将图像转换为单通道灰度图像返回 |
IMREAD_COLOR | 1 | 将图像转换为RGB通道排列的彩色图像,该值是函数的默认值 |
IMREAD_ANYDEPTH | 2 | 如果图像具有深度,则返回对应的16/32位图像。否则转换为8位返回 |
IMREAD_ANYCOLOR | 4 | 图像以任何可能的颜色读取 |
IMREAD_LOAD_GDAL | 8 | 使用gdal驱动程序加载图像 |
IMREAD_REDUCED_GRAYSCALE_2 | 16 | 将图像转换为单通道的灰度图像,图像的尺寸缩小为1/2 |
IMREAD_REDUCED_COLOR_2 | 17 | 将图像转换为RGB通道排列的彩色图像,图像尺寸缩小为1/2 |
IMREAD_REDUCED_GRAYSCALE_4 | 32 | 将图像转换为单通道的灰度图像,图像的尺寸缩小为1/4 |
IMREAD_REDUCED_COLOR_4 | 33 | 将图像转换为RGB通道排列的彩色图像,图像尺寸缩小为1/4 |
IMREAD_REDUCED_GRAYSCALE_8 | 64 | 将图像转换为单通道的灰度图像,图像的尺寸缩小为1/8 |
IMREAD_REDUCED_COLOR_8 | 65 | 将图像转换为RGB通道排列的彩色图像,图像尺寸缩小为1/8 |
IMREAD_IGNORE_ORIENTATION | 128 | 不要根据EXIF的方向标志旋转图像 |
注意:上表中的参数,我们常用的为前三个,其它参数不必去刻意记住。用的时候查询即可
2、对于图片路径的参数,在测试案例中,我们通常会用到函数:
cv::String cv::samples::findFile (const cv::String & relative_path,
bool required = true,
bool silentMode = false)
该函数会到相关路径下去找到相关的图片,这个相关路径通常涵盖以下路径:
- 通过 addSamplesDataSearchPath()函数传递的目录。
- OPENCV_SAMPLES_DATA_PATH_HINT环境变量所在的目录。
- OPENCV_SAMPLES_DATA_PATH环境变量所在目录。
- 当前工作目录,或者说是生成的二进制可执行文件所在目录。
- 如果检测到构建目录,或当前目录在源树中,则选择目录/{,data,samples/data}
- 如果检测到安装目录,则浏览 /share/OpenCV 目录。
该函数与 cv::utils::findDataFile 函数的功能一致。此处不赘述。返回图片所在路径。
- 参数 relative_path:指明文件的路径,可以只是一个图片名,如”lena.jpg“
- 参数 required:说明未找到指定数据后的处理方式,取true时会抛出 cv::Exception 异常,取false时会返回空对象。
-
参数 silentMode:禁用消息。即是否在信息台输出查找消息,下图分别是取值为 true 和 false对比
3、函数调用示例代码(C++):
Mat src = imread(samples::findFile("lena.jpg",true,true), IMREAD_COLOR);
4、Opencv所支持的图像类型说明:
- Windows bitmaps : *.bmp, *.dib
- JPEG files :*.jpeg *.jpg, *.jpe
- JPEG 2000 files : *.jp2
- Portable Network Graphics : *.png
- WebP : *.webp
- 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
- GDAL支持的栅格和矢量地理空间数据
注意:
- 该函数根据内容而不是文件扩展名确定图像的类型
- 对于彩色图像,解码后的图像将按B G R顺序存储
- 当使用IMREAD_GRAYSCALE时,如果可用,将使用编解码器的内部灰度转换。结果可能与cvtColor()的输出不同
- 在Microsoft Windows* OS和MacOSX*上,OpenCV图像附带的编解码器(libjpeg, libpng, libtiff和libjasper)是默认使用的。因此,OpenCV总是可以读取jpeg、png和tiff。在MacOSX上,还有一个使用本地MacOSX图像阅读器的选项。但是要注意,由于MacOSX内置了颜色管理功能,这些本机图像加载器给出的图像具有不同的像素值
- 在Linux*、BSD风格和其他类unix的开源操作系统上,OpenCV寻找与操作系统映像一起提供的编解码器
- 如果你在CMake和IMREAD_LOAD_GDAL中设置WITH_GDAL标志为true来加载图像,那么GDAL驱动程序将用于解码图像,支持以下格式:Raster, Vector
- 如果图像文件中嵌入了EXIF信息,EXIF方向将被考虑进去,因此图像将相应地旋转,除非传递了标志IMREAD_IGNORE_ORIENTATION或IMREAD_UNCHANGED
- 使用IMREAD_UNCHANGED标志来保存PFM图像中的浮点值
- 默认情况下,像素的数量必须小于2的30次方。可以使用系统变量OPENCV_IO_MAX_IMAGE_PIXELS设置限制
二、判断图像是否加载成功
判断图像读取内容是否为空的方法有以下两种:
1、调用 Mat 对象的 empty() 方法。如:src.empty()
通常将该函数的返回值放到 if 的判断逻辑中,如果为真,表示读取图像内容为空,则处理:
if (src.empty())
{
fprintf(stderr, "Failed oepen image: lena.jpg\n");
return EXIT_FAILURE;
}
2、看 Mat 对象的data属性是否为空,如:src.data
if (!src.data)
{
fprintf(stderr, "Failed oepen image: lena.jpg\n");
return EXIT_FAILURE;
}
三、窗体显示图片
1、所用函数原型:
void cv::imshow (const String & winname,
InputArray mat)
- 参数 winname:指定显示窗体的名称,为String类型,如”demo“
- 参数 mat:希望显示图像的Mat对象,此处为InputArray类型,其实和Mat都为同一个东西。
函数imshow在指定的窗口中显示图像。如果窗口是用cv::WINDOW_AUTOSIZE标志创建的,图像将以原始大小显示,但是它仍然受到屏幕分辨率的限制。否则,图像将被缩放以适应窗口。函数可以根据图像的深度对图像进行缩放:
- 如果图像为8位无符号图像,则显示为原样。
- 如果图像为16位无符号或32位整数,则像素除以256,将取值范围[0,255*256]映射为[0,255]
- 如果图像为32位或64位浮点数时,则像素值乘以256,将取值范围[0,1]映射为[0,255]
- 如果创建的窗口支持OpenGL, cv::imshow也支持ogl::Buffer, ogl::Texture2D和cuda::GpuMat作为输入
- 如果在此函数之前没有创建窗口,则假定它创建了一个带有cv::WINDOW_AUTOSIZE的窗口
- 如果你需要显示一个比屏幕分辨率大的图像,你需要在imshow之前调用
namedWindow("", WINDOW_NORMAL)
2、调用 waitKey() 函数等待用户输入,否则图像显示会一闪而过。
int cv::waitKey (int delay = 0)
该函数会等待 delay所指示的时间间隔后,执行后续指令。返回用户所按的键值,通常与ASCII相关联。如果delay≤0,则表示无限制等待。否则等待时间为delay值,单位毫秒。由于线程间的切换存在着时间消耗,所以该等待时间不会严格等于delay,与当前系统执行的任务等有关。
3、调用实例:
namedWindow("demo", WINDOW_AUTOSIZE);
imshow("demo", src);
waitKey(0);
注意此处我在显示之前调用namedWindow函数新建了一个窗口,这一步不是必须,后续会解释其用处。
四、保存图像
1、所用函数原型:
bool cv::imwrite (const String & filename,
InputArray img,
const std::vector< int > & params = std::vector< int >())
函数imwrite将img所指代的图像保存到指定的文件中(filename)。图像格式是根据文件名扩展名选择的。一般情况下,使用该函数只能保存8位单通道或3通道(通道顺序为BGR)的图像,但有以下几种例外情况:
- CV_16U :图片保存格式为 PNG, JPEG 2000 和 TIFF 格式
- CV_32F : 图片保存为 PFM, TIFF, OpenEXR, 和 Radiance HDR 格式
- CV_32FC3: TIFF图像将使用LogLuv高动态范围编码(每像素4字节)保存
- 带有alpha通道的PNG图像可以使用此函数保存。为此,创建8位(或16位)4通道的BGRA图像, alpha通道位于最后。完全透明像素的alpha值应该设置为0,完全不透明像素的alpha值应该设置为255/65535
- 多个图像(Mat类型的vector)可以保存为TIFF格式
参数 filename:指示文件的名称,包含后缀。写入图像支持的格式与读入支持的格式一致
参数 img:需要保存的图像或图像数组(vector)
参数 params:特定于图像保存格式的参数编码对,参数类型为int 构成的vector,其值枚举自 cv::ImwriteFlags,见下表:
枚举类型 | 枚举值 | 类型说明 |
---|---|---|
IMWRITE_JPEG_QUALITY | 1 | 对于JPEG,它的取值可以是0到100(越高越好)。默认值为95 |
IMWRITE_JPEG_PROGRESSIVE | 2 | 启用JPEG特性,0或1,默认为False |
IMWRITE_JPEG_OPTIMIZE | 3 | 启用JPEG特性,0或1,默认为False |
IMWRITE_JPEG_RST_INTERVAL | 4 | JPEG重启间隔,0 - 65535,默认为0 表示不重启 |
IMWRITE_JPEG_LUMA_QUALITY | 5 | 单独的亮度质量等级,0 - 100,默认为0 表示不使用 |
IMWRITE_JPEG_CHROMA_QUALITY | 6 | 单独的色度质量级别,0 - 100,默认为0 表示不使用 |
IMWRITE_PNG_COMPRESSION | 16 | PNG格式的压缩级别为0 ~ 9。数值越高,压缩时间越长。如果指定了,strategy会变为IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY)。默认值为1(最佳速度) |
IMWRITE_PNG_STRATEGY | 17 | cv::ImwritePNGFlags的一种,默认为IMWRITE_PNG_STRATEGY_RLE。 |
IMWRITE_PNG_BILEVEL | 18 | 二值PNG, 0或1,默认为0 |
IMWRITE_PXM_BINARY | 32 | 对于PPM、PGM或PBM,可以是二进制格式标志0或1。默认值为1 |
IMWRITE_EXR_TYPE | EXR存储类型(默认为FLOAT (FP32)) | |
IMWRITE_WEBP_QUALITY | 64 | 对于WEBP,它的质量可以从1到100(越高越好)。默认情况下(没有任何参数),如果质量超过100,则使用无损压缩。 |
IMWRITE_PAM_TUPLETYPE | 128 | 对于PAM,将TUPLETYPE字段设为为该格式定义的对应字符串值 |
IMWRITE_TIFF_RESUNIT | 256 | 对于TIFF格式,使用指定要设置的DPI分辨率单元;有关有效值,请参阅libtiff文档 |
IMWRITE_TIFF_XDPI | 257 | 对于TIFF,用于指定X方向DPI |
IMWRITE_TIFF_YDPI | 258 | 对于TIFF,用于指定Y方向DPI |
IMWRITE_TIFF_COMPRESSION | 259 | 对于TIFF格式,用于指定图像压缩方案。有关压缩格式对应的整数常量,请参阅libtiff。注意,对于深度为CV_32F的图像,只使用libtiff的SGILOG压缩方案。对于其他支持的深度,压缩方案可以由这个标志指定;默认为LZW压缩 |
IMWRITE_JPEG2000_COMPRESSION_X1000 | 272 | 对于JPEG2000,使用指定目标压缩率(乘以1000)。取值范围为0 ~ 1000。默认是1000 |
2、简单调用代码:
int k =waitKey(0);
if (k == 's')
{
imwrite("O:\\image\\test.jpg", src);
}
五、完整代码示例
// 只include一个hpp即可,可以自行查看该文件,包含了所有的hpp
#include<opencv2/opencv.hpp>
// 引入命名空间后,使用opencv的方法时就不需要特定指定cv::? 了
using namespace cv;
int main(int argc, char** argv)
{
// 调用imrad函数读取名为”lena.jpg“的图像,该图像在系统的搜索路径下,图像打开格式为IMREAD_COLOR
Mat src = imread(samples::findFile("lena.jpg",true,true), IMREAD_COLOR);
// 判读读入的图像内容是否为空
if (!src.data)
{
fprintf(stderr, "Failed oepen image: lena.jpg\n");
return EXIT_FAILURE;
}
// 新命名一个窗口,窗体的大小根据图像大小自动调整
namedWindow("demo", WINDOW_AUTOSIZE);
// 在名为”demo“的窗体上显示src所指向的图像
imshow("demo", src);
// 一直等待用户按键,按键的返回值存入变量k
int k =waitKey(0);
// 如果用户按下了's'键,则在相应路径下保存图片
if (k == 's')
{
// 调用imwrite保存图像
imwrite("O:\\image\\test.jpg", src);
}
system("pause");
return EXIT_SUCCESS;
}
六、其它关于图像保存的代码例子
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
// 自定义函数生成带alpha通道的图像
static void paintAlphaMat(Mat& mat)
{
// 判断形参mat的通道数是否符合要求
CV_Assert(mat.channels() == 4);
// 为每一个通道赋值,注意图像的内容是按行存储,所以外层循环通常控制行
for (int i = 0; i < mat.rows; ++i)
{
for (int j = 0; j < mat.cols; ++j)
{
Vec4b& bgra = mat.at<Vec4b>(i, j);
// 分别设置 B G R A 通道的像素值
bgra[0] = UCHAR_MAX; // Blue
bgra[1] = saturate_cast<uchar>((float(mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX); // Green
bgra[2] = saturate_cast<uchar>((float(mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX); // Red
bgra[3] = saturate_cast<uchar>(0.5 * (bgra[1] + bgra[2])); // Alpha
}
}
}
int main(int argc,char **argv)
{
// 自定义一个名为mat的Mat对象,尺寸为480*640,数据类型为CV_8UC4,表示无符号的8位4通道图
Mat mat(480, 640, CV_8UC4);
// 调用自定义函数生成带alpha通道的图像
paintAlphaMat(mat);
// 定义int元素类型的vector变量compression_params作为保存图片时的参数
vector<int> compression_params;
compression_params.push_back(IMWRITE_PNG_COMPRESSION);
compression_params.push_back(9);
// result用于接受保存图像的结果,成功为true ,失败为false
bool result = false;
try
{
result = imwrite("alpha.png", mat, compression_params);
}
catch (const cv::Exception & ex)
{
fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what());
}
if (result)
printf("Saved PNG file with alpha data.\n");
else
printf("ERROR: Can't save PNG file.\n");
// 定义Mat元素类型的vector变量imgs
vector<Mat> imgs;
imgs.push_back(mat);
imgs.push_back(~mat);
imgs.push_back(mat(Rect(0, 0, mat.cols / 2, mat.rows / 2)));
imwrite("test.tiff", imgs);
printf("Multiple files saved in test.tiff\n");
system("pause");
return result ? 0 : 1;
}
七、致谢
1、还是感谢CCTV,感谢所有支持的朋友
2、有兴趣探讨一起学习的欢迎入群 725027506 。入群飞机票