【opencv-python常用知识速查(一)】

0.前言

博客会不断补充,主要是针对opencv-python在深度学习方面常用到的知识总结。

1 基本操作

1.1 读入并显示图片:imread()、imshow()

import cv2 as cv
import numpy as np

img = cv.imread(r'E:\0_postgraduate\test.jpg', flags=0)
cv.imshow('title', img)
k = cv.waitKey(0)
if k & 0xFF == ord('s'):
    cv.destroyAllWindows()
    cv.imwrite(r'E:\1.jpg', img)

在这里插入图片描述

(1)cv.imread(filename,flags)
两个参数,第一个参数filename是图片的路径,第二个参数flags是图像的通道和色彩信息

flags = -1, 8位深度,原通道
flags = 0, 8位深度,1通道
flags = 1, 8位深度,3通道
flags = 2, 原深度, 1通道
flags = 3, 原深度, 3通道
flags = 4, 8位深度,3通道

默认flags=1,为彩色图。flags=0为灰度图。

注意1:cv.imread()读取的图片类型为numpy.ndarray,数据类型为np.uint8

img = cv.imread(r'E:\0_postgraduate\test.jpg', flags=1)
print('img的数据类型是:%s'%type(img))
print('img的数据范围是:{}'.format(img.dtype))
print('img的形状为:{}'.format(img.shape))

# 结果
img的数据类型是:<class 'numpy.ndarray'>
img的数据范围是:uint8
img的形状为:(440, 640, 3)

注意2:cv.imread()读入的三通道图片的顺序是BGR

img = cv.imread(r'E:\0_postgraduate\test.jpg', flags=1)
print('原图的形状为:{}'.format(img.shape))
cv.imshow('original pic', img)
(b, g, r) = cv.split(img)  # 将图片分成BGR三个通道
print('每个通道的形状为:\nB:{} G:{} R:{}'.format(b.shape, g.shape, r.shape))
zeros = np.zeros(img.shape[:2], dtype=np.uint8)
merged1 = cv.merge([b, zeros, zeros])
merged2 = cv.merge([zeros, g, zeros])
merged3 = cv.merge([zeros, zeros, r])
print('合并后的形状为:{}'.format(merged1.shape))
cv.imshow('blue channel', merged1)
cv.imshow('green channel', merged2)
cv.imshow('red channel', merged3)
k = cv.waitKey(0)
if k == ord('s'):
    cv.destroyAllWindows()
    
    
# 结果
原图的形状为:(440, 640, 3)
每个通道的形状为:
B:(440, 640) G:(440, 640) R:(440, 640)
合并后的形状为:(440, 640, 3) 

在这里插入图片描述

(2)cv.imshow(name, img):

展示图片,name是标题,img是要展示的图片

(3)cv.waitKey(delay):

作用:对键盘事件进行delay(ms)的等待(delay=0则为无限等待),若触发则返回该按键的ASSIC码(范围是0-255)(否则返回-1)

着重解释下这句代码:

k = cv.waitKey(0)
if k & 0xFF == ord('q'):
    cv.destroyAllWindows()

其实挺好理解的,不过,既然cv.waitKey()返回的是按键的ASSIC码,那为什么还要让k和0xFF相与呢?(0xFF为16进制,换成二进制是8位1111 1111)

解释如下:
在这里插入图片描述
来源

(4)cv.destroyAllWindows():

关闭所有窗口

(5)cv.imwrite(filepath, img):

把图片写入硬盘。filepath是写入的地址,img是imread()读取的图片。

1.2 读取摄像头操作

基本框架代码:

cap = cv.VideoCapture(0)

if not cap.isOpened():
    print("can't open your camera")
    exit()

while True:
    ret, frame = cap.read()
    if not ret:
        print("can't receive the frame...")
        break
    cv.imshow('frame', frame)
    k = cv.waitKey(25)  # 25ms for 1 frame
    if k & 0xFF == ord('q'):
        break

cap.release()  # 释放摄像头
cv.destroyAllWindows()  # 关闭所有窗口

(1)cap.read():

返回两个参数,ret为Bool型,检查是否读到帧,如果是读取视频文件的话可以用来检测是否到视频结尾。frame为一帧图片。

(2)cap.release():

释放摄像头资源

改变摄像头窗口的尺寸

cap = cv.VideoCapture(0)

w = cap.get(3)  # 得到当前视频窗口的weight
h = cap.get(4)  # 得到当前视频窗口的height

print('当前窗口的wight:{},当前窗口的height:{}\n'.format(w, h))

#  设置当前的窗口为1280 x 720
cap.set(3, 1280)
cap.set(4, 720)

w = cap.get(3)  # 得到当前视频窗口的weight
h = cap.get(4)  # 得到当前视频窗口的height

