相关文章推荐
开心的酸菜鱼  ·  用yaml-cpp读取映射向量失败-腾讯云开 ...·  1 年前    · 
打篮球的充值卡  ·  Python ...·  1 年前    · 
长情的消防车  ·  记一次sql 插入故障[SQL ...·  1 年前    · 
坚强的煎鸡蛋  ·  如何:在使用演示图板对属性进行动画处理后设置 ...·  1 年前    · 
Code  ›  opencv的imread函数_opencv imwrite开发者社区
https://cloud.tencent.com/developer/article/2151329?from=article.detail.2153930&areaSource=106000.2&traceId=1N9uS6dGwWxhGIefWtjz_
讲道义的小虾米
2 年前
作者头像
全栈程序员站长
0 篇文章

opencv的imread函数_opencv imwrite

前往专栏
腾讯云
备案 控制台
开发者社区
学习
实践
活动
专区
工具
TVP
文章/答案/技术大牛
写文章
社区首页 > 专栏 > 全栈程序员必看 > 正文

opencv的imread函数_opencv imwrite

发布 于 2022-11-04 15:31:18
195 0
举报

近日,开始学习图像处理,思前想后决定以opencv作为实验基础。遂完成图片读取和显示功能。Imread作为常用的图像读取函数,虽然简单,但是参数的选择非常重要,直接影响到后期处理。同时在调试学习过程中也可以学习到图像处理的知识。

0 函数原型

Mat imread ( const String & filename , int flags = IMREAD_COLOR );

返回Mat对象;

参数filename: 待打开图片的绝对地址,需要注意的是,并不是所有文件都可以用它打开,它支持的文件如下;函数识别不是依靠文件的后缀名,而是依靠内容的编码格式;

需要注意的是imread读取数据时会重新排列数据。

  • Windows bitmaps – *.bmp, *.dib (always supported)
  • JPEG files – *.jpeg, *.jpg, *.jpe (see the Notes section)
  • JPEG 2000 files – *.jp2 (see the Notes section)
  • Portable Network Graphics – *.png (see the Notes section)
  • WebP – *.webp (see the Notes section)
  • Portable image format – *.pbm, *.pgm, *.ppm *.pxm, *.pnm (always supported)
  • Sun rasters – *.sr, *.ras (always supported)
  • TIFF files – *.tiff, *.tif (see the Notes section)
  • OpenEXR Image files – *.exr (see the Notes section)
  • Radiance HDR – *.hdr, *.pic (always supported)
  • Raster and Vector geospatial data supported by Gdal (see the Notes section)

参数flags:打开的参数,这个非常重要,因为如果设置不合适的话,很容易出现预想之外的效果。它可以指导将原图读取时进行一定的转换。默认值是IMREAD_LOAD_GDAL。因此,如果是想直接处理原图,应该设置为IMREAD_UNCHANED。

IMREAD_UNCHANGED

If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).

IMREAD_GRAYSCALE

If set, always convert image to the single channel grayscale image.

IMREAD_COLOR

If set, always convert image to the 3 channel BGR color image.

IMREAD_ANYDEPTH

If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.

IMREAD_ANYCOLOR

If set, the image is read in any possible color format.

IMREAD_LOAD_GDAL

If set, use the gdal driver for loading the image.

IMREAD_REDUCED_GRAYSCALE_2

If set, always convert image to the single channel grayscale image and the image size reduced 1/2.

IMREAD_REDUCED_COLOR_2

If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.

IMREAD_REDUCED_GRAYSCALE_4

If set, always convert image to the single channel grayscale image and the image size reduced 1/4.

IMREAD_REDUCED_COLOR_4

If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.

IMREAD_REDUCED_GRAYSCALE_8

If set, always convert image to the single channel grayscale image and the image size reduced 1/8.

IMREAD_REDUCED_COLOR_8

If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.

1 通道编码顺序

