图像属性、图像感兴趣ROI区域及通道处理
1.图像属性
1.1形状:shape
图像的形状可以通过 shape 关键字进行获取,使用 shape 关键的后,获取的信息包括行数、列数、通道数的元祖。
需要注意的是,如果是灰度图片,只会返回图像的行数和列数,而彩色图片才会图像的行数、列数和通道数。
实例如下:
import cv2 as cv # 读取彩色图片 color_img = cv.imread("data.jpg", cv.IMREAD_ANYCOLOR) print(color_img.shape) # 结果打印 (310, 560, 3) # 读取灰度图片 gray_img = cv.imread("data.jpg", cv.IMREAD_GRAYSCALE) print(gray_img.shape) # 结果打印 (310, 560)
1.2像素数量:size
图像的像素数量可以通过关键字 size 进行获取。
同样需要注意的是,灰度图片的像素数量是要小于彩色图片的,具体的关系是 1/3 。
import cv2 as cv # 读取彩色图片 color_img = cv.imread("data.jpg", cv.IMREAD_ANYCOLOR) print(color_img.size) # 结果打印 520800 # 读取灰度图片 gray_img = cv.imread("data.jpg", cv.IMREAD_GRAYSCALE) print(gray_img.size) # 结果打印 173600
1.3图像类型-dtype
图像类型是通过关键字 dtype 获取的,通常返回 uint8 ,这个属性在彩色图片和灰度图片中是保持一致的。
注意 dtype 在调试时非常重要,因为 OpenCV-Python 代码中的大量错误是由无效的数据类型引起的。
import cv2 as cv # 读取彩色图片 color_img = cv.imread("data.jpg", cv.IMREAD_ANYCOLOR) print(color_img.dtype) # 结果打印 uint8 # 读取灰度图片 gray_img = cv.imread("data.jpg", cv.IMREAD_GRAYSCALE) print(gray_img.dtype) # 结果打印 uint8
2.获取图像感兴趣ROI区域
ROI(Region of Interest)表示感兴趣区域。
它是指从被处理图像以方框、圆形、椭圆、不规则多边形等方式勾勒出需要处理的区域。可以通过各种算子(Operator)和函数求得感兴趣ROI区域,并进行图像的下一步处理,被广泛应用于热点地图、人脸识别、图像分割等领域。
如果我们要对于图像中的眼睛检测,首先对整个图像进行人脸检测。在获取人脸图像时,我们只选择人脸区域,搜索其中的眼睛,而不是搜索整个图像。它提高了准确性(因为眼睛总是在面部上:D )和性能(因为我们搜索的区域很小)。
我们通过像素矩阵可以直接得到 ROI 区域,如: img[200:400, 200:400] 。
比如下面这个示例我们获取小姐姐的脸,然后再把它显示出来:
import cv2 as cv img = cv.imread("data.jpg", cv.IMREAD_UNCHANGED) face = img[0:175, 200:420] #前一个是宽,后一个是长 # 原始图像显示 cv.imshow("demo", img) # 小姐姐的脸显示 cv.imshow("face", face) #等待显示 cv.waitKey(0) cv.destroyAllWindows()
它的结果如下:
如果我们要把这两张图像合成一张图像,可以对图像进行区域赋值:
import cv2 as cv img = cv.imread("data.jpg", cv.IMREAD_UNCHANGED) # 获取 ROI 区域 face = img[0:175, 200:420] # 图像赋值 img[0:165, 0:160] = face # 原始图像显示 cv.imshow("demo", img) #等待显示 cv.waitKey(0) cv.destroyAllWindows()
结果如下:
3.拆分和合并图像通道
3.1拆分图像通道
有些时候,我们需要分别处理图像的 B,G,R 通道。的通道,用 PS 抠过图的人应该都清楚抠图的时候可以使用单通道进行抠图操作。
将图像的通道拆分出来可以使用 split() 函数,如下:
import cv2 as cv img = cv.imread("data.jpg", cv.IMREAD_UNCHANGED) #拆分通道 b, g, r = cv.split(img) # 分别显示三个通道的图像 cv.imshow("B", b) cv.imshow("G", g) cv.imshow("R", r) # 等待显示 cv.waitKey(0) cv.destroyAllWindows()
可以看到,三个通道的图像看起来都是灰白色的,这个玩过 PS 的人应该都很熟悉。
除了使用 split() 函数获取图像通道,还可以通过索引进行获取,代码如下:
b = img[:, :, 0] g = img[:, :, 1] r = img[:, :, 2]
如果需要将所有红色像素都设置为零,无需先拆分通道,索引更快:
img[:, :, 2] = 0 • 1
注意: split() 函数是一项耗时的操作(就时间而言)。因此,仅在必要时才这样做。否则请进行Numpy索引。
3.2合并图像通道
合并图像通道我们使用函数 merge() ,示例如下:
import cv2 as cv img = cv.imread("data.jpg", cv.IMREAD_UNCHANGED) # 拆分通道 b, g, r = cv.split(img) # 合并图像通道 m = cv.merge([r, g, b]) cv.imshow('merge', m) # 等待显示 cv.waitKey(0) cv.destroyAllWindows()
结果如下:
这里如果是按照 [r, g, b] 进行图像通道合并,小姐姐就会变身成为岚姐,因为 OpenCV 是按照 BGR 读取的,如果想要显示会原图,合并的时候也按照 [b, g, r] 合并即可。
如果我们想要做一个真正的岚姐,可以只提取 B 颜色通道,其余两个 G 、 R 通道全部设置为 0 ,这样,我们就获得了一个真正的岚姐(整个图像只有蓝色通道),代码如下:
import cv2 as cv import numpy as np # 读取图片 img = cv.imread("data.jpg", cv.IMREAD_UNCHANGED) rows, cols, chn = img.shape # 拆分通道 b = img[:, :, 0] g = np.zeros((rows,cols), dtype=img.dtype) r = np.zeros((rows,cols), dtype=img.dtype) # 合并图像通道 m = cv.merge([b, g, r]) cv.imshow('merge', m) # 等待显示 cv.waitKey(0) cv.destroyAllWindows()
结果下: