最常见的色彩空间就是RGB,人眼也是基于RGB的色彩空间去分辨颜色的。OpenCV 默认使用的是BGR。
RGB和BGR色彩空间的区别在于图片在色彩通道上的排列顺序不同。
1、RGB 如下图所示:
2、BGR 如下图所示:
显示图片的时候需要注意适配图片的色彩空间和显示环境的色彩空间。
比如传入的图片是BGR色彩空间,显示环境是RGB色彩空间,就会出现颜色混乱的情况。
1、HSV(HSB)
OpenCV用的最多的色彩空间是HSV。
2、HSL
HUE:色相,色彩的基本属性,就是平常所说的颜色名称。如红色、黄色等。
Saturation:色彩的纯度,越高色彩越纯,低则逐渐变灰,取0%~100%的数值。
Lightness:亮度,取0%~100%
3、HSV 和 HSL 的区别:
4、YUV
YUV,是一种颜色编码方法。常使用在各个视频处理组件中。 YUV在对照片或视频编码时,考虑到人类的感知能力,允许降低色度的带宽。
“Y”表示明亮度(Luminance或Luma),也就是灰阶值,“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
YUV的发明是由于彩色电视与黑白电视的过渡时期。
黑白视频只有Y(Luma,Luminance)视频,也就是灰阶值。到了彩色电视规格的制定,是以YUV/YIQ的格式来处理彩色电视图像,把UV视作表示彩度的C(Chrominance或Chroma),如果忽略C信号,那么剩下的Y(Luma)信号就跟之前的黑白电视频号相同,这样一来便解决彩色电视机与黑白电视机的兼容问题。
YUV最大的优点在于只需占用极少的带宽。
为节省带宽起见,大多数YUV格式平均使用的每像素位数都少于24位。主要的抽样(subsample)格式有YCbCr4:2:0、YCbCr4:2:2、YCbCr4:1:1和YCbCr4:4:4。YUV的表示法称为A:B:C表示法:
cvtColor()
用法:
cv2.cvtColor(img, colorspace)
参数说明:
cv2.COLOR_BGR2RGBA
是将BGR格式转换为RGBA格式
import cv2
def callback(value):
print(value)
cv2.namedWindow('color', cv2.WINDOW_NORMAL)
cv2.resizeWindow('color', 640, 480)
# OpenCV读取的图像默认是BGR的色彩空间
img = cv2.imread('../resource/dog.jpg')
# 定义颜色空间转换列表 2 = to
color_spaces = [
cv2.COLOR_BGR2RGBA, cv2.COLOR_BGR2BGRA,
cv2.COLOR_BGR2GRAY, cv2.COLOR_BGR2HSV,
cv2.COLOR_BGR2YUV
]
# 创建Trackbar
cv2.createTrackbar('trackbar', 'color', 0, 4, callback)
while True:
# 获取当前Trackbar值
index = cv2.getTrackbarPos('trackbar', 'color')
# 颜色空间转换API
cvt_img = cv2.cvtColor(img, color_spaces[index])
cv2.imshow('color', cvt_img)
key = cv2.waitKey(10)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
Numpy是一个经高度优化的Python数值库。OpenCV中用到的矩阵都要转换成Numpy数组,然后再进行后续操作。
在使用Numpy进行基本操作时,都需要导入Numpy库,即import numpy as np
。
1、创建数组 array()
a = np.array([1, 2, 3])
b = np.array([[1, 3, 5], [2, 4, 6]])
2、创建全 0 / 1 数组 zeros() / ones()
zeros()
用法:
c = np.zeros((480, 640, 3), np.uint8)
参数说明:
实例1:4 * 4 * 3(方便演示)
c = np.zeros((4, 4, 3), np.uint8)
print(c)
[[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]]
实例2:4 * 4(可以不指定通道数/层数,即默认1通道/层)
c = np.zeros((4, 4), np.uint8)
print(c)
[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]]
ones()
用法:
d = np.ones((480, 640, 3), np.uint8)
ones() 用法和 zeros() 用法基本一致,其主要区别是:ones() 创建的数组值都为 1 ,而 zeros() 创建的数组都为 0 。
3、创建全值数组 full()
full()
用法:
e = np.full((480, 640, 3), 255, np.uint8)
参数说明:
实例1:
e = np.full((4, 4, 3), 255, np.uint8)
print(e)
[[[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]]
[[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]]
[[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]]
[[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]]]
实例2:当然也可以不指定通道数/层数
e = np.full((4, 4), 255, np.uint8)
print(e)
[[255 255 255 255]
[255 255 255 255]
[255 255 255 255]
[255 255 255 255]]
4、创建单元数组 identity() / eye()
identity()
用法:
f = np.identity(3)
参数说明:
实例1:3 * 3
f = np.identity(3)
print(f)
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
实例2:5 * 5
f = np.identity(5)
print(f)
[[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 1.]]
eye()
用法:
g = np.eye(3, 5, k=3)
参数说明:
实例1:
g = np.eye(3, 5, k=3)
print(g)
[[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 1.]
[0. 0. 0. 0. 0.]]
实例2:如果不指定k或者k为0,则默认从一个开始(下标为0)也就是主对角线赋1,其它为0.
g = np.eye(3, 5)
h = np.eye(3, 5, 0)
print(g)
print(h)
[[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0.]]
# 效果一样
[[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0.]]
1、检索
img = np.zeros((480, 640, 3), np.uint8)
print(img[100, 100])
[0 0 0]
img = np.zeros((480, 640, 3), np.uint8)
print(img[100, 100, 0])
0
channel用来指定通道数,由于OpenCV默认是BGR三通道,所以取值0,1,2
2、赋值
实例1:img[y, x] = 255
img[count, 100] = 255
不指定channel,默认白色。
实例2:img[y, x] = [B, G, R]
通道组合 [B, G, R] 一般只需掌握以下几种:
img[count, 100] = [0, 0, 255]
img[count, 100] = [255, 255, 255]
实例3:img[y, x, channel] = 255
OpenCV默认是BGR三通道,所以channel可以取0、1或2,即:
img[count, 100, 0] = 255
代码实现(完整)
import cv2
import numpy as np
img = np.zeros((480, 640, 3), np.uint8)
# 从矩阵中读取某个元素的值
print(img[100, 100])
print(img[100, 100, 1])
count = 0
# 向矩阵中某个元素赋值
while count < 200:
# img[count, 100] = 255
# img[count, 100, 0] = 255
img[count, 100] = [255, 255, 255]
count += 1
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
1、[y1: y2, x1: x2]
获取像素点x1~x2,y1~y2的区域。
2、[:, :]
或 [:]
获取所有像素点。
import cv2
import numpy as np
img = np.zeros((480, 640, 3), np.uint8)
roi = img[100:400, 100:600]
# roi[:, :] = [0, 0, 255]
roi[:] = [0, 0, 255]
roi[10:200, 10:200] = [0, 255, 0]
cv2.imshow('img', roi)
cv2.waitKey(0)
cv2.destroyAllWindows()
Mat是OpenCV在 C++ 语言中用来表示图像数据的一种数据结构,在 Python 中转换为numpy的ndarray。
class CV_EXPORTS Mat{
public:
...
int dims; //维数
int rows, cols; //行、列数
uchar *data; //存储数据的指针
int *refcount; //引用计数
...
};
字段 | 说明 | 字段 | 说明 |
---|---|---|---|
dims | 维度 | channels | 通道数 RGB是3 |
rows | 行数 | size | 矩阵大小 |
cols | 列数 | type | dep + dt + chs CV_8UC3 |
depth | 像素的位深 | data | 存放数据 |
Mat拷贝时默认为浅拷贝,只拷贝Header中的内容,数据不变。
1、Mat浅拷贝
Mat A
A = imread(file, IMREAD_COLOR)
Mat B(A)
B 与 A 的 Header 不同,但指向的数据相同,如下代码:
img1 = cv2.imread('../resource/cold.jpg', cv2.IMREAD_COLOR)
img2 = img1
img1[10:100, 10:100] = [0, 0, 255]
2、Mat深拷贝
C++中实现方式有两种:
cv::Mat::clone()
cv::Mat::copyTo()
将 Data 也重新赋值一份,A 与 B 完全切断。
在Python中:
img3 = img1.copy()
进行深拷贝后,进行图片处理时不影响原图片。
img1 = cv2.imread('../resource/cold.jpg', cv2.IMREAD_COLOR)
img3 = img1.copy()
img1[10:100, 10:100] = [0, 0, 255]
import cv2
img1 = cv2.imread('../resource/cold.jpg', cv2.IMREAD_COLOR)
# 浅拷贝
img2 = img1
# 深拷贝
img3 = img1.copy()
img1[10:100, 10:100] = [0, 0, 255]
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
img = cv2.imread('../resource/structure.jpg', cv2.IMREAD_COLOR)
方便演示!
1、img.shape
用法:
shape 中包含三个信息:高度、宽度和通道数。
print(img.shape)
(3000, 4500, 3)
即该图像(高:3000,宽:4500,通道数:3)。
2、img.size
用法:
size 即图像占用空间 = 高度 * 宽度 * 通道数 。
print(img.size)
40500000
3000 * 4500 * 3 = 40500000
3、img.dtype
用法:
dtype 表示图像中每个元素的位深。
print(img.dtype)
uint8
uint8 表示 8位无符号整型(0~255)。
1、split(mat)
: 分离
import cv2
import numpy as np
img = np.zeros((480, 640, 3), np.uint8)
b, g, r = cv2.split(img)
b[10:100, 10:100] = 255
g[10:100, 10:100] = 255
cv2.imshow('img', img)
cv2.imshow('b', b)
cv2.imshow('g', g)
cv2.waitKey(0)
cv2.destroyAllWindows()
2、merge((ch1, ch2, ...))
: 合并
import cv2
import numpy as np
img = np.zeros((480, 640, 3), np.uint8)
b, g, r = cv2.split(img)
b[10:100, 10:100] = 255
g[10:100, 10:100] = 255
img_merge = cv2.merge((b, g, r))
cv2.imshow('img', img)
cv2.imshow('b', b)
cv2.imshow('g', g)
cv2.imshow('img_merge', img_merge)
cv2.waitKey(0)
cv2.destroyAllWindows()