Python计算机视觉编程 第十章

2024-09-08 08:36

本文主要是介绍Python计算机视觉编程 第十章,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、OpenCv基础知识

1.读取和写入图像

2.颜色空间

3.显示图像和结果

二、处理视频

1.输入视频

2.将视频读取到NumPy数组中

三、跟踪

1.光流

2.Lucas-Kanade算法


一、OpenCv基础知识

OpenCV 自带读取、写入图像函数以及矩阵操作和数学库。

1.读取和写入图像

import cv2
# 读取图像
im = cv2.imread(r"D:\test\pil.png")
h,w = im.shape[:2]
print (h,w)
# 保存图像
cv2.imwrite('result.png',im)

使用该代码可以读取一张图片,并且得到图片的尺寸信息。imwrite() 会根据文件后缀自动转换图像。

2.颜色空间

OpenCV里面颜色是BGR顺序存储的,读取时默认为BGR,可以使用cvColor来进行转换。其中的参数可以设置为:

cv2.COLOR_BGR2GRAY
cv2.COLOR_BGR2RGB
cv2.COLOR_GRAY2BGR

这些参数可以从字面上直接理解。

3.显示图像和结果

首先是一个简单的例子

import cv2
# 读取图像
im = cv2.imread(r"D:\test\pil.png")
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
# 计算积分图像
intim = cv2.integral(gray)
# 归一化并保存
intim = (255.0*intim) / intim.max()
cv2.imwrite('result.jpg',intim)

得到的结果为

上述代码将一幅图片保存为了一个整数图像。

之后是一个从一个种子像素进行泛洪填充的例子:

import cv2
import numpy as np
# 读取图像
print(cv2.__version__)
im = cv2.imread(r"D:\test\pil.png")
h,w = im.shape[:2]
# 泛洪填充
diff = (6,6,6)
mask = np.zeros((h+2,w+2),np.uint8)
cv2.floodfill(im,mask,(10,10), (255,255,0),diff,diff)
# 在 OpenCV 窗口中显示结果
cv2.imshow('flood fill',im)
cv2.waitKey()
# 保存结果
cv2.imwrite('result.jpg',im)

运行代码出现如下的错误:

最后一个例子为SURF特征提取, SURF 特征是 SIFT 特征的一个更快特征提取版,其实现代码为:

import cv2
import numpy as np
# 读取图像im = cv2.imread(r"D:\test\pil.png")
im_lowres = cv2.pyrDown(im)
# 变换成灰度图像
gray = cv2.cvtColor(im_lowres,cv2.COLOR_RGB2GRAY)
# 检测特征点
s = cv2.xfeatures2d.SIFT_create()
mask = np.uint8(np.ones(gray.shape))
keypoints = s.detect(gray,mask)
# 显示结果及特征点
vis = cv2.cvtColor(gray,cv2.COLOR_GRAY2BGR)
for k in keypoints[::10]:cv2.circle(vis,(int(k.pt[0]),int(k.pt[1])),2,(0,255,0),-1)cv2.circle(vis,(int(k.pt[0]),int(k.pt[1])),int(k.size),(0,255,0),2)
cv2.imshow('local descriptors',vis)
cv2.waitKey()

同样报了和上面错误类似得错误:

 网上查询之后发现是因为cv2.SURF()的问题,需要将其修改为cv2.xfeatures2d.SIFT_create(),之后再次执行就可以运行了。但是对于前一个例子的错误还是无法解决 。

最终得到的结果显示了图片的SURF特征。

二、处理视频

1.输入视频

OpenCV 能够很好地支持从摄像头读取视频。一个捕获视频帧并在 OpenCV 窗口中显示这些视频帧的完整例子为:

import cv2
# 设置视频捕获
cap = cv2.VideoCapture(0)
while True:ret,im = cap.read()cv2.imshow('video test',im)key = cv2.waitKey(10)if key == 27:breakif key == ord(' '):cv2.imwrite('vid_result.jpg',im)

得到的效果为:

