您的位置:首页 > 编程语言 > Python开发

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

2013-12-09 21:52 579 查看


访问像素

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

[python] view
plaincopy

img[j,i] = 255

其中j,i分别表示图像的行和列。对于BGR图像,为:

[python] view
plaincopy

img[j,i,0]= 255

img[j,i,1]= 255

img[j,i,2]= 255

第三个数表示通道。

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

[python] view
plaincopy

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数组来分离通道。直接法为:

[python] view
plaincopy

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()

其中split返回RGB三个通道,如果只想返回其中一个通道,可以这样:

[python] view
plaincopy

b = cv2.split(img)[0]

g = cv2.split(img)[1]

r = cv2.split(img)[2]

最后的索引指出所需要的通道。

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

[python] view
plaincopy

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()

注意先要开辟一个相同大小的图片出来。这是由于numpy中数组的复制有些需要注意的地方,具体事例如下:

[python] view
plaincopy

>>> 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

这里,d只是a的镜像,具体请参考《NumPy简明教程(二,数组3)》中的“复制和镜像”一节。


通道合并

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

[python] view
plaincopy

merged = cv2.merge([b,g,r]) #前面分离出来的三个通道

接着是NumPy的方法:

[python] view
plaincopy

mergedByNp = np.dstack([b,g,r])

注意:这里只是演示,实际使用时请用OpenCV自带的merge函数!用NumPy组合的结果不能在OpenCV中其他函数使用,因为其组合方式与OpenCV自带的不一样,如下:

[python] view
plaincopy

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

结果为:

[python] view
plaincopy

Merge by OpenCV

(1125, 3, 1)

Merge by NumPy

(1, 500, 187500)

NumPy数组的strides属性表示的是在每个维数上以字节计算的步长。这怎么理解呢,看下面这个简单点的例子:

[python] view
plaincopy

>>> a = np.arange(6)

>>> a

array([0, 1, 2, 3, 4, 5])

>>> a.strides

(4,)

a数组中每个元素都是NumPy中的整数类型,占4个字节,所以第一维中相邻元素之间的步长为4(个字节)。

同样,2维数组如下:

[python] view
plaincopy

>>> 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)

从里面开始看,里面是一个4个元素的一维整数数组,所以步长应该为4。外面是一个含有3个元素,每个元素的长度是4×4=16。所以步长为16。

下面来看下3维数组:

[python] view
plaincopy

>>> c = np.arange(27).reshape(3,3,3)

其结果为:

[python] view
plaincopy

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]]])

根据前面了解的,推断下这个数组的步长。从里面开始算,应该为(3×4×3,3×4,4)。验证一下:

[python] view
plaincopy

>>> c.strides

(36, 12, 4)

完整的代码为:

[python] view
plaincopy

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()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