OpenCV-图片与视频的基本操作

注意:opencv_python版本选择3.4.1.15,过高可能会有专利问题无法使用。目前通用的教程中版本基本都是opencv2、3.

图片入门

一张图片由海量的像素点构成,而一个像素点由BGR三个颜色通道组成的,也就是三原色光。BGR的数值表示亮度,使用整数表示,从 0 ~ 255 ,一共256级,0 为黑色,255 为白色,因此数值越大图片越亮。一张彩色照片通常就是BGR图片。
对于一张图片来说,它的数值就是一个矩阵,行列就是像素点的数量。程序读取图片时,就是在读取这个图片像素点所映射的矩阵。

图片读取

1
2
3
4
5
6
7
8
9
10
11
12
13
jz=cv2.imread(
"D:\\z-bank\\bank\\PY\\book.png"
)
print
(jz)
out:
[[[
]
[
]
[
]
...

这里的中括号有三层,表示三个维度,用[h,w,c]表示。补充:hwc维度表示一个图像,H表示图像高度,w表示宽度,c表示通道数。
如果使用jz=cv2.imread("book.png",cv2.IMREAD_GRAYSCALE)读取灰度图片,那么将没有c,只有h、w。
imread()函数的第二个参数是读取图片的方式,有以下几种:

  • cv2.IMREAD_COLOR:读取彩色图片,透明度忽略,这是默认方式,用1表示
  • cv2.IMREAD_GRAYSCALE:读取灰度图片。 用0表示
  • cv2.IMREAD_UNCHANGED:读取图片的alpha通道。用-1表示

图片显示

1
2
3
4
5
6
7
8
9
jz=cv2.imread(
"D:\\z-bank\\bank\\PY\\book.png"
)
cv2.imshow(
"jz"
,jz)
cv2.waitKey(
)
cv2.destroyAllWindows()

使用imshow()函数来显示图像,窗口自适应图像尺寸。
waitKey()用于设置窗口开启时间,单位毫秒。设为 0 代表按下任意键即可关闭图片窗口。一般来说就是填 0
destroyAllWindows()用于关闭所有窗口,如果想关闭指定窗口,可以使用destroyWindow()函数。

图片裁剪

jz是一个数组,左边参数为y轴裁剪范围,右边为x轴。单位是像素。具体数值可以在ps->信息窗口中查看。
图像裁剪截取图像的特定区域,在识别图像中的特定目标时,可以使用图像裁剪来提高识别的准确率。

1
2
3
4
5
6
7
8
9
10
11
jz=cv2.imread(
"D:\\z-bank\\bank\\PY\\book.png"
)
jz=jz[
:
,
:
]
cv_show(
'jz'
,jz)

图片保存

cv2.imwrite('book.png',jz)即可保存图片

图片通道分离与合并

图片shape值的最后一位表示通道数,分别是BGR,用0、1、2表示

1
2
3
4
5
6
# b:0:蓝色通道,g:1:绿色通道,r:2:红色通道
b,g,r=cv2.split(jz)
# split()操作耗时,尽量使用numpy的索引操作
cv_show(
'b'
,b)

图像允许将任意通道置为0,并合并其他通道,从而达到去除某个通道的效果。

1
2
3
4
5
6
7
8
9
10
cpimg=cv2.merge([b,g,r])
cpimg[:,:,
]=
# 将绿色通道置为0
cpimg[:,:,
]=
# 将红色通道置为0
cv_show(
'cpimg'
,cpimg)

matplotlib显示图片

1
2
3
4
5
6
7
8
9
10
11
jz=cv2.imread(
"D:\\z-bank\\bank\\PY\\book.png"
)
plt.imshow(jz,cmap=
'gray'
,interpolation=
'bicubic'
)
plt.xticks([]),plt.yticks([])
# 隐藏x,y轴
plt.show()

其他图像信息

1
2
3
4
5
6
7
8
9
10
11
print
(
type
(jz))
# 图片的底层是numpy.ndarray格式
print
(jz.size)
# 图片大小
print
(jz.dtype)
# 图片类型

图像基本操作

图片填充

图像填充可以在周边创建边框,例如相框。都使用copyMakeBorder()函数,用法及参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
img=cv2.imread(
"D:\\z-bank\\bank\\PY\\book.png"
)
replicate=cv2.copyMakeBorder(img,
,
,
,
,cv2.BORDER_CONSTANT)
# 常量法,常数值填充
reflect =cv2.copyMakeBorder(img,
,
,
,
,cv2.BORDER_REFLECT)
# 反射法,以边界为轴对称填充,如fedcba|abcdefgh|hgfedcb
reflect101 = cv2.copyMakeBorder(img,
,
,
,
,cv2.BORDER_REFLECT_101)
# 反射法,以边缘像素为轴对称填充,如gfedcb|abcdefgh|bagfedc
wrap = cv2.copyMakeBorder(img,
,
,
,
,cv2.BORDER_WRAP)
# 外包装法,如cdefgh|abcdefgh|abcdefg
constant= cv2.copyMakeBorder(img,
,
,
,
,cv2.BORDER_CONSTANT,value=[
,
,
])
plt.subplot(
),plt.imshow(img,
'gray'
),plt.title(
'ORIGINAL'
)
plt.subplot(
),plt.imshow(replicate,
'gray'
),plt.title(
'REPLICATE'
)
plt.subplot(
),plt.imshow(reflect,
'gray'
),plt.title(
'REFLECT'
)
plt.subplot(
),plt.imshow(reflect101,
'gray'
),plt.title(
'REFLECT_101'
)
plt.subplot(
),plt.imshow(wrap,
'gray'
),plt.title(
'WRAP'
)
plt.subplot(
),plt.imshow(constant,
'gray'
),plt.title(
'CONSTANT'
)
plt.show()

图像加法

对一张图片做加法时,会对每个像素点的RGB值进行加法运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
tx=cv2.imread(
"D:\\z-bank\\bank\\PY\\tx.jpg"
)
print
(tx[:
,:,
])
tx2=tx+
print
(tx2[:
,:,
])
# out:
[[
...
]
[
...
]
[
...
]]
[[
...
]
[
...
]
[
...
]]

如上代码,对 tx 图片每个像素点的BGR值+10,此时图片就会变亮。而如果将+10后的图片与原图相加,将得到一个(137+147)%256=28的结果,即图片变暗。因此,图像加法并不是简单的加法运算,而是对每个像素点的RGB值进行加法运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tx3=tx+tx2
print
(tx3[:
,:,
])
# out:这里的结果是(137+147)%256=28
[[
...
]
[
...
]
[
...
]]

上面的加法运算使用的是Numpy的模运算,也可以使用OpenCV的饱和运算,即超过255的值就截断为255,低于0的值就截断为0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tx3=cv2.add(tx,tx2)
print
(tx3[:
,:,
])
#out:
[[
...
]
[
...
]
[
...
]]

图像融合

图像融合的前提是两张图片的shape必须相同,所以需要先使用cv2.resize()函数调整图片大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
tx=cv2.imread(
"D:\\z-bank\\bank\\PY\\tx.jpg"
)
xx=cv2.imread(
"D:\\z-bank\\bank\\PY\\xx.jpg"
)
print
(
"tx:"
,tx.shape)
print
(
"xx:"
,xx.shape)
# resize第二个参数是列数,第一个参数是行数,与shape相反
newxx=cv2.resize(xx,(tx.shape[
],tx.shape[
]))
# out:
tx: (
,
,
)
xx: (
,
,
)
newxx: (
,
,
)

cv2.resize()函数还可以将第二个参数设置为(0,0),第三个参数设置为缩放比例,即可按比例缩放图片。如下,x,y轴缩放为原来的一半,图像大小变为原来的四分之一。

1
2
3
4
5
6
7
8
9
10
tx=cv2.imread(
"D:\\z-bank\\bank\\PY\\tx.jpg"
)
cv2.resize(tx,(
,
),fx=
.5
,fy=
.5
)

然后使用cv2.addWeighted()函数进行融合,用法如下。对图像进行加权融合,公式为:dst=α⋅img1+β⋅img2+γ。其中α、β、γ是缩放系数,α+β=1。
最后的效果类似于Photoshop中的图层融合,正片叠底。

1
2
3
4
5
6
7
8
9
res=cv2.addWeighted(tx,
.5
,xx,
.5
,
)
cv_show(
"res"
,res)

视频入门

视频读取

读取视频时,首先创建一个VideoCapture 对象。参数是设备索引或视频文件的名称。设备索引是指定摄像头,一般用0、1、2等数字表示。也可以填写视频文件的路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
videos=cv2.VideoCapture(
"D:\\z-bank\\bank\\PY\\wg.flv"
)
if
videos.isOpened():
open
,frame=videos.read()
else
:
open
=
False
while
open
:
ret,frame=videos.read()
# 读取每一帧的图片,ret为布尔值,frame为图片
if
frame
is
None
:
break
if
ret==
True
:
# 开始处理视频
gray=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 转换为灰度图
cv2.imshow(
'result'
,gray)
if
cv2.waitKey(
) &
xFF
==
:
# 25即帧率,表示每25帧显示一次,0xFF ==27表示按下ESC退出
break
videos.release()
# 完成所有操作后,释放捕获器
cv2.destroyAllWindows()

视频保存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 视频读取
vd=cv2.VideoCapture(
"D:\\z-bank\\bank\\PY\\wg.flv"
)
# 设置视频的输出路径、编码器、帧率、大小
out=cv2.VideoWriter(
'D:\\z-bank\\bank\\PY\\out.avi'
,cv2.VideoWriter_fourcc(*
'XVID'
),
.0
,(
,
))
if
vd.isOpened():
open
,frame=vd.read()
else
:
open
=
False
while
open
:
ret,frame=vd.read()
# 读取每一帧的图片,ret为布尔值,frame为图片
if
frame
is
None
:
break
if
ret==
True
:
frame=cv2.flip(frame,
)
# 翻转图片
out.write(frame)
# 写入视频
cv2.imshow(
'frame'
,frame)
# 显示图片
if
cv2.waitKey(
) &
xFF
==
ord
(
'q'
):
break
vd.release()
cv2.destroyAllWindows()

OpenCV-图片与视频的基本操作
https://zhouyinglin.top/2023/04/25/OpenCV-图片与视频的基本操作/
作者
小周
发布于
2023年4月25日
许可协议