其中的read() 方法解码并返回下一视频帧,第一个变量 ret 是一个判断视频帧是否成功读入,第二个变量是实际读入的图像数组。函数 waitKey() 等待用户按键:如果按下的是 Esc 键键,则退出应用;如果按下的是空格键,就保存该视频帧。

其次也可以使用给 GaussianBlur() 函数将图像模糊,这个函数会用高斯滤波器对传入的该帧图像进行滤波。

得到的结果为:

出来可以使用摄像头读取图像之外,还可以从文件里面读取视频帧, 再调用VideoCapture()函数是需要设置为如下的格式:

capture = cv2.VideoCapture('filename')

2.将视频读取到NumPy数组中

一个从摄像头捕获视频并将视频帧存储在一个 NumPy 数组中的例子为:

import cv2
import numpy as np
# 设置视频捕获
cap = cv2.VideoCapture(0)
frames = []
# 获取帧,存储到数组中
while True:ret,im = cap.read()cv2.imshow('video',im)frames.append(im)if cv2.waitKey(10) == 27:break
frames = np.array(frames)
# 检查尺寸
print (im.shape)
print (frames.shape)

当关闭打开的视频窗口之后,会在控制台输出一个视频帧的帧数、 帧高、帧宽和颜色通道数。

三、跟踪

 跟踪指的是在图像序列或视频里对其中的目标进行跟踪的过程。

1.光流

光流是目标、场景或摄像机在连续两帧图像间运动时造成的目标的运动。它是图像在平移过程中的二维矢量场。其主要依赖于三个假设:

  1. 亮度恒定:图像中目标的像素强度在连续帧之间不会发生变化
  2. 时间规律:相邻帧之间的时间足够短,以至于在考虑运行变化时可以忽略它们之间的差异
  3. 空间一致性:相邻像素具有相似的运动

对于相邻帧间的小运动以及短时间跳跃是一个很好的模型。假设一个目标像素在 t 时刻亮度为 I(x,y,t),那么它的光流方程为:

\nabla I^T\boldsymbol{v}=-I_{t}

OpenCV 中包含了一些光流实现的函数:

用了块匹配的 CalcOpticalFlowBM()

用了文献的 CalcOpticalFlowHS()

空间金字塔 Lucas-Kanade 算法 calcOpticalFlowPyrLK()

calcOpticalFlowFarneback()

其中最后一种是获取密集流场最好的方法之一,使用该方法的一个例子为:

import cv2
from numpy import *def draw_flow(im, flow, step=16):""" 在间隔分开的像素采样点处绘制光流 """h,w = im.shape[:2]y,x = mgrid[step/2:h:step, step/2:w:step].reshape(2, -1).astype('int64')fx, fy = flow[y, x].T# 创建线的终点lines = vstack([x, y, x + fx, y + fy]).T.reshape(-1, 2, 2)lines = int32(lines)# 创建图像并绘制vis = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)for (x1, y1), (x2, y2) in lines:cv2.line(vis, (x1, y1), (x2, y2), (0, 255, 0), 1)cv2.circle(vis, (x1, y1), 1, (0, 255, 0), -1)return vis# 设置视频捕获
cap = cv2.VideoCapture(0)
ret, im = cap.read()
prev_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)while True:# 获取灰度图像ret, im = cap.read()gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)# 计算流flow = cv2.calcOpticalFlowFarneback(prev_gray, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)prev_gray = gray# 画出流失量cv2.imshow('Optical flow', draw_flow(gray, flow))if cv2.waitKey(10) == 27:break

运行了出现了如下的错误:

 将代码中错误前面的y和x类型修改为int类型即可:

上图为手从左向右移动产生的光流矢量。

2.Lucas-Kanade算法

跟踪最基本的形式是跟随感兴趣点,比如角点。其中一种算法是 Lucas-Kanade 跟踪算法,利用了稀疏光流算法。其可以应用于任何一种特征,不过通常使用一些角点。角点是结构张量中有两个较大特征值的那些点,且更小的特征值要大于某个阈值。

