侧边栏壁纸
博主头像
Dioxide-CN博主等级

茶边话旧,看几许星迢露冕,从淮海南来。

  • 累计撰写 47 篇文章
  • 累计创建 46 个标签
  • 累计收到 21 条评论

目 录CONTENT

文章目录

计算机视觉:1.1~2.5 初等概念及OpenCV的使用

Dioxide-CN
2022-07-06 / 1 评论 / 4 点赞 / 118 阅读 / 7,358 字
温馨提示:
本文最后更新于 2022-08-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1.1~2.5 初等概念及OpenCV的使用

1.1 机器视觉介绍

现在说的机器视觉(Machine Vision)一般指计算机视觉(Computer Vision),简单来说就是研究如何使机器看懂东西。就是指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更合适人眼观察或传送给仪器检测的图像。

在上面的讨论中,计算机视觉(computer vision)和机器视觉(machine vision)两个术语是不加以区分的,在很多文献中也是如此。但其实这两个术语既有区别又有联系。计算机视觉是采用图像处理、模式识别、人工智能技术相结合的手段,着重于一副或多副图像的计算机分析。图像可以有单个或者多个传感器获取,也可以是单个传感器在不同时刻获取的图像序列。分析是对目标物体的识别,确定目标物体的位置和姿态,对三维景物进行符号描述和解释。在计算机视觉研究中,经常使用几何模型、复杂的知识表达,采用基于模型的匹配和搜索技术,搜索的策略常使用在自底向上、自顶向下、分层和启发式控制策略。机器视觉则偏重于计算机视觉技术工程化,能够自动获取和分析特定图像,以控制相应的行为。具体地说,计算机视觉为机器视觉提供图像和景物分析的理论以及算法基础,机器视觉为计算机视觉的实现提供传感器模型、系统构造和实现手段。因此可以认为,一个机器视觉系统就是一个能自动获取一副或多幅目标物体图像,对所获取图像的各种特征量进行处理、分析和测量,并对测量结果做出定性分析和定量解释,从而得到有关目标物体的某种认识并做出相应决策的系统。计算机视觉系统的功能包括:物体定位、特征测量、缺陷判断、目标识别、技术、运动跟踪。

计算机视觉的应用

  1. 物体识别:人脸识别、测量检测;
  2. 识别图像中的文字(OCR);
  3. 图像拼接、修复、背景替换;

1.2 OpenCV介绍

  • Gray Bradsky 于 1999 年开发,2000 年发布
  • C++,Python,Java,JS,C#,Ch,Ruby,Go
  • 跨平台(Windows,Linux,Mac …)

为什么使用Python:

  • Python语言简单,开发速度快
  • 底层使用C/C++,速度有保障
  • 有完整的生态链

学习目标:

  • 了解OpenCV的运行机制
  • 可以使用OpenCV处理一些图像常见问题
  • 学会物体识别,文字识别等问题的处理思路

1.3 安装OpenCV环境

进入虚拟环境,执行命令:

pip3 install opencv-python opencv-contrib-python jupyter matplotlib -i https://pypi.douban.com/simple

如果安装不了需要手动下载:https://www.lfd.uci.edu/~gohlke/pythonlibs
检查安装(进入venv环境):

% ipython
In [1]: import cv2
In [2]: cv2.__version__
Out[2]: '4.6.0'
In [3]: exit()

如果出现 Out[2]: '4.6.0' 则说明安装且导入成功。

1.4 创建和显示窗口

  • namedWindow():创建命名窗口
  • imshow():显示窗口
  • destoryAllWindows():销毁窗口
  • resizeWindow():改变窗口大小
  • waitKey():等待用户输入
    使用 Jupyter 进行编写 ipynb 文件:
jupyter

在Jupyter中新建文件“图像和视频的加载和显示”并写入代码块:

In[1]:
# opencv导包为cv2
import cv2

In[2]:
# 创建窗口
# cv2.WINDOW_AUTOSIZE不允许修改窗口大小
# cv2.namedWindow('window', cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('window', cv2.WINDOW_NORMAL)
# 更改窗口大小
cv2.resizeWindow('window', 800, 600)
# 展示名字为window的窗口
cv2.imshow('window',0)

# 等待按下键盘
# 返回按下键的ASCII码
# 0表示接收任意按键,如果给其他整数,表示等待按键的时间,单位ms
# 可以利用waitKey来销毁窗口,不用每次都重启python
key = cv2.waitKey(0)
# key是int型,最少都是16位,但是ASCII是8位
if key & 0xFF == ord('q'):
    print('准备销毁窗口')
    cv2.destroyAllWindows()

In[3]:
# 怎么计算Q的ASCII码
# ord('q')函数是python中计算ASCII值的函数

In[1] 开始运行代码即可看到弹出的窗口。

1.5 显示图像

  • imread(path, flag):使用imread可以读取图片,默认读取的是彩色图片,比如:
# 导入opencv包
import cv2
import numpy as np
from matplotlib import pyplot as plt

