OpenCV Python教程之图像元素的访问、通道分离与合并

OpenCV Python教程之图像元素的访问、通道分离与合并

转载请详细注明原作者及出处,谢谢!

访问像素

像素的访问和访问numpy中ndarray的方法完全一样,灰度图为:

[python]  view plain  copy
  1. img[j,i] = 255  
其中j,i分别表示图像的行和列。对于BGR图像,为:
[python]  view plain  copy
  1. img[j,i,0]= 255  
  2. img[j,i,1]= 255  
  3. img[j,i,2]= 255  
第三个数表示通道。

下面通过对图像添加人工的椒盐现象来进一步说明OpenCV Python中需要注意的一些问题。完整代码如下:

[python]  view plain  copy
  1. import cv2  
  2. import numpy as np  
  3.   
  4. def salt(img, n):  
  5.     for k in range(n):  
  6.         i = int(np.random.random() * img.shape[1]);  
  7.         j = int(np.random.random() * img.shape[0]);  
  8.         if img.ndim == 2:   
  9.             img[j,i] = 255  
  10.         elif img.ndim == 3:   
  11.             img[j,i,0]= 255  
  12.             img[j,i,1]= 255  
  13.             img[j,i,2]= 255  
  14.     return img  
  15.   
  16. if __name__ == '__main__':  
  17.     img = cv2.imread("图像路径")  
  18.     saltImage = salt(img, 500)  
  19.     cv2.imshow("Salt", saltImage)  
  20.     cv2.waitKey(0)  
  21.     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数组来分离通道。直接法为:

[python]  view plain  copy
  1. import cv2  
  2. import numpy as np  
  3.   
  4. img = cv2.imread("D:/cat.jpg")  
  5. b, g, r = cv2.split(img)  
  6. cv2.imshow("Blue", r)  
  7. cv2.imshow("Red", g)  
  8. cv2.imshow("Green", b)  
  9. cv2.waitKey(0)  
  10. cv2.destroyAllWindows()  
其中split返回RGB三个通道,如果只想返回其中一个通道,可以这样:
[python]  view plain  copy
  1. b = cv2.split(img)[0]  
  2. g = cv2.split(img)[1]  
  3. r = cv2.split(img)[2]  
最后的索引指出所需要的通道。

也可以直接操作NumPy数组来达到这一目的:

[python]  view plain  copy
  1. import cv2  
  2. import numpy as np  
  3.   
  4. img = cv2.imread("D:/cat.jpg")  
  5.   
  6. b = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)  
  7. g = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)  
  8. r = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)  
  9.   
  10. b[:,:] = img[:,:,0]  
  11. g[:,:] = img[:,:,1]  
  12. r[:,:] = img[:,:,2]  
  13.   
  14. cv2.imshow("Blue", r)  
  15. cv2.imshow("Red", g)  
  16. cv2.imshow("Green", b)  
  17. cv2.waitKey(0)  
  18. cv2.destroyAllWindows()  
注意先要开辟一个相同大小的图片出来。这是由于numpy中数组的复制有些需要注意的地方,具体事例如下:
[python]  view plain  copy
  1. >>> c= np.zeros(img.shape, dtype=img.dtype)  
  2. >>> c[:,:,:] = img[:,:,:]  
  3. >>> d[:,:,:] = img[:,:,:]  
  4. >>> c is a  
  5. False  
  6. >>> d is a  
  7. False  
  8. >>> c.base is a  
  9. False  
  10. >>> d.base is a #注意这里!!!  
  11. True  
这里,d只是a的镜像,具体请参考《 NumPy简明教程(二,数组3 )》中的“复制和镜像”一节。

通道合并

同样,通道合并也有两种方法。第一种是OpenCV自带的merge函数,如下:

[python]  view plain  copy
  1. merged = cv2.merge([b,g,r]) #前面分离出来的三个通道  
接着是NumPy的方法:
[python]  view plain  copy
  1. mergedByNp = np.dstack([b,g,r])   
注意:这里只是演示,实际使用时请用OpenCV自带的merge函数! 用NumPy组合的结果不能在OpenCV中其他函数使用,因为其组合方式与OpenCV自带的不一样,如下:
[python]  view plain  copy
  1. merged = cv2.merge([b,g,r])  
  2. print "Merge by OpenCV"   
  3. print merged.strides  
  4.   
  5. mergedByNp = np.dstack([b,g,r])   
  6. print "Merge by NumPy "   
  7. print mergedByNp.strides  
结果为:
[python]  view plain  copy
  1. Merge by OpenCV  
  2. (112531)  
  3. Merge by NumPy  
  4. (1500187500)  
NumPy数组的strides属性表示的是在每个维数上以字节计算的步长。这怎么理解呢,看下面这个简单点的例子:
[python]  view plain  copy
  1. >>> a = np.arange(6)  
  2. >>> a  
  3. array([012345])  
  4. >>> a.strides  
  5. (4,)  
a数组中每个元素都是NumPy中的整数类型,占4个字节,所以第一维中相邻元素之间的步长为4(个字节)。

同样,2维数组如下:

[python]  view plain  copy
  1. >>> b = np.arange(12).reshape(3,4)  
  2. >>> b  
  3. array([[ 0,  1,  2,  3],  
  4.        [ 4,  5,  6,  7],  
  5.        [ 8,  91011]])  
  6. >>> b.strides  
  7. (164)  
从里面开始看,里面是一个4个元素的一维整数数组,所以步长应该为4。外面是一个含有3个元素,每个元素的长度是4×4=16。所以步长为16。

下面来看下3维数组:

[python]  view plain  copy
  1. >>> c = np.arange(27).reshape(3,3,3)  
其结果为:
[python]  view plain  copy
  1. array([[[ 0,  1,  2],  
  2.         [ 3,  4,  5],  
  3.         [ 6,  7,  8]],  
  4.   
  5.        [[ 91011],  
  6.         [121314],  
  7.         [151617]],  
  8.   
  9.        [[181920],  
  10.         [212223],  
  11.         [242526]]])  
根据前面了解的,推断下这个数组的步长。从里面开始算,应该为(3×4×3,3×4,4)。验证一下:
[python]  view plain  copy
  1. >>> c.strides  
  2. (36124)  
完整的代码为:
[python]  view plain  copy
  1. import cv2  
  2. import numpy as np  
  3.   
  4. img = cv2.imread("D:/cat.jpg")  
  5.   
  6. b = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)  
  7. g = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)  
  8. r = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)  
  9.   
  10. b[:,:] = img[:,:,0]  
  11. g[:,:] = img[:,:,1]  
  12. r[:,:] = img[:,:,2]  
  13.   
  14. merged = cv2.merge([b,g,r])  
  15. print "Merge by OpenCV"   
  16. print merged.strides  
  17. print merged  
  18.   
  19. mergedByNp = np.dstack([b,g,r])   
  20. print "Merge by NumPy "   
  21. print mergedByNp.strides  
  22. print mergedByNp  
  23.   
  24. cv2.imshow("Merged", merged)  
  25. cv2.imshow("MergedByNp", merged)  
  26. cv2.imshow("Blue", b)  
  27. cv2.imshow("Red", r)  
  28. cv2.imshow("Green", g)  
  29. cv2.waitKey(0)  
  30. cv2.destroyAllWindows()  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值