如果基于每一个像素考虑,该光流方程组是欠定方程,即每个方程中含很多未知变量。利用相邻像素有相同运动这一假设,可以将方程写为:

\begin{bmatrix}\nabla I^T(\mathbf{x}_1)\\\nabla I^T(\mathbf{x}_2)\\\vdots\\\nabla I^T(\mathbf{x}_n)\end{bmatrix}v=\begin{bmatrix}I_x(\mathbf{x}_1)&I_y(\mathbf{x}_1)\\I_x(\mathbf{x}_2)&I_y(\mathbf{x}_2)\\\vdots&\vdots\\I_x(\mathbf{x}_n)&I_y(\mathbf{x}_n)\end{bmatrix}\begin{bmatrix}\boldsymbol u\\\boldsymbol v\end{bmatrix}=-\begin{bmatrix}I_t(\mathbf{x}_1)\\I_t(\mathbf{x}_2)\\\vdots\\I_t(\mathbf{x}_n)\end{bmatrix}

可以使用最小二乘法对该方程进行求解。通过对于周围像素的贡献可以进行加权处理,使越远的像素影响越小,可以得到如下的关系:

\overline{\boldsymbol{M}}_lv=-\begin{bmatrix}I_t(\mathbf{x}_1)\\I_t(\mathbf{x}_2)\\\vdots\\I_t(\mathbf{x}_n)\end{bmatrix}, Or\; \; Av=b

对于该超定方程组也可以使用最小二乘法进行求解,从而得到运动矢量:

\boldsymbol{v}=(A^T\boldsymbol{A})^{-1}\boldsymbol{A}^T\boldsymbol{b}

其上为该跟踪算法运行矢量的求解过程,其具体实现为:

import cv2
# 一些常数及默认参数
lk_params = dict(winSize=(15,15),maxLevel=2,criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT,10,0.03))
subpix_params = dict(zeroZone=(-1,-1),winSize=(10,10),criteria = (cv2.TERM_CRITERIA_COUNT | cv2.TERM_CRITERIA_EPS,20,0.03))
feature_params = dict(maxCorners=500,qualityLevel=0.01,minDistance=10)
class LKTracker(object):def __init__(self,imnames):""" 使用图像名称列表初始化 """self.imnames = imnamesself.features = []self.tracks = []self.current_frame = 0

首先是需要建立一个跟踪类,用一个文件名列表对跟踪对象进行初始化,在利用一个变量对当前帧进行跟踪。之后就是需要载入实际图像,并转换成灰度图像,提取利用跟踪的好的特征点:

    def detect_points(self):self.image = cv2.imread(self.imnames[self.current_frame])self.gray = cv2.cvtColor(self.image,cv2.COLOR_BGR2GRAY)# 搜索好的特征点features = cv2.goodFeaturesToTrack(self.gray, **feature_params)# 提炼角点位置cv2.cornerSubPix(self.gray,features, **subpix_params)self.features = featuresself.tracks = [[p] for p in features.reshape((-1,2))]self.prev_gray = self.gray

之后需要获得下 一帧图像,然后应用 OpenCV 函数找出这些点运动到哪里 了,最后清除这些包含跟踪点的列表:

def track_points(self):""" 跟踪检测到的特征 """ if self.features != []:self.step() # 移到下一帧# 载入图像并创建灰度图像self.image = cv2.imread(self.imnames[self.current_frame])self.gray = cv2.cvtColor(self.image,cv2.COLOR_BGR2GRAY)#reshape() 操作,以适应输入格式tmp = np.float32(self.features).reshape(-1, 1, 2)# 计算光流features,status,track_error = cv2.calcOpticalFlowPyrLK(self.prev_gray,self.gray,tmp,None,**lk_params)# 去除丢失的点self.features = [p for (st,p) in zip(status,features) if st]features = np.array(features).reshape((-1,2))for i,f in enumerate(features):self.tracks[i].append(f)ndx = [i for (i,st) in enumerate(status) if not st]ndx.reverse()# 从后面移除for i in ndx:self.tracks.pop(i) self.prev_gray = self.graydef step(self,framenbr=None):""" 移到下一帧。如果没有给定参数,直接移到下一帧 """if framenbr is None:self.current_frame = (self.current_frame + 1) % len(self.imnames)else:self.current_frame = framenbr % len(self.imnames)

