OpenCV轻松入门:面向Python
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 使用numpy.array访问像素

numpy.array提供了item()和itemset()函数来访问和修改像素值,而且这两个函数都是经过优化处理的,能够更大幅度地提高处理效率。在访问及修改像素点的值时,利用numpy.array提供的函数比直接使用索引要快得多,同时,这两个函数的可读性也更好。

1.二值图像及灰度图像

可以将二值图像理解为特殊的灰度图像,所以这里仅以灰度图像为例讨论像素点值的读取和修改。

函数item()能够更加高效地访问图像的像素点,该函数的语法格式为:

        item(行,列)

函数itemset()可以用来修改像素值,其语法格式为:

        itemset(索引值,新值)

为了便于理解,我们首先使用Numpy库生成一个5×5大小的随机数组,用来模拟一幅灰度图像,并对其进行简单的处理。

例2.7】使用Numpy生成一个二维随机数组,用来模拟一幅灰度图像,并对其像素进行访问、修改。

分析:使用Numpy中的random.randint可以生成一个随机数组,该随机数组对应一幅灰度图像。然后分别使用函数item()及函数itemset()对其像素进行访问、修改。

根据题目要求及分析,编写代码如下:

        import numpy as np
        img=np.random.randint(10,99, size=[5,5], dtype=np.uint8)
        print("img=\n", img)
        print("读取像素点img.item(3,2)=", img.item(3,2))
        img.itemset((3,2),255)
        print("修改后img=\n", img)
        print("修改后像素点img.item(3,2)=", img.item(3,2))

运行程序,控制台输出结果如下:

        img=
         [[69 11 79 35 84]
         [87 10 63 12 20]
         [31 67 68 16 45]
         [81 26 61 51 28]
         [33 94 18 71 53]]
        读取像素点img.item(3,2)= 61
        修改后img=
         [[ 69  11  79  35  84]
         [ 87  10  63  12  20]
         [ 31  67  68  16  45]
         [ 81  26255  51  28]
         [ 33  94  18  71  53]]
        修改后像素点img.item(3,2)= 255

通过观察输出结果可以发现,语句img.itemset((3,2),255)将图像第3行第2列位置上的像素值修改为255了。

在例2.7中,为方便读者仔细观察数组内的每一个值,生成的数组规模(尺寸)较小。在实际使用中,可以利用随机函数生成更大尺寸的随机数组,并使用函数imshow()观察随机数组对应的灰度图像。

例2.8】生成一个灰度图像,让其中的像素值均为随机数。

根据题目要求,编写代码如下:

        import numpy as np
        import cv2
        img=np.random.randint(0,256, size=[256,256], dtype=np.uint8)
        cv2.imshow("demo", img)
        cv2.waitKey()
        cv2.destroyAllWindows()

运行上述程序,可以生成一幅256×256大小的灰度图像,如图2-12所示。

图2-12 随机灰度图像

例2.9】读取一幅灰度图像,并对其像素值进行访问、修改。

根据题目要求,编写代码如下:

        import cv2
        img=cv2.imread("lena.bmp",0)
        #测试读取、修改单个像素值
        print("读取像素点img.item(3,2)=", img.item(3,2))
        img.itemset((3,2),255)
        print("修改后像素点img.item(3,2)=", img.item(3,2))
        #测试修改一个区域的像素值
        cv2.imshow("before", img)
        for i in range(10,100):
            for j in range(80,100):
              img.itemset((i, j),255)
        cv2.imshow("after", img)
        cv2.waitKey()
        cv2.destroyAllWindows()

本程序首先修改了一个像素点的像素值:使用item()函数读取了第3行第2列位置上的像素值;接下来使用itemset()函数对该像素值进行了修改。

接下来使用嵌套循环语句修改了一个区域的像素值,将位于“第10行到第99行”和“第80列到第99列”的行列交叉区域的像素值设置(修改)为255,即让该区域显示为白色。

运行上述程序,显示如图2-13所示图像,其中,左图是读取的原始图像,右图是修改部分像素后得到的图像。

图2-13 【例2.9】程序的运行结果

同时,在控制台得到如下结果:

        读取像素点img.item(3,2)= 159
        修改后像素点img.item(3,2)= 255

2.彩色图像

我们也可以使用函数item()和函数itemset()来访问和修改彩色图像的像素值,过程与操作灰度图像相似,不同之处在于需要补充通道信息。

函数item()访问RGB模式图像的像素值时,其语法格式为:

        item(行,列,通道)

