OpenCV Python教程之图像元素的访问、通道分离与合并
OpenCV Python教程之图像元素的访问、通道分离与合并
转载请详细注明原作者及出处,谢谢!
访问像素
像素的访问和访问numpy中ndarray的方法完全一样,灰度图为:
- img[j,i] = 255
- img[j,i,0]= 255
- img[j,i,1]= 255
- img[j,i,2]= 255
下面通过对图像添加人工的椒盐现象来进一步说明OpenCV Python中需要注意的一些问题。完整代码如下:
- import cv2
- import numpy as np
- def salt(img, n):
- for k in range(n):
- i = int(np.random.random() * img.shape[1]);
- j = int(np.random.random() * img.shape[0]);
- if img.ndim == 2:
- img[j,i] = 255
- elif img.ndim == 3:
- img[j,i,0]= 255
- img[j,i,1]= 255
- img[j,i,2]= 255
- return img
- if __name__ == '__main__':
- img = cv2.imread("图像路径")
- saltImage = salt(img, 500)
- cv2.imshow("Salt", saltImage)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
上面的代码需要注意几点:
1、与C++不同,在python中灰度图的img.ndim
= 2,而C++中灰度图图像的通道数img.channel() =1
2、为什么使用np.random.random()?
这里使用了numpy的随机数,Python自身也有一个随机数生成函数。这里只是一种习惯,np.random模块中拥有更多的方法,而Python自带的random只是一个轻量级的模块。不过需要注意的是np.random.seed()不是线程安全的,而Python自带的random.seed()是线程安全的。如果使用随机数时需要用到多线程,建议使用Python自带的random()和random.seed(),或者构建一个本地的np.random.Random类的实例。
分离、合并通道
由于opencv Python和NumPy结合的很紧,所以即可以使用OpenCV自带的split函数,也可以直接操作numpy数组来分离通道。直接法为:
- import cv2
- import numpy as np
- img = cv2.imread("D:/cat.jpg")
- b, g, r = cv2.split(img)
- cv2.imshow("Blue", r)
- cv2.imshow("Red", g)
- cv2.imshow("Green", b)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
- b = cv2.split(img)[0]
- g = cv2.split(img)[1]
- r = cv2.split(img)[2]
也可以直接操作NumPy数组来达到这一目的:
- import cv2
- import numpy as np
- img = cv2.imread("D:/cat.jpg")
- b = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- g = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- r = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- b[:,:] = img[:,:,0]
- g[:,:] = img[:,:,1]
- r[:,:] = img[:,:,2]
- cv2.imshow("Blue", r)
- cv2.imshow("Red", g)
- cv2.imshow("Green", b)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
- >>> c= np.zeros(img.shape, dtype=img.dtype)
- >>> c[:,:,:] = img[:,:,:]
- >>> d[:,:,:] = img[:,:,:]
- >>> c is a
- False
- >>> d is a
- False
- >>> c.base is a
- False
- >>> d.base is a #注意这里!!!
- True
通道合并
同样,通道合并也有两种方法。第一种是OpenCV自带的merge函数,如下:
- merged = cv2.merge([b,g,r]) #前面分离出来的三个通道
- mergedByNp = np.dstack([b,g,r])
- merged = cv2.merge([b,g,r])
- print "Merge by OpenCV"
- print merged.strides
- mergedByNp = np.dstack([b,g,r])
- print "Merge by NumPy "
- print mergedByNp.strides
- Merge by OpenCV
- (1125, 3, 1)
- Merge by NumPy
- (1, 500, 187500)
- >>> a = np.arange(6)
- >>> a
- array([0, 1, 2, 3, 4, 5])
- >>> a.strides
- (4,)
同样,2维数组如下:
- >>> b = np.arange(12).reshape(3,4)
- >>> b
- array([[ 0, 1, 2, 3],
- [ 4, 5, 6, 7],
- [ 8, 9, 10, 11]])
- >>> b.strides
- (16, 4)
下面来看下3维数组:
- >>> c = np.arange(27).reshape(3,3,3)
- array([[[ 0, 1, 2],
- [ 3, 4, 5],
- [ 6, 7, 8]],
- [[ 9, 10, 11],
- [12, 13, 14],
- [15, 16, 17]],
- [[18, 19, 20],
- [21, 22, 23],
- [24, 25, 26]]])
- >>> c.strides
- (36, 12, 4)
- import cv2
- import numpy as np
- img = cv2.imread("D:/cat.jpg")
- b = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- g = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- r = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- b[:,:] = img[:,:,0]
- g[:,:] = img[:,:,1]
- r[:,:] = img[:,:,2]
- merged = cv2.merge([b,g,r])
- print "Merge by OpenCV"
- print merged.strides
- print merged
- mergedByNp = np.dstack([b,g,r])
- print "Merge by NumPy "
- print mergedByNp.strides
- print mergedByNp
- cv2.imshow("Merged", merged)
- cv2.imshow("MergedByNp", merged)
- cv2.imshow("Blue", b)
- cv2.imshow("Red", r)
- cv2.imshow("Green", g)
- cv2.waitKey(0)
- cv2.destroyAllWindows()