通道,与像素深度深度有关。灰度图通常是8比特的像素深度,则通道数为1。如果是彩色图,且为RGB编码,那么一般为24比特的像素深度,通道数为3。而有的彩色图的像素深度是16或者32比特。16比特可能有多种情况:一是压缩的RGB格式,二是YUV的输出。无论何种,都是只有2通道,需要手动解析分离。32比特(windows *.bmp)的像素深度对应的彩色图,则表示的是4通道,RGBA,多出的A表示的是透明度的索引。

另外读取时需要注意内部像素的编码顺序,这也依赖于imread的flags选项的取值,如果取值决定转成RGB,那么正常的顺序是BGR,排列顺序如下图所示。如果最后imread输出是四通道,多了Alpha通道,那么顺序是RGBA。

2 图像像素通道数据访问

这部分可以借鉴网上资料,可以分为三种类型。

2.1 动态访问at<typename>(i,j)

Imread返回的mat类,提供了at模板函数。Image.at<uchar>(i, j);取出i行j列的数据,uchar可以理解为imread返回之后图像的编码类型(如1所述的通道)。如果是三通道,则可以是Vec3b,四通道则是Vec4b。

//CV_LOAD_IMAGE_UNCHANGED如果要取A分量那么flag最好设置成这个值 Mat image = imread(“1_firstlai.png”, CV_LOAD_IMAGE_UNCHANGED); for(int i=0;i<image.rows;i++) for(int j=0;j<image.cols;j++) image.at<Vec3b>(i,j)[0]; //B image.at<Vec3b>(i,j)[1]; //G image.at<Vec3b>(i,j)[2]; //R image.at<Vec4b>(i,j)[0]; //B image.at<Vec4b>(i,j)[1]; //G image.at<Vec4b>(i,j)[2]; //R image.at<Vec4b>(i,j)[3]; //A }

2.2 指针-更加高效

imgage.ptr<uchar>(i)。

int nr=image.rows; // 将3通道转换为1通道 int nl=image.cols*image.channels(); for(int k=0;k<nr;k++) // 每一行图像的指针 const uchar* inData=image.ptr<uchar>(k); for(int i=0;i<nl;i++) inData[i]; }

本质就是将每行的3/4通道数据转换为1通道数据访问,因为OpenCV内部存储每一行像素数据以及像素内部通道数据都是连续存储的。但是行与行的数据并不一定是连续存储的,所以不能应用在行与行之间。

2.3 结合isContinuous的指针

2.2中已经说明了,OpenCV中行与行之间不一定连续存储,也就是有可能连续存储,而且提供了对应的API支持判断是否连续这一现象,也可基于此,再提高访问速度。

int nr=image.rows; int nc=image.cols*image.channels(); if(image.isContinuous()){ nc=nc*nr; nr=1; for(int i=0;i<nr;i++){ // 每一行图像的指针 const uchar* inData=image.ptr<uchar>(i); for(int j=0;j<nc;j++){ inData[j]; }

2.4 安全但低效的迭代器

2.1-2.3的方法虽然效率高,但是如果操作不小心,容易造成数组越界的Bug。所以opencv提供了一种更安全的访问方法-迭代器。

MatIterator_<Vec3b> it_im, itEnd_im; it_im = im.begin<Vec3b>();

 
推荐文章
开心的酸菜鱼  ·  用yaml-cpp读取映射向量失败-腾讯云开发者社区-腾讯云
1 年前
打篮球的充值卡  ·  Python 中文转Unicode字符串-腾讯云开发者社区-腾讯云
1 年前
长情的消防车  ·  记一次sql 插入故障[SQL Server]从字符串转换日期和/或时间时,转换失败。 (241)_sql 添加日期数据时转换失败-CSDN博客
1 年前
坚强的煎鸡蛋  ·  如何:在使用演示图板对属性进行动画处理后设置该属性 - WPF .NET Framework | Microsoft Learn
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号