# 读取图片
doge = cv2.imread('./doge.jpg')
# doge输出numpy的ndarray dtype=uint8 cat.max()=2^8-1
doge.max()
plt.imshow(doge)

其中,使用 cv2.imread('./doge.jpg') 方法读取图片显示如下:
Pasted image 20220704182852
使用 plt.imshow(doge) 方法读取图片显示如下:
Pasted image 20220704182822
其中狗的颜色发生了改变,这是因为OpenCV读取图片的颜色通道按照BGR(蓝绿红)排列的,一般图片通道都是按照RGB来排列的。为了正常显示猫的图片,要使用OpenCV的图像显示方法:

cv2.imshow('doge', doge)
cv2.waitKey(0)
cv2.destroyAllWindows()

可以将其其为一个函数来显示图片

def cv_show(name, img):
	cv2.imshow(name, img)
	cv2.waitKey(0)
	cv2.destroyAllWindows()

2.1 保存图片

  • imwrite(path, img):使用imwrite保存图片
import cv2

cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 320, 240)

img = cv2.imread("./doge.jpg")

# 利用while循环优化退出逻辑
while True:
	cv2.imshow('img', img)
	key = cv2.waitKey(0)
	if key & 0xFF == ord('q'):
		break
	elif key & 0xFF == ord('s'):
		cv2.imwrite("./123.png", img)
	else:
		print(key)
cv2.destroyAllWindows()

保存后文件目录如下:
Pasted image 20220706142906

2.2 读取摄像头和视频数据

视频采集

  • 视频是由图片组成的,视频的每一帧就是一副图片,一般30帧,表示一秒显示30张图片。
  • cv2.VideoCapture可以捕获摄像头,用数字来表示不同的设备,比如:0、1。
  • 如果是视频文件,可以直接指定路径即可。
# 打开视频文件
vc = cv2.VideoCapture('./1.mp4')
# 打开摄像头
vc = cv2.VideoCapture(0)

读取摄像头

# 打开摄像头
import cv2

cv2.namedWindow('video', cv2.WINDOW_NORMAL)
cv2.resizeWindow('video', 640, 480)
cap = cv2.VideoCapture(0)
# 循环读取摄像头的每一帧
while True:
    # 读取一帧数据,返回标记,True表示读到了数据反之亦然,和这一帧的数据
    ret, frame = cap.read()
    # 根据ret做出判断
    if not ret:
        # 没读到数据
        break
    # 读到了数据就显示
    cv2.imshow('video', frame)
    
    key = cv2.waitKey(10)
    if key & 0xFF == ord('q'):
        break
# 释放资源
cap.release()
cv2.destroyAllWindows()

若设备没有摄像头或打开摄像头失败,程序会直接退出而非报错。这时需要检测是否正确打开摄像头:

if vc.isOpened():
	# 读取视频的一帧
	open, frame = vc.read()
else:
	open = False

读取视频

# 打开视频
import cv2

cv2.namedWindow('mp4', cv2.WINDOW_NORMAL)
cv2.resizeWindow('mp4', 640, 480)
cap = cv2.VideoCapture('./1.mp4')
# 循环读取摄像头的每一帧
while True:
    # 读取一帧数据,返回标记,True表示读到了数据反之亦然,和这一帧的数据
    ret, frame = cap.read()
    # 根据ret做出判断
    if not ret:
        # 没读到数据
        break
    # 读到了数据就显示
    cv2.imshow('video', frame)
    
    key = cv2.waitKey(10)
    if key & 0xFF == ord('q'):
        break
# 释放资源
cap.release()
cv2.destroyAllWindows()

Pasted image 20220706145720
视频被加速的原因:cv2.waitKey(10) 使得视频每一帧的间隔缩短至了10毫秒。
考虑问题:假如一个视频为30FPS那么每张图之间的间隔为多少毫秒?

100030=1003\lfloor \frac{1000}{30} \rfloor = \lfloor \frac{100}{3} \rfloor

必须向下取整计算

