Opencv 图像读取与保存问题

本系列文章由 @yhl_leo 出品,转载请注明出处。

文章链接: http://blog.csdn.net/yhl_leo/article/details/49737357



本文仅对 Opencv图像读取与保存进行阐述,重在探讨图像读取与保存过程中应注意的细节问题。

1 图像读取

首先看一下,imread函数的声明:

// C++: Mat based
Mat imread(const string& filename, int flags=1 );

// C: IplImage based
IplImage* cvLoadImage(const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR );

// C: CvMat based
CvMat* cvLoadImageM(const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR );

此处,就不列出python的函数声明。随着2.x和3.x版本不断更新, Opencv的C++版本数据结构和C版本有较大差异,前者减少了指针的大量使用,用法更加便捷,因此建议多使用前者。以C++版本函数进行分析,形参列表包括:

  • filename : 待加载图像(包括:文件路径和文件名,图像在工程默认路径下的可省略文件路径);
  • flags : 标志符,指定图像加载颜色类型,默认值为1:
    • IMREAD_UNCHANGED / CV_LOAD_IMAGE_UNCHANGED :不加改变的加载原图。
    • IMREAD_GRAYSCALE / CV_LOAD_IMAGE_GRAYSCALE :图像转为灰度图(GRAY,1通道)。
    • IMREAD_COLOR / CV_LOAD_IMAGE_COLOR :图像转为彩色图(BGR,3通道)。
    • IMREAD_ANYDEPTH / CV_LOAD_IMAGE_ANYDEPTH :任何位深度,如果载入的图像不是16-bit位图或者32-bit位图,则转化为8-bit位图。
    • IMREAD_ANYCOLOR / CV_LOAD_IMAGE_ANYCOLOR :任何彩色,单独使用的时候等价于 IMREAD_UNCHANGED / CV_LOAD_IMAGE_UNCHANGED 。
    • > 0 :返回3通道的彩色图,但是如果是4通道(RGBA),其中Alpha需要保留的话,不建议这么使用,因为一旦这么使用,就会导致Alpha通道被剥离掉,此时建议使用负值。
    • = 0 :返回灰度图像。
    • < 0 :返回具有Alpha通道的图像。

如果你喜欢使用imread("file.jpg")缺省参数的形式加载图像,务必要留意你所加载后的图像可能已经不是你原本想要的图像了!

从 Opencv源码枚举类型中也可以看到上述标识符含义:

// highgui.hpp
enum
{
    // 8bit, color or not
    IMREAD_UNCHANGED  =-1,
    // 8bit, gray
    IMREAD_GRAYSCALE  =0,
    // ?, color
    IMREAD_COLOR      =1,
    // any depth, ?
    IMREAD_ANYDEPTH   =2,
    // ?, any color
    IMREAD_ANYCOLOR   =4
};

// highui_c.h
enum
{
/* 8bit, color or not */
    CV_LOAD_IMAGE_UNCHANGED  =-1,
/* 8bit, gray */
    CV_LOAD_IMAGE_GRAYSCALE  =0,
/* ?, color */
    CV_LOAD_IMAGE_COLOR      =1,
/* any depth, ? */
    CV_LOAD_IMAGE_ANYDEPTH   =2,
/* ?, any color */
    CV_LOAD_IMAGE_ANYCOLOR   =4
};

Opencv已经支持目前很多图像格式,但是并非全部。主要包括:

  • Windows bitmaps    ->    *.bmp, *.dib (always supported)
  • JPEG files    ->    *.jpeg, *.jpg, *.jpe (see the Notes section)
  • JPEG 2000 files    ->    *.jp2,*.jpf,*.jpx (see the Notes section)
  • Portable Network Graphics    ->    *.png (see the Notes section)
  • WebP    ->    *.webp (see the Notes section)
  • Portable image format    ->    *.pbm, *.pgm, *.ppm (always supported)
  • Sun rasters    ->    *.sr, *.ras (always supported)
  • TIFF files    ->    *.tiff, *.tif (see the Notes section)

    Notes

    • 1 The function determines the type of an image by the content, not by the file extension.
    • 2 On Microsoft Windows* OS and MacOSX*, the codecs shipped with an OpenCV image (libjpeg, libpng, libtiff, and libjasper) are used by default. So, OpenCV can always read JPEGs, PNGs, and TIFFs. On MacOSX, there is also an option to use native MacOSX image readers. But beware that currently these native image loaders give images with different pixel values because of the color management embedded into MacOSX.
    • 3 On Linux*, BSD flavors and other Unix-like open-source operating systems, OpenCV looks for codecs supplied with an OS image. Install the relevant packages (do not forget the development files, for example, “libjpeg-dev”, in Debian* and Ubuntu*) to get the codec support or turn on the OPENCV_BUILD_3RDPARTY_LIBS flag in CMake.
    • 4 In the case of color images, the decoded images will have the channels stored in B G R order.

对于常见的支持4通道的图像格式来说, Opencv读取结果是有差异的:

