【OpenCV图像处理2】OpenCV 基础知识

二、OpenCV 基础知识

1、OpenCV 的色彩空间

1.1 RGB 和 BGR

最常见的色彩空间就是RGB,人眼也是基于RGB的色彩空间去分辨颜色的。OpenCV 默认使用的是BGR

RGB和BGR色彩空间的区别在于图片在色彩通道上的排列顺序不同

1、RGB 如下图所示:

2、BGR 如下图所示:

显示图片的时候需要注意适配图片的色彩空间和显示环境的色彩空间。

比如传入的图片是BGR色彩空间,显示环境是RGB色彩空间,就会出现颜色混乱的情况。

1.2 HSV、HSL 和 YUV

1、HSV(HSB)

  • Hue:色相,即色彩,如红色、绿色、蓝色。
    • 用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。
    • 它们的补色是:黄色为60°,青色为180°,紫色为300°。
  • Saturation:饱和度,表示颜色接近光谱色的程度。
    • 一种颜色,可以看成是某种光谱色与白色混合的结果。
      • 其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。
      • 饱和度高,颜色则深而艳。
      • 光谱色的白光成分为0,饱和度达到最高。
    • 通常取值范围为0%~100%,值越大,颜色越饱和。
  • Value(Brightness):明度,表示颜色明亮的程度。
    • 对于光源色,明度值与发光体的光亮度有关;
    • 对于物体色,该值和物体的透射比或反射比有关。
    • 通常取值范围为0%(黑)~100%(白)。

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表示法:

  • 4:4:4表示完全取样。
  • 4:2:2表示2:1的水平取样,垂直完全采样。
  • 4:2:0表示2:1的水平取样,垂直2:1采样。
  • 4:1:1表示4:1的水平取样,垂直完全采样。

1.3 色彩空间的转换

1.3.1 cvtColor() 颜色转换

cvtColor()用法:

cv2.cvtColor(img, colorspace)

参数说明:

  • img:需要转换的图像
  • colorspace:将图像转换成何种格式

cv2.COLOR_BGR2RGBA是将BGR格式转换为RGBA格式

1.3.2 代码实现
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()

2、Numpy 基本操作

Numpy是一个经高度优化的Python数值库。OpenCV中用到的矩阵都要转换成Numpy数组,然后再进行后续操作。

在使用Numpy进行基本操作时,都需要导入Numpy库,即import numpy as np

2.1 创建矩阵

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)

参数说明:

  • (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)

参数说明:

  • (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)

参数说明:

  • 3:表示几维数组,即 3 * 3(3行3列)
  • 主对角线是1,其它是0

实例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)

参数说明:

  • (3, 5):3行5列
  • k=3:从下标为3开始的对角线为1,其它为0(下标0,1,2,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.]]

2.2 检索与赋值[y, x] / [y, x, channel]

1、检索

  • [y, x]
img = np.zeros((480, 640, 3), np.uint8)
print(img[100, 100])
[0 0 0]
  • [y, x, channel]
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] 一般只需掌握以下几种:

  • [255, 0, 0]:蓝色通道(B)
  • [0, 255, 0]:绿色通道(G)
  • [0, 0, 255]:红色通道®
  • [255, 255, 255]:白色(混合)
img[count, 100] = [0, 0, 255]

img[count, 100] = [255, 255, 255]

实例3:img[y, x, channel] = 255

OpenCV默认是BGR三通道,所以channel可以取0、1或2,即:

  • channel = 0:蓝色通道(B)
  • channel = 1:绿色通道(G)
  • channel = 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()

2.3 获取子矩阵[:, :]

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()

3、OpenCV 的重要数据结构—Mat

3.1 Mat 介绍

Mat是OpenCV在 C++ 语言中用来表示图像数据的一种数据结构,在 Python 中转换为numpy的ndarray。

  • Mat由header和data组成,header中记录了图片的维数、大小和数据类型等数据。

  • Mat在C++中的原型:
class CV_EXPORTS Mat{
    public:
    ...
    int dims; //维数
    int rows, cols; //行、列数
    uchar *data; //存储数据的指针
    int *refcount; //引用计数
    ...
};
  • Mat属性
字段说明字段说明
dims维度channels通道数 RGB是3
rows行数size矩阵大小
cols列数typedep + dt + chs CV_8UC3
depth像素的位深data存放数据

3.2 Mat 拷贝

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]

3.3 代码实现

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()

3.4 访问图像(Mat)的属性

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

3.5 通道分离与合并

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()

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_leoatliang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值