OpenCV图像输入输出模块imgcodecs

发布于:2025-03-29 ⋅ 阅读:(25) ⋅ 点赞:(0)

《OpenCV计算机视觉开发实践:基于Python(人工智能技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书

要处理图像,第一步就是把图像文件从磁盘上读取到内存,处理完毕后再保存到内存,所以我们先来看一下图像文件读取与保存模块imgproc。imgproc提供了一系列全局函数,用于读取或保存图像文件。

3.2.1  读取图像文件

函数imread用于读取图像文件或加载图像文件,声明如下:

cv.imread(filename[, flags]) -> retval

其中,参数filename表示要读取的图像文件名,flags表示读取模式,取值如下:

  • cv.IMREAD_ANYDEPTH:其值是2,取这个标志的话,若载入的图像深度为16位或者32位,则返回对应深度的图像,否则转换为8位图像再返回。
  • cv.IMREAD_COLOR:其值是1,取这个标志的话,图像转为彩色图像(BGR,3通道)。
  • cv.IMREAD_GRAYSCALE:其值是0,取这个标志的话,始终将图像转换成灰度图,即返回灰度图像,1通道。
  • cv. IMREAD_UNCHANGED,其值是-1,不加改变地载入原图。

如果从指定文件加载图像成功,就返回一个存储着图片像素数据的矩阵。如果无法读取图像(缺少文件、权限不正确、格式不受支持或无效),那么函数将返回空。

imread支持常见的图像格式,在Windows操作系统下,OpenCV的imread函数支持如下类型的图像载入:

  • JPEG文件:*.jpeg、*.jpg、*.jpe。
  • JPEG 2000文件:*.jp2。
  • PNG文件:*.png。
  • 便携文件格式:*.pbm、*.pgm、*.pp。
  • Sun rasters光栅文件:*.sr、*.ras。
  • TIFF 文件:*.tiff、*.tif。
  • Windows位图:*.bmp、*.dib。

如果读取失败就返回None,可以通过判断是否为None来判断是否读取正确,比如:

img = cv.imread("p1.jpg"); #读取第一幅图片

if img is None:

    sys.exit("Could not read the p1.jpg.") #如果读取为空,则退出程序

img实际上是一个NumPy的array数组,它包含着每个像素点的数据(如果是彩色模式,就包括了BGR值,灰度模式则是灰度值)。我们可以通过下标访问每一个像素点的数据,对每一个像素点进行更改操作。

值得注意的是,函数imread根据内容而不是文件扩展名来确定图像的类型,比如把某个BMP图像文件改为后缀名为JPG文件,imread依然能探测到这个文件是BMP图像文件。

另外,imread的第一个参数一般是图像文件的绝对路径或相对路径。对于绝对路径,imread除了不支持单右斜线形式(\),其他斜线形式都支持,比如双右斜线形式(\\)、双左斜线形式(//)、单左斜线形式(/)等。通常相对路径更加方便点,只要把图像文件放在工程目录下即可。值得注意的是,imread的文件路径不支持中文路径,如果要支持中文路径,就可以用函数imdecode。该函数从指定的内存缓存中读取一幅图像,声明如下:

cv.imdecode(buf, flags) -> retval

其中,buf是存放图像数据的内存缓存,通常用字节数组或向量的形式表示;flags的含义同imread函数的flags参数。如果内存缓冲区太短或包含无效数据,就返回空矩阵图像。实际上,imread和imdecode内部都是通过ImageDecoder类来进行图像解码的。

例如,下列代码从文件中读取数据到内存:

import numpy as np #导入numpy模块

img = cv.imdecode(np.fromfile(imgpath,dtype=np.uint8),-1)

其中,fromfile函数是支持中文路径的,它通过读取文件在内存中构造数组数据,这样imdecode就能在内存中获得数组数据了,继而进行解码。

【例3.1】  多种路径读取图像文件

import cv2 as cv 
import numpy as np #导入numpy模块 

#imgpath = "d:\\我的图片\\p1.jpg";
#imgpath = "d://test//p1.jpg";
#imgpath = "d:/test/p1.jpg"
#imgpath = "d:/test//test2\\test3//test4//p1.jpg";#-- 4 --以上三种混合法 
imgpath = "p1.jpg"; #-- 5 --相对路径法,放在和test.py同一路径
img = cv.imdecode(np.fromfile(imgpath,dtype=np.uint8),-1)
cv.imshow("img",img) #显示窗口
cv.waitKey(0) #等待按键
cv.destroyAllWindows() #释放窗口

我们对上面的六种路径进行了测试,任何一种都是支持的,都可以成功读取并显示图片;其中较常用的是相对路径,也就是第五种。图片放在和3.1.py文件同一路径下,既可以在PyCharm中直接运行来打开图片,也可以到命令行窗口下执行“pthon 3.1.py”命令来打开图片。

运行工程,结果如图3-3所示。

在用imread或imdecode加载图像文件时,可以指定模式来获得不同的效果。

【例3.2】  用不同模式打开图像文件

import cv2 as cv 
import numpy as np #导入numpy模块 
imgpath = "p1.jpg"; 
img = cv.imread(imgpath,cv.IMREAD_ANYDEPTH)
cv.imshow("img",img) #显示窗口
cv.waitKey(0) #等待按键

img = cv.imread(imgpath,cv.IMREAD_COLOR)
cv.imshow("img",img) #显示窗口
cv.waitKey(0) #等待按键继续下一幅

img = cv.imread(imgpath,cv.IMREAD_GRAYSCALE)
cv.imshow("img",img) #显示窗口
cv.waitKey(0) #等待按键
 
cv.destroyAllWindows() #释放窗口

我们分别用3种模式来加载图片。对于cv.IMREAD_ANYDEPTH,由于p1.jpg的位深度是24(不是16或32),因此会转换为8位图像。cv.IMREAD_COLOR会将图像以彩色方式加载,由于我们的图像本来是彩色图像,因此没有变化。cv.IMREAD_GRAYSCALE会将图像转换成灰度图,所以加载后图像是黑白的。

保存工程并运行,第一幅图像运行结果如图3-4所示。然后按空格键,可以继续显示下一幅图像。

3.2.2  得到读取的图片的高度和宽度

上节我们提到imread如果读取图像文件成功,就返回该图像的矩阵。既然是矩阵,就有宽度和高度两个属性,宽度相当于矩阵的列数,高度相当于矩阵的行数。在Python中,可以利用NumPy库提供的shape函数来得到矩阵的行数和列数。

shape函数是numpy.core.fromnumeric中的函数,功能是读取矩阵的长度,比如shape[0]就是读取矩阵第一维度的长度。shape的输入参数可以是一个整数(表示维度),也可以是一个矩阵。使用shape[0]读取矩阵第一维度的长度,也就是行数;使用shape[1]计算列数;使用shape[2]存放图像的通道数。该函数强大,这里我们只需要知道如何获得图片的高度和宽度即可。我们插入这一节的目的主要是为了让大家能在读取图像文件到内存后,对内存中存放图像的矩阵有一个感性的认识。

【例3.3】  得到读取图像后的高度和宽度

import cv2 as cv 
import numpy as np #导入numpy模块 
img = cv.imread('test.jpg')
print(np.shape(img))

height=np.shape(img)[0]
width=np.shape(img)[1]
channles=np.shape(img)[2]
print("h=",height,"w=",width,"channles=",channles)

height, width,channles = np.shape(img)[:3] # a[:n]代表列表中的第一项到第n项
print("h=",height,"w=",width,"channles=",channles)

在上述代码中,首先读取了当前工程目录下的图像文件test.jpg,返回值为一个矩阵数组,然后我们通过shape打印了高度和宽度。注意:在Python中,a[:n]代表列表中的第1项到第n项,这里的shape[:3]表示shape[0](高度)、shape[1](宽度)和shape[2](通道数)。随后我们又赋值给了3个变量并打印。最后,用shape[:3]赋值给变量。

运行工程,结果如下:

(183, 335, 3)

h= 183 w= 335 channles= 3

h= 183 w= 335 channles= 3