2、Opencv加载、显示、保存图像

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对比
    2、Opencv加载、显示、保存图像
    2、Opencv加载、显示、保存图像

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::Texture2Dcuda::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 。入群飞机票

上一篇:最新整理的spring面试题从基础到高级,干货满满


下一篇:OpenCV Stitcher图像拼接