// 1.tif, 1.jp2 and 1.png are color images with 4 channels: R, G, B, A
cv::Mat imageTif = cv::imread("E:\\1.tif"); // the default flags is 1
cv::Mat imageJp2 = cv::imread("E:\\1.jp2"); // the default flags is 1
cv::Mat imagePng = cv::imread("E:\\1.png"); // the default flags is 1
std::cout << imageTif.channels() << std::endl; // prints 3
std::cout << imageJp2.channels() << std::endl; // prints 3
std::cout << imagePng.channels() << std::endl; // prints 3

cv::Mat imageTif2 = cv::imread("E:\\1.tif", -1); // flags = -1
cv::Mat imageJp22 = cv::imread("E:\\1.jp2", -1);
cv::Mat imagePng2 = cv::imread("E:\\1.png", -1);
std::cout << imageTif2.channels() << std::endl; // prints 3
std::cout << imageJp22.channels() << std::endl; // prints 3
std::cout << imagePng2.channels() << std::endl; // prints 4

由此可见,目前 Opencv能够直接读取4通道图像并保留Alpha通道的貌似只有PNG格式,对于非PNG格式数据,需要保留Alpha通道的应用,如果坚持使用 Opencv库,建议转格式吧~

2 图像存储

首先来看,imwrite函数的声明:

// c++: Mat based
bool imwrite(const string& filename, InputArray img, const vector<int>& params=vector<int>() );

// C: CvMat and IplImage based
int cvSaveImage(const char* filename, const CvArr* image, const int* params=0 );

仍旧以C++版本为例,其形参列表为:

  • filename:待保存图像名(包括:文件路径和文件名,图像在工程默认路径下的可省略文件路径);
  • img:待保存的图像对象;
  • params :特定图像存储编码参数设置,以类似pairs类型的方式,(paramId_1, paramValue_1)(paramId_2, paramValue_2)…,其中paramId_1就是标志符值,paramValue_1标识符值对应的后续参数设置:
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION); // paramId_1, png compression
compression_params.push_back(9);                          // paramValue_2, compression level is 9

在 Opencv中,主要对JPEG,PNG和PXM的编码方式进行了特别声明:

// highgui.hpp
enum
{
    IMWRITE_JPEG_QUALITY =1,         // quality from 0 to 100, default value is 95.
    IMWRITE_PNG_COMPRESSION =16,     // compression level from 0 to 9, default value is 3.
    IMWRITE_PNG_STRATEGY =17,
    IMWRITE_PNG_BILEVEL =18,
    IMWRITE_PNG_STRATEGY_DEFAULT =0,
    IMWRITE_PNG_STRATEGY_FILTERED =1,
    IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY =2,
    IMWRITE_PNG_STRATEGY_RLE =3,
    IMWRITE_PNG_STRATEGY_FIXED =4,
    IMWRITE_PXM_BINARY =32          // binary format flag: 0 or 1, default value is 1.
};

// highui_c.h
enum
{
    CV_IMWRITE_JPEG_QUALITY =1,
    CV_IMWRITE_PNG_COMPRESSION =16,
    CV_IMWRITE_PNG_STRATEGY =17,
    CV_IMWRITE_PNG_BILEVEL =18,
    CV_IMWRITE_PNG_STRATEGY_DEFAULT =0,
    CV_IMWRITE_PNG_STRATEGY_FILTERED =1,
    CV_IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY =2,
    CV_IMWRITE_PNG_STRATEGY_RLE =3,
    CV_IMWRITE_PNG_STRATEGY_FIXED =4,
    CV_IMWRITE_PXM_BINARY =32
};

上述的标识符含义,显而易见,就不累述。值得强调的是,imwrite函数支持存储的图像类型是有限的只包括:1,3,4通道的图像,但是对于不同的图像格式,也是有差异的:

  • 对于单通道8-bit位图(或者16-bit位图( CV_16U/CV_16UC1 的PNG,JPEG 2000 和TIFF))或者3通道(通道顺序为:B G R )的图像,imwrite函数是都支持的。对于格式,或者位深或者通道顺序与上面不一致的,可以使用函数Mat::convertTo()cvtColor()函数进行转换后,再保存。当然,也可以使用通用的方法利用FileStorageI/O操作,将图像存为XML或YAML格式
  • 对于PNG图像,可以保存其Alpha通道,创建一个8-bit或者16-bit 4通道的位图(通道顺序为:B G R A ),如果是全透明的Alpha通道设置为0,反之不透明设置为255/65535。

对于多通道图像,如果想对其每个通道单独进行保存,当然也是可行的,一方面自己可以根据图像的信息和图层信息写出相应的存储函数,另一方面 Opencv也提供了专门的函数split可以将图像的每个通道提取出保存到vector中:

PNG原图

cv::Mat img = imread( "C:\\Users\\Leo\\Desktop\\Panda.png", CV_LOAD_IMAGE_UNCHANGED );

