文章連接: http://blog.csdn.net/yhl_leo/article/details/49737357
python
本文僅對 Opencv圖像讀取與保存進行闡述,重在探討圖像讀取與保存過程當中應注意的細節問題。c++
首先看一下,imread函數的聲明:web
// 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++
版本號函數進行分析,形參列表包含:markdown
filename
: 待載入圖像(包含:文件路徑和文件名稱。圖像在project默認路徑下的可省略文件路徑);flags
: 標誌符,指定圖像載入顏色類型。默認值爲1:數據結構
假設你喜歡使用
imread("file.jpg")
缺省參數的形式載入圖像。務必要留意你所載入後的圖像可能已經不是你本來想要的圖像了。函數
從 Opencv源代碼枚舉類型中也可以看到上述標識符含義:post
ui
// 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已經支持眼下很是多圖像格式,但是並非全部。編碼
主要包含:spa
*.bmp
, *.dib
(always supported)*.jpeg
, *.jpg
, *.jpe
(see the Notes section)*.jp2
,*.jpf
,*.jpx
(see the Notes section)*.png
(see the Notes section)*.webp
(see the Notes section)*.pbm
, *.pgm
, *.ppm
(always supported)*.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庫,建議轉格式吧~
首先來看,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
:待保存圖像名(包含:文件路徑和文件名稱,圖像在project默認路徑下的可省略文件路徑);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. (The higher is the better)
IMWRITE_PNG_COMPRESSION =16, // compression level from 0 to 9, default value is 3. (A higher value means a smaller size and longer compression time. 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通道的圖像,但是對於不一樣的圖像格式。也是有差別的:
對於格式,或者位深或者通道順序與上面不一致的。可以使用函數Mat::convertTo()
和cvtColor()
函數進行轉換後,再保存。固然,也可以使用通用的方法利用FileStorage
I/O操做。將圖像存爲XML或YAML格式。
對於多通道圖像,假設想對其每個通道單獨進行保存,固然也是可行的。一方面本身可以依據圖像的信息和圖層信息寫出相應的存儲函數,還有一方面 Opencv也提供了專門的函數split
可以將圖像的每個通道提取出保存到vector
中:
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]);
附上 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;
}
執行結果爲: