OpenCV-Python:图像元素的访问、通道分离和合并

访问像素

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

img[j,i] = 255

# 其中 j, i 分别表示图像的行和列。对于 BGR 图像,为:
img[j,i,0] =255
img[j,i,1] =255
img[j,i,2] =255

# 第三个数表示通道

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

#! user/bin/env python3
# -*- coding: utf-8 -*- 
# @filename: salt.py
# @author: yang

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
#与C++不同,在 python 中灰度图像 img.ndim =2, 而在 C++ 中灰度图像的通道数 img.channel() =1。
if __name__ == "__main__":
    img = cv2.imread("cat.jpg")
    saltImage = salt(img, 500)
    cv2.imshow("Img", img)
    cv2.imshow("Salt", saltImage)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

效果图:

OpenCV-Python:图像元素的访问、通道分离和合并_第1张图片

 

分离通道

由于OpenCV Python 和 Numpy 结合的很紧,所以可以使用 OpenCV 自带的 split 函数,也可以直接操作 numpy 

数组来分离通道。

import cv2
import numpy as np

img = cv2.imread("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 三个通道,如果只想返回其中一个通道,可以这样:

b = cv2.split(img)[0]
g = cv2.split(img)[1]
r = cv2.split(img)[2]

# 通过索引指出所需要的通道

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

#! user/bin/env python3
# -*- coding: utf-8 -*- 
# @filename: salt.py
# @author: yang

import cv2
import numpy as np

img = cv2.imread("1.jpg")
img= cv2.resize(img, (0, 0), fx=0.1, fy=0.1, interpolation=cv2.INTER_NEAREST)

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)

print(b)

b[:,:] = img[:,:,0]
g[:,:] = img[:,:,1]
r[:,:] = img[:,:,2]

cv2.imshow("Blue",b)
cv2.imshow("Green",g)
cv2.imshow("Red",r)
print(b)
cv2.waitKey(0)
cv2.destroyAllWindows()

通道合并

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

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

接着是 NumPy 的方法:

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


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


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)


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


>>> a = np.arange(6)
>>> a
array([0, 1, 2, 3, 4, 5])
>>> a.strides
(4,)

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


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

>>> c = np.arange(27).reshape(3,3,3)
>>> c
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)。验证一下:
>>> 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()


 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(OpenCV-Python)