std::vector<cv::Mat> imageChannels;
cv::split( img, imageChannels );
cv::imwrite("E:\\0.jpg", imageChannels[0]);
cv::imwrite("E:\\1.jpg", imageChannels[1]);
cv::imwrite("E:\\2.jpg", imageChannels[2]);
cv::imwrite("E:\\3.jpg", imageChannels[3]);

B G R A

通道分离保存结果

附上 Opencv文档源码:

#include <vector>
#include <stdio.h>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

void createAlphaMat(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);
            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 argv, char **argc)
{
    // Create mat with alpha channel
    Mat mat(480, 640, CV_8UC4);
    createAlphaMat(mat);

    vector<int> compression_params;
    compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
    compression_params.push_back(9);

    try {
        imwrite("alpha.png", mat, compression_params);
    }
    catch (runtime_error& ex) {
        fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what());
        return 1;
    }

    fprintf(stdout, "Saved PNG file with alpha data.\n");
    return 0;
}

运行结果为:

时间: 2024-10-22 17:18:08

Opencv 图像读取与保存问题的相关文章

在opencv下读取视频保存为图片

VideoCapture capture; capture.open("D:\\car.avi");//读取视频 对于视频下一帧的读取: capture>>frameImg;//读取视频流下一帧控制,字符重载 对于视频的图片保存 std::stringstream ss;//存储图片路径保存信息 ss<<"D:/output/image_"<<setfill('0')<<setw(3)<<(nCount-1

利用Python PIL、cPickle读取和保存图像数据库

利用Python PIL.cPickle读取和保存图像数据库  @author:wepon @blog:http://blog.csdn.net/u012162613/article/details/43226127 计算机视觉.机器学习任务中,经常跟图像打交道,在C++上有成熟的OpenCV可以使用,在Python中也有一个图像处理库PIL(Python Image Library),当然PIL没有OpenCV那么多功能(比如一些人脸检测的算法),不过在Python上,我们用PIL进行一些基本

opencv入门基础——图像读取,图像显示,图像保存

一,图像读取 如上图所示,从文件中导入图像用这个函数 retval=cv.imread(文件名,[,显示控制参数]) 显示控制参数,主要是这几个: cv.IMREAD_UNCHANGED cv.IMREAD_GRAYSCALE cv.IMREAD_COLOR 主要是控制读取的图片以灰度图的形式出现还是以彩色图的形式出现. 以下还有更多的其他控制参数:如图 二.图像显示 1. 如上图所示,显示图像用这个函数 None=cv.imshow(窗口名,图像名) 注:窗口名尽量不用中文,否则可能会报错 2

【opencv系列02】OpenCV4.X图像读取与显示

一.读取图片 opencv中采用imread() 函数读取图像 imread(filename, flags=None) ????filename 图片的路径 ????flags 图像读取方式 ● cv2.IMREAD_COLOR : 加载彩色图像, 图像的任何透明度都将被忽略(默认). ● cv2.IMREAD_GRAYSCALE : 以灰度模式加载图像. ● cv2.IMREAD_UNCHANGED : 加载包含Alpha通道的图像. 也可以使用1, 0 or -1代替,源码中,IMREAD

OpenCV图像视频编程框架

? ? ? 接触OpenCV好几年了,一直只用OpenCV读入图像.视频,显示图像或者视频,由于公司图像算法都属于前端应用,因此一直没有使用OpenCV的内置函数,所有算法均要转化到C下面.所以目的很明确,OpenCV对于我来说就是一个Demo演示和调试工具. OpenCV :图像读取,图像保存,图像显示,视频读取,视频保存,鼠标画点.画圆.画矩形.画图. 1)图像保存 ? ? ? 为了方便每次都sprintf拼写图像路径,采用如下定义: ? ? ? void cvSaveImageNow(Ip

opencv播放,变换和保存视频

核心函数: 1. cvCreateFileCapture 2. cvGetCaptureProperty 3. cvQueryFrame 4. cvCreateVideoWriter 5. cvWriteFrame 程序: #include "cv.h" #include "cxcore.h" #include "highgui.h" #include <iostream> #include <stdio.h> int V

关于图像读取函数imread()的一点使用经验,注意默认参数的赋值

读入数字图像到数组,用CNN进行训练,发现关于图像读取的一个问题. 问题描述:读取灰度数字图像,在验证时发现存在错误,从图像到数组中的值不完全一样? main code as follows: int dst_width = 12, dst_height = 17;//set the dst size int vec_Num = dst_width*dst_height; /*the second parameter must set when read gray image, //the de

[转]OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

[OpenCV入门教程之十三]OpenCV图像金字塔:高斯金字塔.拉普拉斯金字塔与图片尺寸缩放 2014-05-18 18:58 36007人阅读 评论(54) 收藏 举报 本文章已收录于:  OpenCV知识库 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 知乎:http

【OpenCV入门教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 知乎:http://www.zhihu.com/people/mao-xing-yun 邮箱: [email protected] 写作当前博文时配套使用的OpenCV版本: 2.4.9 这篇文章里,我们将一起探讨图像金字塔的一