目标
- 掌握获取像素值和改变像素值的方法
- 掌握获得图像属性的方法
- 掌握设置感兴趣区域(ROI)的方法
- 掌握分割和融合图像的方法
本节几乎所有的操作都将与Numpy库息息相关,因此深入学习Numpy库将有助于优化OpenCV的代码。
所有代码案例将使用Python terminal来运行。
获取和修改像素值
首先要读取一张照片。
>>> import numpy as np
>>> import cv2 as cv
>>> img = cv.imread('lenacolor.png')
通过行和列坐标获得一个像素值。对于一个BGR图像(OpenCV里面是以BGR的顺序存储彩色图片),返回一个蓝色、绿色和红色三个值的数组。对于灰度图像,只返回相应的数值。
>>> px = img[100,100]
>>> print( px )
[78 68 178]
# 只获取蓝色像素值
>>> blue = img[100,100,0]
>>> print( blue )
78
可以改变像素值。
>>> img[100,100] = [255,255,255]
>>> print( img[100,100] )
[255 255 255]
注意:由于Numpy库是一个十分优秀的矩阵运算库。因此如果使用简单的方法获得每一个像素的值并进行操作将会十分缓慢,因此这种方法并不推荐。上面的方法通常用来选取一片区域,比如获取前五行和最后3列。对于单个像素的获取,使用Numpy库的array的方法,推荐使用array.item()和array.itemset()。
更好的获得像素值和处理方法:
# 获取红色通道像素值
>>> img.item(10,10,2)
226
# 修改红色通道像素值
>>> img.itemset((10,10,2),100)
>>> img.item(10,10,2)
100
获取图像属性
图像属性包括行列数和通道数,图像数据类型,像素数量等。
通过img.shape获取图像形状,返回一个元组,包含行列数和通道数(如果图像是彩色的)
>>> print( img.shape )
(512 512, 3)
注意:如果是灰度图像,只会返回包含行列数的元组。所以使用这个方法可以检查读入的图像是彩色图像还是灰度图。
通过img.size获得图像的像素数量(行数*列数)。
>>> print( img.size )
786432
通过img.dtype获得图像数据类型。
>>> print( img.dtype )
uint8
注意:在调试过程检查图像数据类型将十分有用,因此很多错误通常是由错误的数据类型导致的。
图像感兴趣区域(ROI)
有些时候,我们并不需要对整幅图像进行处理,只需要对其中我们感兴趣的区域进行处理。例如,在一张图片中识别眼睛,首先我们会识别图片中的脸部,在获得脸部之后,我们将脸部区域单独提取出来识别其中的眼睛,使用这样的方法来代替搜索整张图像。这样操作可以提高准确度(因为眼睛一定是在脸上,而脸部区域比较大,识别脸部区域的准确性相对直接在图像中找眼睛会高很多),并且效率也会更高。
通过Numpy索引提取感兴趣区域。这里我们复制lena的一只眼睛到图像的右下角。
eye = img[200:300,200:300]
img[400:500,400:500] = eye
分割和融合图像通道
有些时候我们需要单独处理图像的BGR通道。这样,我们需要将BGR图像分割成单通道图像。然而有些时候则需要将单独通道的结果加入到BGR图像中。
>>> b,g,r = cv.split(img)
>>> img = cv.merge((b,g,r))
或者
b = img[:,:,0]
如果想将图像某一通道的值都设置为0,不需要将图像通道给分开,只要使用Numpy索引即可。
>>> img[:,:,2] = 0
注意:cv.split()是一个耗时的操作,因此,除非必须使用,否则还是使用Numpy索引操作。
图像加边框
可以使用cv.copyMakeBorder()给图像加一个像相框一样的边框。但是,这个方法在卷积运算和零填充(zero padding)等会有更多的应用。这个函数有以下的参数:
- src——需要处理的原图像
- top, bottom, left, right——在相应方向上的边界宽度(大小为像素个数)
- borderType——用于确定加上哪种边框的标志符。有如下几种
- cv.BORDER_CONSTANT-加入一个大小不变的有颜色边框。Value需要指定。
- cv.BORDER_REFLECT-边框单元会镜像反射。
- cv.BORDER_REFLECT_101或者cv.BORDER_DEFAULT-和上面的一样,但是在单个通道上加上边框。
- value———边框的颜色,如果边框的类型是cv.BORDER_CONSTANT
下面的代码将展示所有的边界类型
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = cv.imread('image\\OpenCV.png')
replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
结果如上,因为图像是使用matplotlib显示,matplotlib的彩色图像是RGB排列顺序,与OpenCV读入图像的BGR不同,因此图像颜色会有所不同。