在真实场景中使用这个跟踪类的例子为:

from PIL import Image
from matplotlib import pyplot as plt
import lktrackimnames = [r"D:\test\images\bt.000.pgm", r"D:\test\images\bt.001.pgm", r"D:\test\images\bt.002.pgm", r"D:\test\images\bt.003.pgm"]
lkt = lktrack.LKTracker(imnames)
# 在第一帧进行检测,跟踪剩下的帧
img1 = Image.open(imnames[0])
img2 = Image.open(imnames[1])
img3 = Image.open(imnames[2])
img4 = Image.open(imnames[3])
plt.figure()
plt.subplot(141)
plt.imshow(img1)
plt.gray()
plt.axis('off')
plt.subplot(142)
plt.imshow(img2)
plt.gray()
plt.axis('off')
plt.subplot(143)
plt.imshow(img3)
plt.gray()
plt.axis('off')
plt.subplot(144)
plt.imshow(img4)
plt.gray()
plt.axis('off')
plt.show()
lkt.detect_points()
lkt.draw()
for i in range(len(imnames)-1):lkt.track_points()lkt.draw()

原始的4张图像为:

得到的结果为:

 之后还可以对其添加发生器:

    def track(self):for i in range(len(self.imnames)):if self.features == []:self.detect_points()else:self.track_points()# 创建一份 RGB 副本f = np.array(self.features).reshape(-1,2)im = cv2.cvtColor(self.image,cv2.COLOR_BGR2RGB)yield im,f

上面的函数可以使遍历整个序列并将获得的跟踪点和这些图像以 RGB 数组保存,以方便画出跟踪结果,之后可以画出这些点及这些点的跟踪结果:

from PIL import Image
from matplotlib import pyplot as plt
import lktrackimnames = [r"D:\test\dinosaur\viff.000.ppm", r"D:\test\dinosaur\viff.001.ppm", r"D:\test\dinosaur\viff.002.ppm", r"D:\test\dinosaur\viff.003.ppm"]
lkt = lktrack.LKTracker(imnames)
# 在第一帧进行检测,跟踪剩下的帧
img1 = Image.open(imnames[0])
img2 = Image.open(imnames[1])
img3 = Image.open(imnames[2])
img4 = Image.open(imnames[3])
plt.figure()
plt.subplot(141)
plt.imshow(img1)
plt.gray()
plt.axis('off')
plt.subplot(142)
plt.imshow(img2)
plt.gray()
plt.axis('off')
plt.subplot(143)
plt.imshow(img3)
plt.gray()
plt.axis('off')
plt.subplot(144)
plt.imshow(img4)
plt.gray()
plt.axis('off')
lkt = lktrack.LKTracker(imnames)
for im,ft in lkt.track():print ('tracking %d features' % len(ft))
# 画出轨迹
plt.figure()
plt.imshow(im)
for p in ft:plt.plot(p[0],p[1],'bo')
for t in lkt.tracks:plt.plot([p[0] for p in t],[p[1] for p in t])
plt.axis('off')
plt.show()

最终得到的结果为:

这篇关于Python计算机视觉编程 第十章的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147629

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

nudepy,一个有趣的 Python 库!

更多资料获取 📚 个人网站:ipengtao.com 大家好,今天为大家分享一个有趣的 Python 库 - nudepy。 Github地址:https://github.com/hhatto/nude.py 在图像处理和计算机视觉应用中,检测图像中的不适当内容(例如裸露图像)是一个重要的任务。nudepy 是一个基于 Python 的库,专门用于检测图像中的不适当内容。该

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow