很多非科班出身(或是科班但大学没认真学习)的程序员,听到类似“哈希表”、“树/图”、“矩阵”之类的数据结构/数学专业词汇都会觉得头大。
计算机图像处理,矩阵是基础,未来无论多高级的功能都要用到。接下来我会尽量避开数学的东西,用形象的方式来讲。(其实我读书时比大家好不到哪儿去——既非科班出身,又没有认真学习-_-#)。
照例啰嗦完,下面开始。
0. 理解矩阵
看一张图:
这是一个3x3矩阵(3行3列,行在前列在后),行列索引均从0开始。
1. 代码创建矩阵
从 cv2
接口开始,OpenCV Python使用 numpy 作为其官方矩阵处理库。运行以下代码以创建上图的矩阵:
import numpy as np
mat = np.array([
[ 0, 100, 0 ],
[ 100, 255, 100 ],
[ 0, 100, 0 ]])
print(mat)
没错,二维矩阵其实就是个二维数组。
2. 矩阵与图像
矩阵和图像有什么关系?我们尝试将矩阵当做图片显示出来(为了便于观看,矩阵被放大100倍):
import cv2
import numpy as np
mat = np.array([
[ 0, 100, 0 ],
[ 100, 255, 100 ],
[ 0, 100, 0 ]], dtype = np.uint8)
resized = np.kron(mat, np.ones((100, 100))) # 【调试用,勿深究】将矩阵放大100倍便于观看
resized = resized.astype(np.uint8) # 【调试用,勿深究】由于np.kron会改变dtype类型为float64,这里我们转回uint8
cv2.imshow('3x3 Matrix', resized)
cv2.waitKey()
(中间两行是为了放大图像写的调试代码,你可以删掉试试看效果)
运行结果如下:
可以看到,刚刚矩阵中的数值,其实是最简单的颜色——灰度值,0为黑色,255为白色,中间线性变化(所以100是灰色)。请仔细对比矩阵图和结果图观察每个像素值和显示色彩。
所以,OpenCV中矩阵即图片。
2. 彩色图像
上面我们说了灰度图的创建,接下来考虑一下彩色图。
OpenCV官方最常用的是BGR图像(注意和RGB图像色彩顺序是反的)。灰度图每个像素用1个0~255的值表示,BGR彩色图则每个像素包含B(Blue 蓝色)、G(Green 绿色)、R(Red 红色)3个值,也是用0~255表示。看图理解:
依然是9个像素,部分像素解析:
- [0,0](0行0列)像素BGR均为0,所以依然是黑色
- [0,1](0行1列)像素第一个值B为100,GR均为0,所以是蓝色
- [1,0](1行0列)像素BG均为0,R为100,所以是红色
- [1,1](1行1列)像素BGR均为255,所以是白色
修改之后的代码如下:
import cv2
import numpy as np
mat = np.array([
[ [ 0, 0, 0 ], [ 100, 0, 0 ], [ 0, 0, 0 ] ],
[ [ 0, 0, 100 ], [ 255, 255, 255 ], [ 0, 0, 100 ] ],
[ [ 0, 0, 0 ], [ 100, 0, 0 ], [ 0, 0, 0 ] ]], dtype = np.uint8)
resized = np.kron(mat, np.ones((100, 100, 1))) # 【调试用,勿深究】将矩阵放大100倍便于观看
resized = resized.astype(np.uint8) # 【调试用,勿深究】由于np.kron会改变dtype类型为float64,这里我们转回uint8
cv2.imshow('3x3 Matrix', resized)
cv2.waitKey()
可以看到我们在原来灰度图二维数组基础之上,将每个元素由原来的int改为了一个包含BGR 3个数值的数组(注意放大时的矩阵也扩大了一个维度)。效果如下:
同样请大家仔细对比矩阵图和结果图的每个像素,并请大家动手改一改代码中的矩阵内容,将两侧的红色改为绿色。
好了,大家平时看到的色彩丰富的照片,也都是用这种方式组成的,只是矩阵更大一些,例如下面是一个3264 x 2448的3通道RGB矩阵(如果舍得花时间,也是可以一个像素一个像素手工填出来的!-_-):
(摄于2017年1月香港铜锣湾凌晨1点)
3. 通道的概念
通道的概念很重要,下面的内容偏理论一点,但请尽量理解:
1)通道就是每个像素拥有的色彩维度
- 对于灰度图,只有一个色彩维度,所以是单通道(灰度图也被称为单通道二维矩阵)
- 对于BGR彩色图,有BGR三个色彩维度,所以是3通道
- 像RGBA彩色图,则有四个色彩维度(A是Alpha透明度),所以是4通道
- 类似的还有YUV、HSL等色彩模型(未来会详细介绍),也是3通道
- 如果我们将BGR中,所有B通道值取出来组成一个二维矩阵,就形成了单通道二维矩阵,即灰度图,这个灰度图描述了当前图像蓝色分布
- 如果我们要将一张照片中的红色调低,则可以将BGR图像拆分成3个通道灰度图,然后将R通道灰度图的亮度调低(例如每个值都缩小为原有的0.5),再将3个通道合并回BGR图像
2)几乎所有的OpenCV图像都可以被表示为3维矩阵(数组)
- 从代码来看,1维矩阵就是普通数组,2维矩阵就是2维数组,3维矩阵就是3维数组
- OpenCV图像3维矩阵中的3维按顺序是:1维-行,2维-列,3维-通道
- 如果3维矩阵不好理解,可以理解成2维矩阵,矩阵中每个元素都包含1、3或4个数值(暂时不存在2通道颜色空间)
如果之前对矩阵等不太熟悉,可能会有点难理解,没关系,多写多思考,慢慢就好了。
以上是一些图像矩阵基础知识,以及矩阵的创建,为了让大家理解OpenCV原理,特意没有像其他教程一样从加载图片中来分析,希望大家能够学到东西。下一篇继续讲矩阵操作。