函数itemset()修改(设置)RGB模式图像的像素值时,其语法格式为:

        itemset(三元组索引值,新值)

需要注意,针对RGB图像的访问,必须同时指定行、列以及行列索引(通道),例如img.item(a, b, c)。仅仅指定行和列是不可以的。

例2.10】使用Numpy生成一个由随机数构成的三维数组,用来模拟一幅RGB色彩空间的彩色图像,并使用函数item()和itemset()来访问和修改它。

根据题目要求,编写代码如下:

        import numpy as np
        img=np.random.randint(10,99, size=[2,4,3], dtype=np.uint8)
        print("img=\n", img)
        print("读取像素点img[1,2,0]=", img.item(1,2,0))
        print("读取像素点img[0,2,1]=", img.item(0,2,1))
        print("读取像素点img[1,0,2]=", img.item(1,0,2))
        img.itemset((1,2,0),255)
        img.itemset((0,2,1),255)
        img.itemset((1,0,2),255)
        print("修改后img=\n", img)
        print("修改后像素点img[1,2,0]=", img.item(1,2,0))
        print("修改后像素点img[0,2,1]=", img.item(0,2,1))
        print("修改后像素点img[1,0,2]=", img.item(1,0,2))

运行上述程序,在控制台得到如下输出结果:

        img=
         [[[71 32 69]
          [43 73 67]
          [30 48 93]
          [79 52 69]]
        [[66 60 48]
          [68 17 10]
          [92 79 20]
          [70 14 85]]]
        读取像素点img[1,2,0]= 92
        读取像素点img[0,2,1]= 48
        读取像素点img[1,0,2]= 48
        修改后img=
         [[[ 71  32  69]
          [ 43  73  67]
          [ 30255  93]
          [ 79  52  69]]
        [[ 66  60255]
          [ 68  17  10]
          [255  79  20]
          [ 70  14  85]]]
        修改后像素点img[1,2,0]= 255
        修改后像素点img[0,2,1]= 255
        修改后像素点img[1,0,2]= 255

在本例中,为了方便读者细致观察数组内的值,生成的数组尺寸较小。在实际使用中,读者可以利用随机函数生成更大尺寸的随机数组,并使用函数cv2.imshow()观察随机数组对应的彩色图像。

例2.11】生成一幅彩色图像,让其中的像素值均为随机数。

根据题目要求,编写代码如下:

        import cv2
        import numpy as np
        img=np.random.randint(0,256, size=[256,256,3], dtype=np.uint8)
        cv2.imshow("demo", img)
        cv2.waitKey()
        cv2.destroyAllWindows()

上述程序可以生成一幅256×256×3的彩色图像,显示的图像如图2-14所示。由于本书为黑白印刷,所以为了更好地观察运行效果,请大家亲自上机运行程序。

图2-14 随机图像

例2.12】读取一幅彩色图像,并对其像素进行访问、修改。

根据题目要求,编写代码如下:

        import cv2
        import numpy as np
        img=cv2.imread("lenacolor.png")
        cv2.imshow("before", img)
        print("访问img.item(0,0,0)=", img.item(0,0,0))
        print("访问img.item(0,0,1)=", img.item(0,0,1))
        print("访问img.item(0,0,2)=", img.item(0,0,2))
        for i in range(0,50):
            for j in range(0,100):
              for k in range(0,3):
                  img.itemset((i, j, k),255)    #白色
        cv2.imshow("after", img)
        print("修改后img.item(0,0,0)=", img.item(0,0,0))
        print("修改后img.item(0,0,1)=", img.item(0,0,1))
        print("修改后img.item(0,0,2)=", img.item(0,0,2))

在本程序中,首先,使用item()函数读取了第0行第0列位置上的B通道、G通道、R通道三个通道上的像素值;接着,使用itemset()函数对该值进行了修改;最后,使用嵌套循环语句将位于“第0行到第49行”和“第0列到第99列”的交叉区域内的像素值设置为了255,即让该区域显示为白色。

运行上述程序,得到如图2-15所示结果,其中左图是读取的原始图像,右图是修改后的图像。由于本书为黑白印刷,所以为了更好地观察运行效果,请大家亲自上机运行程序。

图2-15 【例2.12】程序的运行结果

同时,会在控制台显示如下结果:

        访问img.item(0,0,0)= 125
        访问img.item(0,0,1)= 137
        访问img.item(0,0,2)= 226
        修改后img.item(0,0,0)= 255
        修改后img.item(0,0,1)= 255
        修改后img.item(0,0,2)= 255