计算机视觉:三、图像基础
本文我们将回顾构建图像的基础元素:像素。
-
什么是像素?
每个图像都由一组像素构成,像素是图像原生的基础构件,没有比像素更好的粒度(granularity)了。
一般来说,我们认为像素是图像中某个给定位置出现的光的"颜色"或者"强度"。
如果我们将图像看成一个网格,网格中的每个方块就包含一个像素。
例如,如果我们有一个分辨率为10*10的图像,这就说明我的图像被表示为一个像素网格,这个网格有10行10列。整体来说,图像中共有10✖️10=100个像素,如图。
当然我们平时所见的图像,远远不止于此,一般普通的图片都在500*300左右。
这样说来,我们的图片能被一个300*500的像素网格所表示,500行300列。总体来看共有150000个像素。
大多数的像素以两种方式来表示:灰度和彩色。灰度图中每个像素的取值范围仅仅是0-255,0对应黑色,255对应白色。0-255中间的数值则对应着灰色。
而彩色像素通常以RGB色彩空间来表示,每个像素分别有R、G、B三个值。这三个颜色分别用0-255区间中的整数来表示,代表着这个颜色的成分有多少。因为取值范围在[0,255]之间,所以通常用8位无符号整数来表示。
然后把这三个值组合成RGB三元组(red,green,blue),以此来表示颜色。
白色:(255, 255, 255)
黑色:(0, 0, 0)
红色:(255, 0, 0)
...
- 坐标系
如上所述,一副图像可以被表示为一个像素网格。将我们的网格想想为一张图表,图像的左上角对应着点(0, 0),当我们从该点出发向右或者向下移动时,x , y的坐标开始增加。
-
操纵像素
上篇文章计算机视觉:二、加载、显示与创建图片中的代码仅仅是从磁盘中读取图像、展示图像,并换一种格式保存到指定的目录下,显然还不够有趣。
接下来我们做点更有意思的事情:对图像中的像素进行处理和操作。
上代码:
import cv2
import numpy as np
import argparse
ap = argparse.ArgumentParser()
ap.add_argument("-I", "--image", required=True,
help="the path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
cv2.imshow("origin", image)
cv2.waitKey(0)
和之前一样,读入一张图片并展示。
执行命令
python manipulatePixel.py --image ~/Desktop/1.jpeg
又看见了这只可爱的小松鼠,那么按照我们之前说的,这幅松鼠的图像在计算机中是用一组像素来表示的,那么我们能否对这组像素做一些操作呢?
显然是可以的,我们通过指定在坐标系中的x和y坐标来确定我们要操作的像素。同时,我们可以通过给定的三元组来表示图像的红、绿和蓝色成分。
但是,我们需要注意的是OpenCV中以相反的顺序来存储RGB通道,也就是说,通常我们说的RGB通道在OpenCV中以蓝、绿、红的顺序来存储。这点需要特别注意以免后面出现混淆。
现在,让我们通过代码来实现对像素的操作吧:
在上面的代码后面追加:
(b, g, r) = image[0, 0]
print("(0,0)处的像素:红色:{},绿色:{},蓝色:{}".format(r, g, b))
image[0, 0] = (0, 0, 255)
(b, g, r) = image[0, 0]
print("(0,0)处的像素:红色:{},绿色:{},蓝色:{}".format(r, g, b))
可以看到,我们将图像中的(0,0)坐标处的像素分解成一个三元组(b, g, r),分别代表该像素的蓝、绿、红三个通道,并将他们分别输出。
然后再将该点处像素三个通道的值改变成(0, 0, 255)后分别输出。
当我们点击展示处的图像,并按下任意键后,输出下列信息。
(0,0)处的像素:红色:41,绿色:64,蓝色:22
(0,0)处的像素:红色:255,绿色:0,蓝色:0
可以看到(0,0)处的像素信息被打印出来,随后该值被改变,又再一次被输出。
我们可以如此简单的读取并操作图片中的像素都是因为NumPy的帮助。
上面的代码只对单个的像素值进行操作,看起来非常简单但如果我们想对图像的某个区域进行操作呢?我们可以利用NumPy的切片能力来完成,我们在上述的代码下追加如下代码:
corner = image[0:100, 0:100]
cv2.imshow("Corner", corner)
image[0:100, 0:100] = (255, 0, 0)
cv2.imshow("changed", image)
cv2.waitKey(0)
我们定义了一个新的数组,这个数组复制了小松鼠图像的左上角x=0到x=100 ,y=0到y=100的矩形的像素信息,将这个矩形定义为变量corner
然后改变了原来的image图像,将原来图像的x=0到x=100 ,y=0到y=100的矩形的像素值改变为(255, 0 , 0),也就是将图像左上角边长为100像素的矩形的像素改变为蓝色。
执行该程序,效果如下所示:
这里我们注意一下切片的用法:
[x1:x2 , y1:y2]表示数组中从x = x1 到 x = x2 从y = y1 到y = y2的矩形切片。
总结:
今天我们主要学习了图像的基础表示:像素的概念和组成。通过执行x和y坐标来读取和改变单个像素点的信息。然后通过数组切片的来读取和改变图像中某个区域的像素的信息。
参考书籍:Practical Python and OpenCV