# 30fps
key = cv2.waitKey(1000 // 30)

2.3 录制视频

  • VideoWriter:参数一为输出文件、参数二为多媒体文件的格式(VideoWriter_fourcc对象),参数三位帧率,参数四为分辨率。
  • write:编码写入缓存。
  • release:缓存内容写入磁盘,并释放资源。

OpenCV可以将打开的视频或摄像头中的每一个画面保存到新的视频流中。
* 注:这里的(1920, 1080)以 MacBook Pro 16 英寸 M1 2021 的FaceTime高清摄像头为准。

# 摄像头录制视频
cap = cv2.VideoCapture(0)
# *mp4v就是解包操作 等同于 'm', 'p', '4', 'v'
# avi 格式为 XVID
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
# (1920, 1080)表示摄像头拍视频的分辨率,大小错了就不行了
vw = cv2.VideoWriter('output.mp4', fourcc, 20, (1920, 1080))

# vw = cv2.VideoWriter('output.mp4', cv2.VideoWriter_fourcc(*'mp4v'), 20, (1920, 1080))

while cap.isOpened():
	ret, frame = cap.read()
	if not ret:
		print('摄像头未开启')
		break

	vw.write(frame)
	cv2.imshow('frame', frame)

	# 这里的1毫秒决定了根本帧率,需要使用 1000//30
	if cv2.waitKey(1) & 0xFF == ord('q'):
		break

# 释放资源
cap.release()
vw.release()
cv2.destroyAllWindows()

Pasted image 20220706204345

2.4 控制鼠标

OpenCV允许我们对窗口上的鼠标动作做出响应

  • setMouseCallback(winname, callback, userdata)
    • winname:窗口名字
    • callback:回调函数名
    • userdata:传递给回调函数的参数列表
  • callback(event, x, y, flags, userdata)
    • 回调函数必须包含这五个参数
    • event:鼠标事件(左键、右键、滚动、移动等操作事件)
    • x,y:鼠标的位置坐标
    • flags:主要用于组合键
    • userdata:为上面的setMouseCallback的userdata

鼠标动作事件

事件名 事件值 操作
EVENT_MOUSEMOVE 0 鼠标移动
EVENT_LBUTTONDOWN 1 按下鼠标左键
EVENT_RBUTTONDOWN 2 按下鼠标右键
EVENT_MBUTTONDOWN 3 按下鼠标中键
EVENT_LBUTTONUP 4 左键释放
EVENT_RBUTTONUP 5 右键释放
EVENT_MBUTTONUP 6 中键释放
EVENT_LBUTTONDBLCLK 7 左键双击
EVENT_RBUTTONDBLCLK 8 右键双击
EVENT_MBUTTONDBLCLK 9 中键双击
EVENT_MOUSEWHEEL 10 鼠标滚轮上下滚动
EVENT_MOUSEHWHEEL 11 鼠标滚轮左右滚动

Flags组合键

事件名 事件值 操作
EVENT_FLAG_LBUTTON 1 按下左键
EVENT_FLAG_RBUTTON 2 按下右键
EVENT_FLAG_MBUTTON 4 按下中键
EVENT_FLAG_CTRLKEY 8 按下Ctrl键
EVENT_FLAG_SHIFTKEY 16 按下Shift键
EVENT_FLAG_ALTKEY 32 按下Alt键
# opencv控制鼠标
import cv2
import numpy as np

# 回调函数参数必须为5个
# event事件,xy坐标,flags第二组合键,userdata自定义数据
def mouse_callback(event, x, y, flags, userdata):
    print(event, x, y, flags, userdata)
    
# 创建窗口
cv2.namedWindow('mouse', cv2.WINDOW_NORMAL)
# 宽度(列数)和高度(行数)
cv2.resizeWindow('mouse', 640, 360)

# 绑定鼠标的回调函数
cv2.setMouseCallback('mouse', mouse_callback, '123')

# 生成全黑的图片(先行后列)
img = np.zeros((360, 640, 3), np.uint8)
while True:
    cv2.imshow('mouse', img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
        
# 销毁窗口
cv2.destroyAllWindows()
[Output]:
0 376 174 0 123 # 鼠标移动 组合 鼠标移动
0 422 185 0 123
0 514 201 0 123
0 566 210 0 123
1 524 258 1 123 # 左键按下 组合 左键按下
4 524 258 1 123 # 左键释放 组合 左键按下
0 528 258 0 123
0 544 259 0 123
0 567 259 0 123
0 625 262 0 123 # 鼠标移动 组合 鼠标移动

2.5 TrackBar用法

TrackBar控件

类似于可拖动的数值进度条

  • createTrackbar(trackbarname, winname, value, count, onChange)
    • 创建Trackbar控件
    • trackbarname:控件名字
    • winname:窗口名字
    • value:trackbar的默认值
    • count:trackbar的最大值,最小为0
    • onChange:回调函数
  • getTrackbarPos(trackbarname, winname)
    • 获取TrackjBar当前值
# trackbar
import cv2
import numpy as np

# 创建窗口
cv2.namedWindow('trackbar', cv2.WINDOW_NORMAL)
cv2.resizeWindow('trackbar', 640, 480)

# 定义回调函数
def callback(value):
    print(value)
    
# 创建trackbar
cv2.createTrackbar('R', 'trackbar', 0, 255, callback)
cv2.createTrackbar('G', 'trackbar', 0, 255, callback)
cv2.createTrackbar('B', 'trackbar', 0, 255, callback)

# 创建一个背景图片
img = np.zeros((480, 640, 3), np.uint8)

while True:
    # 获取当前TrackBar的值
    r = cv2.getTrackbarPos('R', 'trackbar')
    g = cv2.getTrackbarPos('G', 'trackbar')
    b = cv2.getTrackbarPos('B', 'trackbar')
    
    # 改变背景图颜色
    img[:] = [b, g, r]
    cv2.imshow('trackbar', img)
    
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()
4

评论区