本节主要翻译自OpenCV的帮助资料,并结合一些编程考量。
D、基本输入输出函数
- imread(fln),imwrite(fln,img);
函数原型:
Mat cv::imread(const String &filename, int flags = IMREAD_COLOR );
从文件中装入图像
函数imread从指定的文件中加载图像并返回一个Mat类型的图像对象。如果加载失败(由于文件错,不合适的权限,不支持或不可用的格式),这个函数返回空矩阵( Mat::data==NULL )。
当前版本的openCV中这个函数支持下列格式的图像文件:
- Windows 位图 - *.bmp, *.dib (总是支持的格式)
- JPEG 文件 - *.jpeg, *.jpg, *.jpe(见注释节)
- JPEG 2000 文件 - *.jp2 (见注释节)
- 便携网络图文件 - *.png (见注释节)
- WebP - *.webp (见注释节)
- 便携图像格式 - *.pbm, *.pgm, *.ppm *.pxm, *.pnm (总是支持的格式)
- PFM 文件 - *.pfm (见注释节)
- Sun光栅文件 - *.sr, *.ras (总是支持的格式)
- TIFF 文件 - *.tiff, *.tif (见注释节)
- OpenEXR 图像文件 - *.exr (见注释节)
- 辐射HDR - *.hdr, *.pic (总是支持的格式)
- 由GDAL所支持的光栅和向量几何数据(见注释节)
注释
- 这个函数通过内容确定图像类型,而不是通过文件的扩展名。
- 在彩色图像中解码图像使用B G R 顺序存储图像的彩色通道。
- 在使用IMREAD_GRAYSCALE图像标志时,也可能使用编解码器内部的灰度转换,此时的结果可能与cvtColor()的输出不一样。
- 在微软的Windows OS 和MacOSX*下,编解码器默认使用附带的OpenCV图像(libjpeg, libpng, libtiff, and libjasper)库。所以OpenCV 总是能读取JPEGs, PNGs, 和TIFFs。在MacOSX下,还可以允许选择MacOSX原生的图像读取器。但是要当心,到现在为止,这些原生的图像加载器获得的图像具有不同的像素值,这是因为嵌入到MacOSX内的色彩管理操作是有差异的。
- 对于Linux,BSD风格和其它类Unix的开源操作系统,OpenCV查找操作系统支持的图像编解码器。一定要记得安装相关的包(不要忘了这些开发文件,如,"libjpeg-dev",在Debian 和Ubuntu中)以便获得编解码的支持或者在CMake中打开OPENCV_BUILD_3RDPARTY_LIBS标志开关。
- 在CMake设置WITH_GDAL 标志为true,且使用IMREAD_LOAD_GDAL 来加载图像时,GDAL 驱动器将用于解码图像,支持: Raster, Vector格式。
- 如果EXIF信息嵌入到图像文件中,就要考虑EXIF的朝向,因而,图像将依据EXIF进行旋转,除非传输了IMREAD_IGNORE_ORIENTATION 或 IMREAD_UNCHANGED 标志。
- 使用IMREAD_UNCHANGED 标志来保持PFM图像的浮点值。
- 默认情况下像素数必需小于2^30。这个限制可以使用OPENCV_IO_MAX_IMAGE_PIXELS进行设置。
参数
filename |
装入的文件名。 |
flags |
标志,可以取值于cv::ImreadModes |
cv::ImreadModes { cv::IMREAD_UNCHANGED = -1, |
|
|
|
IMREAD_UNCHANGED Python: cv.IMREAD_UNCHANGED |
如果设置,返回加载的源图,(对alpha通道保留,否则裁剪掉)。不考虑EXIF朝向。 |
IMREAD_GRAYSCALE Python: cv.IMREAD_GRAYSCALE |
如果设置,总是转换图像到单一通道的灰度图(编解码器内部转换)。 |
IMREAD_COLOR Python: cv.IMREAD_COLOR |
如果设置,总是转换图像到3通道BGR的彩色图。 |
IMREAD_ANYDEPTH Python: cv.IMREAD_ANYDEPTH |
如果设置,在输入有对应深度时返回16-bit/32-bit图像,否则转换成8-bit图像。 |
IMREAD_ANYCOLOR Python: cv.IMREAD_ANYCOLOR |
如果设置,图像以任何可能的彩色格式读取。 |
IMREAD_LOAD_GDAL Python: cv.IMREAD_LOAD_GDAL |
如果设置,使用gdal驱动器装载图像。 |
IMREAD_REDUCED_GRAYSCALE_2 Python: cv.IMREAD_REDUCED_GRAYSCALE_2 |
如果设置,总是转换图像到单通道灰度图像,并且图像尺寸缩减1/2。 |
IMREAD_REDUCED_COLOR_2 Python: cv.IMREAD_REDUCED_COLOR_2 |
如果设置,总是转换图像到3通道BGR彩色图像,并且图像尺寸缩减1/2。 |
IMREAD_REDUCED_GRAYSCALE_4 Python: cv.IMREAD_REDUCED_GRAYSCALE_4 |
如果设置,总是转换图像到单通道灰度图像,并且图像尺寸缩减1/4。 |
IMREAD_REDUCED_COLOR_4 Python: cv.IMREAD_REDUCED_COLOR_4 |
如果设置,总是转换图像到3通道BGR彩色图像,并且图像尺寸缩减1/4。 |
IMREAD_REDUCED_GRAYSCALE_8 Python: cv.IMREAD_REDUCED_GRAYSCALE_8 |
如果设置,总是转换图像到单通道灰度图像,并且图像尺寸缩减1/8。 |
IMREAD_REDUCED_COLOR_8 Python: cv.IMREAD_REDUCED_COLOR_8 |
如果设置,总是转换图像到3通道BGR彩色图像,并且图像尺寸缩减1/8。 |
IMREAD_IGNORE_ORIENTATION Python: cv.IMREAD_IGNORE_ORIENTATION |
如果设置,不依据EXIF朝向标志旋转图像。 |
bool cv::imwrite(const String & filename, InputArray img, const std::vector<int> & params=std::vector< int >()
);
保存图像到指定的文件。
函数imwrite()保存图像到指定的文件。图像格式以选择的文件名扩展为准(参见cv::imread中文件名扩展的列表)。一般而言,只有8位单通道或3通道(BGR通道顺序)图像可以使用这个函数保存,除此之外还可以有:
- 16位无符号(CV_16U)图像可以存储成PNG,JPEG 2000,和TIFF格式
- 32位浮点(CV_32F)图像可以存储成PFM,TIFF,OpenEXR,和辐射HDR格式;3通道(CV_32FC3) TIFF 图像则存储成LogLuv高动态变幅编码(每像素4字节)格式。
- 具有alpha 通道的PNG图像可以使用这个函数存储。此时可建立8位(或16位) 4通道图像BGRA,其中alpha通道排在最后。完全透明的像素的alpha设置到0,完全不透明像素的alpha设置到255/65535(参见下面的示例代码)。
如果格式的深度或通道顺序不同,需使用 Mat::convertTo 和 cv::cvtColor 在保存之前进行转换。也可通过FileStorage I/O 函数保存图像到XML 或 YAML 格式。
下面的示例给出建立BGRA 图像并存储成PNG 文件的例子。 它还展示了怎样设置图像的压缩参数:
#include <opencv2/imgcodecs.hpp>
using namespace cv;
using namespace std;
static 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; // 蓝
bgra[1] = saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX); // 绿
bgra[2] = saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX); // 红
bgra[3] = saturate_cast<uchar>(0.5 * (bgra[1] + bgra[2])); // Alpha
}
}
}
int main()
{
//建立具有alpha通道的矩阵
Mat mat(480, 640, CV_8UC4);
createAlphaMat(mat);
vector<int> compression_params;
compression_params.push_back(IMWRITE_PNG_COMPRESSION);
compression_params.push_back(9);
bool result = false;
try{
result = imwrite("alpha.png", mat, compression_params);
}catch (const cv::Exception& ex){
fprintf(stderr, "转换图像到PNG格式出现异常: %s\n", ex.what());
}
if (result)
printf("存储成具有alpha数据的PNG格式文件.\n");
else
printf("错误: 不能存储成PNG格式文件.\n");
return result ? 0 : 1;
}
参数
filename |
文件名 |
img |
要存储的图像 |
params |
格式指定的编码参数使用名-值对(paramId_1, paramValue_1, paramId_2, paramValue_2, ... .) 参见 cv::ImwriteFlags |
cv::ImwriteFlags { } |
IMWRITE_JPEG_QUALITY Python: cv.IMWRITE_JPEG_QUALITY |
JPEG图像的存储质量0 - 100 (越高越好)。默认为95。 |
IMWRITE_JPEG_PROGRESSIVE Python: cv.IMWRITE_JPEG_PROGRESSIVE |
允许的JPEG属性,0/1,默认为False。 |
IMWRITE_JPEG_OPTIMIZE Python: cv.IMWRITE_JPEG_OPTIMIZE |
允许的JPEG属性,0/1,默认为False. |
IMWRITE_JPEG_RST_INTERVAL Python: cv.IMWRITE_JPEG_RST_INTERVAL |
JPEG重启间隔,0 – 65535,默认为0 – 无重起。 |
IMWRITE_JPEG_LUMA_QUALITY Python: cv.IMWRITE_JPEG_LUMA_QUALITY |
不同的流明质量级,0 – 100,默认为0 – 不使用。 |
IMWRITE_JPEG_CHROMA_QUALITY Python: cv.IMWRITE_JPEG_CHROMA_QUALITY |
不同的浓度质量级,0 – 100,默认为0 – 不使用。 |
IMWRITE_PNG_COMPRESSION Python: cv.IMWRITE_PNG_COMPRESSION |
对于PNG格式,标识压缩级别从0 到9。较高的值说明较小的图像文件尺寸和较长的压缩时间。如果指定,压缩策略变为IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY)。默认值为1 (最快的速度)。 |
IMWRITE_PNG_STRATEGY Python: cv.IMWRITE_PNG_STRATEGY |
cv::ImwritePNGFlags标志之一 ,默认为IMWRITE_PNG_STRATEGY_RLE。 |
IMWRITE_PNG_BILEVEL Python: cv.IMWRITE_PNG_BILEVEL |
二进制层的PNG,0 或1,默认为0。 |
IMWRITE_PXM_BINARY Python: cv.IMWRITE_PXM_BINARY |
对PPM,PGM,或PBM,可以为二进制格式标志,0 或 1。默认为1。 |
IMWRITE_EXR_TYPE Python: cv.IMWRITE_EXR_TYPE |
|
IMWRITE_WEBP_QUALITY Python: cv.IMWRITE_WEBP_QUALITY |
重载EXR存储类型(FLOAT,默认为 (FP32) ) 对于WEBP,可以是1到100的质量值(越高越好)。默认(没有任何参数)和大于100的值,使用最低压缩形式。 |
IMWRITE_PAM_TUPLETYPE Python: cv.IMWRITE_PAM_TUPLETYPE |
对于PAM,设置TUPLETYPE字段用对应串值定义使用的格式。. |
IMWRITE_TIFF_RESUNIT Python: cv.IMWRITE_TIFF_RESUNIT |
对于TIFF,用于指定DPI分辨率单位;参见libtiff 资料设置可用的值。 |
IMWRITE_TIFF_XDPI Python: cv.IMWRITE_TIFF_XDPI |
对于TIFF,用于指定X方向的DPI。 |
IMWRITE_TIFF_YDPI Python: cv.IMWRITE_TIFF_YDPI |
对于TIFF,用于指定Y方向上的DPI。 |
IMWRITE_TIFF_COMPRESSION Python: cv.IMWRITE_TIFF_COMPRESSION |
对于TIFF,用于指定图像压缩策略。参见libtiff 的整数内容对应的压缩格式。注意,对于深度为CV_32F的图像,仅仅libtiff 的SGILOG压缩策略可用。对于其它支持的深度,压缩策略可以由这个标志指定;LZW压缩标识是默认选择。 |
IMWRITE_JPEG2000_COMPRESSION_X1000 Python: cv.IMWRITE_JPEG2000_COMPRESSION_X1000 |
对于JPEG2000,用于指定目标压缩率(乘以1000)。可以指定从0 到1000。默认为1000。 |
- cv::imshow (const String &winname, InputArray mat);
在指定窗口中显示图像。
函数imshow()在指定窗口中显示图像。如果窗口使用cv::WINDOW_AUTOSIZE标志建立,图像将以其初始的尺寸显示,此时,图像将受到屏幕分辨率的限制。反之图像将以适合窗口大小的尺寸压缩显示。这个函数可以使用相关的深度标识图像。
- 如果图像为8位无符号,它就被实际显示(无任何转换)
- 如果图像为16位无符号或32位整数,像素被256除。即,值范围在[0,255*256]被映射到[0,255]。
- 如果图像为32位或64位浮点数,像素值乘以255。即,值范围在[0,1]被映射到[0,255]。
如果窗口是以OpenGL支持的方式建立,cv::imshow 也支持 ogl::Buffer , ogl::Texture2D 和 cuda::GpuMat 作为输入。
如果在这个函数之前没有建立窗口,这个函数则使用cv::WINDOW_AUTOSIZE建立窗口。
如果需要显示大于屏幕分辨率的图像,则需在imshow()之前要调用namedWindow("", WINDOW_NORMAL)。
注意
在控制台程序操作中,这个函数之后应该调用cv::waitKey 函数来指定显示图像几毫秒(暂停程序)。否则,将不能显示图像。例如,waitKey(0) 将无限长时间显示窗口,直到按下任意键(这适合于图像显示)。waitKey(25) 将显示帧25ms,之后将自动关闭显示。(如果将其放到读视频的循环中,将会逐帧显示视频图像)
[在Windows环境下] 按下Ctrl+C 拷贝图像到剪裁板。
[在Windows环境下] 按下Ctrl+S 将显示保存文件对话框。
参数
winname |
窗口名(窗口标题) |
mat |
要显示的图像数据。 |
- cv::namedWindow (const String &winname, int flags=WINDOW_AUTOSIZE);
建立窗口(并在openCV窗口管理中注册窗口,可用窗口名进行检索)
函数namedWindow()建立一个用于图像或跟踪条显示的占位窗口(原始窗口)。所建立的窗口可由窗口名加以引用。如果存在同名窗口,这个函数不做任何操作。
可以调用 cv::destroyWindow 或 cv::destroyAllWindows 来关闭窗口和释放任何相关的内存。为简化程序,并不要求必需调用这些函数,因为应用的所有资源和窗口都在退出时由操作系统自动关闭和释放。
注意
Qt 环境支持的附加标志:
- WINDOW_NORMAL 或 WINDOW_AUTOSIZE: WINDOW_NORMAL 允许改变窗口尺寸,而WINDOW_AUTOSIZE 自动调节窗口尺寸到适合显示的图像尺寸(见imshow),并且不能手动改变窗口尺寸。
- WINDOW_FREERATIO 或 WINDOW_KEEPRATIO: WINDOW_FREERATIO 不依据图像比例调节图像,而WINDOW_KEEPRATIO保持图像比例。
- WINDOW_GUI_NORMAL或WINDOW_GUI_EXPANDED: WINDOW_GUI_NORMAL使用旧风格画不带状态条和工具条的窗口,而WINDOW_GUI_EXPANDED是新风格的GUI界面。默认,flags== WINDOW_AUTOSIZE | WINDOW_KEEPRATIO | WINDOW_GUI_EXPANDED。
参数
winname |
窗口标题上的窗口名,可用作窗口标识。 |
flags |
窗口标志。支持的标志是:(cv::WindowFlags) |
cv::WindowFlags { } |
WINDOW_NORMAL Python: cv.WINDOW_NORMAL |
用户可以改变窗口大小(无限制) / 也可用于切换全屏窗口到正常大小。 |
WINDOW_AUTOSIZE Python: cv.WINDOW_AUTOSIZE |
用户不能改变窗口大小,窗口大小由显示的图像所限制。 |
WINDOW_OPENGL Python: cv.WINDOW_OPENGL |
具有opengl 支持的窗口。 |
WINDOW_FULLSCREEN Python: cv.WINDOW_FULLSCREEN |
改变窗口到全屏。 |
WINDOW_FREERATIO Python: cv.WINDOW_FREERATIO |
图像可以任意扩展(没有比例限制)。 |
WINDOW_KEEPRATIO Python: cv.WINDOW_KEEPRATIO |
保持图像比例 |
WINDOW_GUI_EXPANDED Python: cv.WINDOW_GUI_EXPANDED |
建立有状态条和工具条窗口。 |
WINDOW_GUI_NORMAL Python: cv.WINDOW_GUI_NORMAL |
旧风格的窗口 |
E、色彩空间转换(Color Space Conversions)
- void cv::cvtColor (InputArray src, OutputArray dst, int code, int dstCn=0)
转换图像从一种彩色空间到另一种彩色空间。
这个函数转换图像从一种彩色空间到另一种彩色空间。在转换RGB彩色空间时,应显式地指定通道顺序(RGB 或 BGR)。注意在openCV中默认的彩色格式通常不同于RGB顺序,而是BGR (字节是颠倒的,Intel CPU是低字节在前)。所以在标准(24位)彩色图像中头一个字节应该是8位的蓝色分量,第二个字节是绿色,而第三个字节是红色。而后的第四,第五,和第六字节是下一个像素(蓝,然后绿,然后红)等等。
R,G,和B 通道值的转换范围是:
- 0 to 255 为CV_8U 图像
- 0 to 65535 为CV_16U 图像
- 0 to 1 为CV_32F 图像
在线性变换时,范围并不重要。但是在非线性变换中,输入的RGB图像应该归一化到适当的值范围以便获得正确结果,如,对RGB → L*u*v* 变换。例,假设32位浮点图像直接从8位图像转换而来,而没有定义任何比例,结果是将0..255值范围取代函数设定的0..1。所以在调用cvtColor 之前,需要首先标定像素比例如下:
img *= 1./255;
cvtColor(img, img, COLOR_BGR2Luv);
如果函数 cvtColor 用于8位图像,转换将丢失某些信息。对于很多应用这样的损失并不显著,但是还是推荐在应用中使用32位图像保证全彩色范围或在操作之前先转换为32位图像,然后再转换回来。
如果转换附加了alpha通道,其值将被设置到最大对应通道范围:255 对应CV_8U,65535 对应CV_16U,1 对应CV_32F。
参数
src |
输入图像:8位无符号,16位无符号( CV_16UC... ),或单精度浮点数。 |
dst |
与源图同尺寸和深度的输出图像。 |
code |
色彩空间转换码(参见ColorConversionCodes)。 |
dstCn |
输出图像的通道数;如果这个参数为0,通道数自动从src和code中导出。 |
- void cv::cvtColorTwoPlane (InputArray src1, InputArray src2, OutputArray dst, int code)
转换图像从一种颜色空间到另一种颜色空间,此处的源图像存储在两个位面中。
这个函数现在仅支持YUV420 到 RGB 转换。
参数
src1 |
Y位面的8位图像(CV_8U)。 |
src2 |
包含交替U/V 位面的图像。 |
dst |
输出图像。 |
code |
指定转换类型。可以取值下面任何值:
|
- void cv::demosaicing (InputArray src, OutputArray dst, int code, int dstCn=0)
所有去马赛克过程的主函数
参数
src |
输入图像:8位无符号或16位无符号。 |
dst |
输出图像,与输入图像同尺寸和深度。 |
code |
色彩空间转换码(参见下面的描述)。 |
dstCn |
输出图像的通道数;如果为0,通道数自动从scr和code参数中导出。 |
这个函数可以做如下转换:
- 用双线性插值去马赛克
COLOR_BayerBG2BGR ,COLOR_BayerGB2BGR ,COLOR_BayerRG2BGR ,COLOR_BayerGR2BGR
COLOR_BayerBG2GRAY , COLOR_BayerGB2GRAY , COLOR_BayerRG2GRAY , COLOR_BayerGR2GRAY
- 用可变梯度数去马赛克
COLOR_BayerBG2BGR_VNG , COLOR_BayerGB2BGR_VNG , COLOR_BayerRG2BGR_VNG , COLOR_BayerGR2BGR_VNG
- 已知边缘的去马赛克
COLOR_BayerBG2BGR_EA , COLOR_BayerGB2BGR_EA , COLOR_BayerRG2BGR_EA , COLOR_BayerGR2BGR_EA
- 使用alpha 通道去马赛克
COLOR_BayerBG2BGRA , COLOR_BayerGB2BGRA , COLOR_BayerRG2BGRA , COLOR_BayerGR2BGRA
示例程序中首先建立操作对象ImageCls定义如下:
class CV_EXPORTS ImageCls
{
public:
static ImageCls* CurMy;//存储回调函数调用的对象
void setCurMy()
{
//设置当前对象为回调函数调用的对象
CurMy = this;
}
static INT_PTR CALLBACK iwinProcCls(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);//static void* callback(void*);//回调函数
//
HWND hwndMain;//主窗口消息处理handle,在winproc中实现消息处理
char filenm[255]; //图像文件名
//
Mat img; //图像数组,初始化为wid = 0,hig = 0,填充为0
Mat Gry_img;
char buffer_str[255]; //信息显示缓冲
//
ImageCls();//默认构造函数
ImageCls(HWND hwnd, char * flnm, int fltID, int matID);
~ImageCls(void);
//
public:
int handCnt;
procHandle* pHandler[255];
int findHandlerPos();//查找空位
int findHandlerPos(HWND hsWnd);//查找定位
int findHandlerPos(char * wnm);//查找定位
public:
bool showImageToWin(int imgID);
bool showImageToWin(int imgID, char *winNm);
HWND SetWinProcTo(char * wname);//绑定键盘消息处理函数
void ShowImage(HWND hpWnd, char * wname, Mat dimg);
void Closed();
public:
//滤波器节
char filterNM[255];//滤波器显示名
Mat Flt_img;//滤波器操作图像
};
然后在程序初始化中调用opencv_ImageCls自定义函数:
void opencv_ImageCls(HWND hwnd, int filterSz)
{
MyImageCls = ImageCls(hwnd, filenm, filterID, borderID);
MyImageCls.setCurMy();//设置回调操作的静态对象指针变量,静态函数使用非静态类变量需要对象指针。
MyImageCls.handCnt = 0;
MyImageCls.showImageToWin(IMAGE_COLOR);//其中包含给图像窗口挂接回调函数,每一个窗口都挂接函数(多个窗口需要不同的操作变量)。
MyImageCls.showImageToWin(IMAGE_GRAY);
}
其中showImageToWin函数:
bool ImageCls::showImageToWin(int imgID)
{
bool retV = false;
HWND hwd;
int ndx = -1;
if(img.data){
ndx = findHandlerPos("源图像窗口");
if (ndx >= 0)
{
retV = true;
break;
}
newNamedWindow( "源图像窗口",CV_WINDOW_AUTOSIZE );
hwd = SetWinProcTo("源图像窗口");//绑定键盘消息处理函数
ShowImage(hwd, "源图像窗口", img);
retV = true;
}
}
其中newNamedWindow函数是对namedWindow函数的改写以适应对图像窗口的管理,其中调用了namedWindow函数。ShowImage函数如下:
void ImageCls::ShowImage(HWND hpWnd, char * wname, Mat dimg)
{
int ndx = findHandlerPos(hpWnd);
if(ndx < 0)
return;
procHandle *wpHandler = pHandler[ndx];
//
Mat _img = ((InputArray)dimg).getMat();
wpHandler->c_img = _img;
wpHandler->arrData = &wpHandler->c_img;
wpHandler->iwid = img.cols;
wpHandler->ihig = img.rows;
newShowImage(wname,&wpHandler->c_img);
}
newShowImage函数是对imShow的改写。
注意:这里使用的不是控制台形式的操作,而是简单的窗口操作,因此,在winproc回调函数中做了处理,利用了win32的消息循环,不需要使用waitkey()函数做暂停。
以后的所有示例和函数调用都是以这种形式进行,通过主菜单选择功能,对话框获取参数,对图像对象进行操作。这样的展示适合图像的对比和操作结果的显示。