1. 像素的读写
可以根据像素的行和列的坐标获取它的像素值。对 BGR 图像而言,返回值为 B,G,R 的值。
- img.shape 可以获取图像的形状。它的返回值是一个包含行数 h,列数 w,通道数 ch 的元组。注意:如果图像是灰度图,返回值仅有行数和列数。所以通过检查这个返回值就可以知道加载的是灰度图还是彩色图。
- img.size 可以返回图像的像素数目 (h * w * ch)
- img.dtype 返回的是图像的数据类型:
import cv2
image_name = "img/003.jpg"
img = cv2.imread(image_name)
cv2.imshow("origin", img)
high, wide, channel = img.shape
print "high is {0}, wide is {1}, channel is {2}".format(high, wide, channel)
# high is 198, wide is 198, channel is 3
for row in range(high):
for col in range(wide):
b, g, r = img[row, col]
b = 255 - b
g = 255 - g
r = 255 - r
img[row, col] = b, g, r # 修改像素值
cv2.imshow("output", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
显示结果:
如果上面的难以理解,可以看下面的这些操作,希望能帮助读者更好的理解。
>>> a = np.array([[[1, 2], [3,4], [5, 6]], [[11, 22], [33,44], [55, 66]]])
>>> a.shape
(2, 3, 2)
>>> a
array([[[ 1, 2],
[ 3, 4],
[ 5, 6]],
[[11, 22],
[33, 44],
[55, 66]]])
>>> a.ndim
3
>>> a.size
12
>>> a[0, 1]
array([3, 4])
>>> a[1, 2]
array([55, 66])
>>> h, w = a[1, 2]
>>> h,w
(55, 66)
2. 像素的算术运算
图像像素也可以进行加、减、乘、除操作,但是必须要注意,进行算术运算操作的时,必须要保证两幅图像的大小、数据类型和通道数目必须相同。
- OpenCV 中的加法与 Numpy 的加法是有所不同的。OpenCV 的加法是一种饱和操作,而 Numpy 的加法是一种模操作。这种差别在你对两幅图像进行加法时会更加明显。OpenCV 的结果会更好一点。所以我们尽量使用 OpenCV 中的函数。
使用示例如下:
import cv2
import numpy as np
img1 = cv2.imread("img/003.jpg")
img2 = cv2.imread("img/003_gray.jpg")
cv2.imshow("img1", img1)
cv2.imshow("img2", img2)
h, w, ch = img1.shape
add_result = np.zeros(img1.shape, img1.dtype)
cv2.add(img1, img2, add_result)
cv2.imshow("add_result", add_result)
sub_result = np.zeros(img1.shape, img1.dtype)
cv2.subtract(img1, img2, sub_result)
cv2.imshow("sub_result", sub_result)
mul_result = np.zeros(img1.shape, img1.dtype)
cv2.multiply(img1, img2, mul_result)
cv2.imshow("mul_result", mul_result)
div_result = np.zeros(img1.shape, img1.dtype)
cv2.divide(img1, img2, div_result)
cv2.imshow("div_result", div_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
3. 像素的逻辑运算
这里包括的按位操作有:AND,OR,NOT,XOR 等。当我们提取图像的一部分,选择非矩形 ROI 时这些操作会很有用。下面的例子就是教给我们如何改变一幅图的特定区域。
import cv2
import numpy as np
# create img one
img1 = np.zeros(shape=(200, 200, 3), dtype=np.uint8)
img1[50:100, 50:100, 1] = 255
img1[50:100, 50:100, 2] = 255
cv2.imshow("img1", img1)
# create img two
img2 = np.zeros(shape=(200, 200, 3), dtype=np.uint8)
img2[75:150, 75:150, 2] = 255
cv2.imshow("img2", img2)
dst1 = cv2.bitwise_and(img1, img2)
dst2 = cv2.bitwise_or(img1, img2)
dst3 = cv2.bitwise_xor(img1, img2)
cv2.imshow("dst1", dst1)
cv2.imshow("dst2", dst2)
cv2.imshow("dst3", dst3)
img4 = cv2.imread("img/003.jpg")
dst4 = cv2.bitwise_not(img4)
cv2.imshow("dst4", dst4)
cv2.waitKey(0)
cv2.destroyAllWindows()
4. 像素的统计
像素值统计涉及到的知识点有以下几个
- 最小(min)
- 最大(max)
- 均值(mean)
- 标准方差(standard deviation)
OpenCV 相关的 API 知识点
- 最大最小值 minMaxLoc
- 计算均值与标准方差 meanStdDev
注意:像素值统计必须是单通道的图片,所以 cv2.imread 时必须加上图片的载入类型。
源码中有如下提示:
'''
The function do not work with multi-channel arrays. If you need to find minimum or maximum
elements across all the channels, use Mat::reshape first to reinterpret the array as
single-channel.
'''
import cv2
import numpy as np
img = cv2.imread("img/003.jpg", cv2.IMREAD_GRAYSCALE)
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(img)
print minVal, maxVal, minLoc, maxLoc # 0.0 255.0 (128, 24) (120, 12)
means, stddev = cv2.meanStdDev(img)
print means, stddev # [[97.23278237]] [[45.80720813]]
img[np.where(img < means)] = 0
img[np.where(img > means)] = 255
cv2.imshow("binary", img)
cv2.waitKey(0)
cv2.destroyAllWindows()