print('当前窗口的wight:{},当前窗口的height:{}\n'.format(w, h))

if not cap.isOpened():
    print('没打开摄像头')
    exit()
    
while True:
    ret, frame = cap.read()
    if not ret:
        print('未读取到帧...')
        break
    cv.imshow('frame', frame)
    k = cv.waitKey(10)
    if k & 0xFF == ord('q'):
        break

cap.release()
cv.destroyAllWindows()
# 结果
当前窗口的wight:640.0,当前窗口的height:480.0

当前窗口的wight:1280.0,当前窗口的height:720.0

(3) cap.get():获取当前图像信息

参数含义
cv2.VideoCapture.get(0)视频文件的当前位置(播放)以毫秒为单位
cv2.VideoCapture.get(1)基于以0开始的被捕获或解码的帧索引
cv2.VideoCapture.get(2)视频文件的相对位置(播放):0=电影开始,1=影片的结尾。
cv2.VideoCapture.get(3)在视频流的帧的宽度
cv2.VideoCapture.get(4)在视频流的帧的高度
cv2.VideoCapture.get(5)帧速率
cv2.VideoCapture.get(6)编解码的4字-字符代码
cv2.VideoCapture.get(7)编解码的4字-字符代码
cv2.VideoCapture.get(8)返回对象的格式
cv2.VideoCapture.get(9)返回后端特定的值,该值指示当前捕获模式
cv2.VideoCapture.get(10)图像的亮度(仅适用于照相机)
cv2.VideoCapture.get(11)图像的对比度(仅适用于照相机)
cv2.VideoCapture.get(12)图像的饱和度(仅适用于照相机)
cv2.VideoCapture.get(13)色调图像(仅适用于照相机)
cv2.VideoCapture.get(14)图像增益(仅适用于照相机)(Gain在摄影中表示白平衡提升
cv2.VideoCapture.get(15)曝光(仅适用于照相机)
cv2.VideoCapture.get(16)指示是否应将图像转换为RGB布尔标志
cv2.VideoCapture.get(17)× 暂时不支持
cv2.VideoCapture.get(18)立体摄像机的矫正标注(目前只有DC1394 v.2.x后端支持这个功能)

来源:OpenCV VideoCapture.get()参数详解

(4)cap.set():改变图像属性信息

1.3 绘图

(1)绘制直线:
cv.line(img, startpoint, endpoint, color, thickness)

img:原始图像
startpoint:开始点坐标
endpoint:结束点坐标
color:直线的颜色
thickness:直线的厚度

(2)绘制矩形:
cv.rectangle(img, pos1, pos2, color, thickness)

img:原始图像
pos1:左上角坐标
pos2:右下角坐标
color:颜色
thickness:厚度(thickness=-1代表填充)

(3)绘制圆形
cv.circle(img, pos, radius, color, thickness)

img:原始图像
pos:圆心坐标
radius:半径
color:颜色
thickness:厚度(thickness=-1代表填充)

(4)添加文本:
cv.putText(img, ‘text’, pos, font, size, color)

img:原始图像
text:输出的文本
pos:文本的位置坐标
font:文本字体
size:文本大小
color:文本颜色

bg = np.zeros((550,550,3), dtype=np.uint8)
# 画一条直线
cv.line(bg, (0,0), (549,549), (255,0,0), 5)
# 画矩形
cv.rectangle(bg, (100,100), (200,200), (0,255,0), -1)
# 画圆形
cv.circle(bg, (300,300), 50, (0,0,255), 3)
# 放文字
cv.putText(bg, '123', (0,400), 0, 4, (255,0,0))
cv.imshow('draw', bg)
k = cv.waitKey(0)
if k & 0xFF == ord('q'):
    cv.destroyAllWindows()

在这里插入图片描述

2. 图像操作

2.1 分割和合并通道cv.split(img) cv.merge([b,g,r])

这个前面举过例子了,不多说,不过有一点是:使用numpy索引要比cv.split(img)更高效,两者的效果是一样的:

img = cv.imread(r'E:\opencv.jpg')

e1 = cv.getTickCount()
b, g, r = cv.split(img)
e2 = cv.getTickCount()
print('cv.split time is:{} ms'.format((e2-e1)*1000/cv.getTickFrequency()))

e1 = cv.getTickCount()
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
e2 = cv.getTickCount()
print('numpy time is:{} ms'.format((e2-e1)*1000/cv.getTickFrequency()))
# 结果
cv.split time is:0.7039 ms
numpy time is:0.1805 ms

2.2 边框填充:cv.copyMakeBorder()

用法:cv.copyMakeBorder(img, top, bottom, left, right, borderType)

img:原始图像
top:顶部填充的边框宽度(单位为像素值)
bottom:底部填充的边框宽度(单位为像素值)
left:左部填充的边框宽度(单位为像素值)
right:右部填充的边框宽度(单位为像素值)
borderType:填充类型

img = cv.imread(r'E:\test.jpg')

img1 = cv.copyMakeBorder(img, 20,20,20,20, 0) #第0类填充:黑边填充
img2 = cv.copyMakeBorder(img, 20,20,20,20, 1) #第1类填充
img3 = cv.copyMakeBorder(img, 20,20,20,20, 2) #第2类填充
img4 = cv.copyMakeBorder(img, 20,20,20,20, 3) #第3类填充

cv.imshow('0', img1)
cv.imshow('1', img2)
cv.imshow('2', img3)
cv.imshow('3', img4)

k = cv.waitKey(0)
if k & 0xFF == ord('q'):
    cv.destroyAllWindows()

在这里插入图片描述

2.3 图像加法:cv.add()

我们已经知道了读入的图像本质上是numpy.ndarry数组,那么如果将两个同样维度的数组相加会怎样?

对于相加,我们有两种方式:假设a和b都为numpy.ndarry数组,
(1)使用numpy数组直接相加:a + b
(2)使用cv.add(a, b)

这两种方法的不同之处在于:

a + b:250+10 = 260 => 255
cv.add(a, b):250+10 = 260 % 256 = 4

具体来说,OpenCV加法是一个饱和操作,而Numpy加法是一个模数操作

举个例子:

np.random.seed(100)
a = np.random.randint(250,255,(10,10), dtype=np.uint8)
print('a数组:\n{}'.format(a))
b = np.ones((10,10),dtype=np.uint8) * 5
print('b数组:\n{}'.format(b))
print('a+b的结果为:\n{}'.format(a+b))
print('cv.add(a,b)的结果为:\n{}'.format(cv.add(a,b)))
# 结果
a数组:
[[250 254 253 250 253 250 253 253 253 253]
 [251 254 250 251 250 253 250 252 252 251]
 [251 254 250 252 250 254 252 253 252 251]
 [253 253 252 253 253 251 253 252 250 252]
 [251 250 251 251 253 250 254 254 254 253]
 [252 254 252 252 250 253 251 253 252 251]
 [253 254 251 250 250 252 251 253 253 252]
 [254 253 254 252 251 254 250 251 253 254]
 [254 254 250 254 252 254 250 253 254 254]
 [252 251 254 254 253 251 253 252 254 253]]
b数组:
[[5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]
 [5 5 5 5 5 5 5 5 5 5]]
a+b的结果为:
[[255   3   2 255   2 255   2   2   2   2]
 [  0   3 255   0 255   2 255   1   1   0]
 [  0   3 255   1 255   3   1   2   1   0]
 [  2   2   1   2   2   0   2   1 255   1]
 [  0 255   0   0   2 255   3   3   3   2]
 [  1   3   1   1 255   2   0   2   1   0]
 [  2   3   0 255 255   1   0   2   2   1]
 [  3   2   3   1   0   3 255   0   2   3]
 [  3   3 255   3   1   3 255   2   3   3]
 [  1   0   3   3   2   0   2   1   3   2]]
cv.add(a,b)的结果为:
[[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 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 255 255 255 255]]

这么说可能还不明显,用一张图片来看看:

mask = np.ones(img.shape, dtype=np.uint8) * 50
newImg1 = cv.add(img, mask)  # cv.add(a, b)
newImg2 = img + mask  # a + b
cv.imshow('original image', img)
cv.imshow('cv.add(a,b)', newImg1)
cv.imshow('numpy: a + b', newImg2)
k = cv.waitKey(0)
if k & 0xFF == ord('q'):
    cv.destroyAllWindows()

在这里插入图片描述
可以看出cv.add()更适合用来处理图像

3.衡量性能 :cv.getTickCount()和cv.getTickFrequency()

在opencv中,可以使用cv.getTickCount()和cv.getTickFrequency()来获取一段代码运行的时间,比使用time()更精确。

img = cv.imread(r'E:\opencv.jpg')

e1 = cv.getTickCount()
b, g, r = cv.split(img)
e2 = cv.getTickCount()
print('cv.split time is:{} ms'.format((e2-e1)*1000/cv.getTickFrequency()))

e1 = cv.getTickCount()
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
e2 = cv.getTickCount()
print('numpy time is:{} ms'.format((e2-e1)*1000/cv.getTickFrequency()))
# 结果

cv.split time is:0.7039 ms
numpy time is:0.1805 ms
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SinHao22

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

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

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

打赏作者

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

抵扣说明:

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

余额充值