当前位置: 首页 > news >正文

Python计算机视觉编程 第十章 OpenCV

目录

  • OpenCV的Python接口
  • OpenCV基础知识
    • 读取和写入图像
    • 颜色空间
    • 显示图像及结果
  • 处理视频
    • 视频输入
    • 将视频读取到NumPy数组中
  • 跟踪
    • 光流
    • Lucas-Kanade算法

OpenCV的Python接口

目前,OpenCV 的Python 接口仍在发展,不过并不是所有的OpenCV组件都提供了相应的Python 接口。
OpenCV 2.3.1 版本实际上提供了两个Python 接口。旧的cv 模块使用OpenCV 内部数据类型,并且从NumPy 使用起来可能需要一些技巧。新的cv2 模块用到了NumPy 数组,并且使用起来更加直观1,可以通过以下方式导入新的cv2 模块:

import cv2

OpenCV基础知识

OpenCV 自带读取、写入图像函数以及矩阵操作和数学库。我们现在来看一些基本的组件及其使用方法

读取和写入图像

import cv2
# 读取图像
im = cv2.imread('empire.jpg')
h,w = im.shape[:2]
print h,w
# 保存图像
cv2.imwrite('result.png',im)

函数imread() 返回图像为一个标准的NumPy 数组,并且该函数能够处理很多不同格式的图像。如果你愿意,可以将该函数作为PIL 模块读取图像的备选方案。函数imwrite() 会根据文件后缀自动转换图像

颜色空间

在OpenCV 中,图像不是按传统的RGB 颜色通道,而是按BGR 顺序(即RGB 的倒序)存储的。读取图像时默认的是BGR,但是还有一些可用的转换函数。颜色空间的转换可以用函数cvColor() 来实现。例如,可以通过下面的方式将原图像转换成灰度图像:

im = cv2.imread('empire.jpg')
# 创建灰度图像
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)

显示图像及结果

这个例子是从文件中读取一幅图像,并创建一个整数图像表示

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

这个例子从一个种子像素进行泛洪填充

import cv2
# 读取图像
filename = 'fisherman.jpg'
im = cv2.imread(filename)
h,w = im.shape[:2]
# 泛洪填充
diff = (6,6,6)
mask = zeros((h+2,w+2),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

结果如下所示
在这里插入图片描述
在该例中,对图像应用泛洪填充并在OpenCV 窗口中显示结果。waitKey() 函数一直处于暂停状态,直到有按键按下,此时窗口才会自动关闭。这里的floodfill() 函数获取(灰度或彩色)图像、一个掩膜(非零像素区域表明该区域不会被填充)、一个种子像素以及新的颜色值来代替下限和上限阈值差的泛洪像素。泛洪填充以种子像素为起始,只要能在阈值的差异范围内添加新的像素,泛洪填充就会持续扩展。

处理视频

单纯使用Python 来处理视频有些困难,因为需要考虑速度、编解码器、摄像机、操作系统和文件格式。目前还没有针对Python 的视频库,使用OpenCV 的Python 接口是唯一不错的选择。下面介绍几个基本示例

视频输入

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)

拓展上面的例子,将摄像头捕获的数据作为输入,并在OpenCV 窗口中实时显示经模糊的(彩色)图像

import cv2
# 设置视频捕获
cap = cv2.VideoCapture(0)
# 获取视频帧,应用高斯平滑,显示结果
while True:ret,im = cap.read()blur = cv2.GaussianBlur(im,(0,0),5)cv2.imshow('camera blur',blur)if cv2.waitKey(10) == 27:break

如果仅有一个摄像头与计算机相连接,那么该摄像头的id为0。read() 方法解码并返回下一视频帧,第一个变量ret 是一个判断视频帧是否成功读入的标志,第二个变量则是实际读入的图像数组。函数waitKey() 等待用户按键:如果按下的是Esc 键(ASCII 码是27)键,则退出应用;如果按下的是空格键,就保存该视频帧。
在这里插入图片描述
会得到本人在镜头前的画面。

将视频读取到NumPy数组中

使用OpenCV 可以从一个文件读取视频帧,并将其转换成NumPy 数组。下面是一个从摄像头捕获视频并将视频帧存储在一个NumPy 数组中的例子

import cv2
# 设置视频捕获
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 = array(frames)
# 检查尺寸
print im.shape
print frames.shap

会得到一幅作者在镜头前的画面(这里不展示),上述代码将每一视频帧数组添加到列表末,直到捕获结束。最终得到的数组会有帧数、帧高、帧宽及颜色通道数(3 个),打印出的结果如下
在这里插入图片描述

跟踪

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

光流

光流是目标、场景或摄像机在连续两帧图像间运动时造成的目标的运动。它是图像在平移过程中的二维矢量场。作为一种经典并深入研究了的方法,它在诸如视频压缩、运动估计、目标跟踪和图像分割等计算机视觉中得到了广泛的应用。
光流法主要依赖于三个假设。
(1) 亮度恒定: 图像中目标的像素强度在连续帧之间不会发生变化。
(2) 时间规律 :相邻帧之间的时间足够短,以至于在考虑运行变化时可以忽略它们之间的差异。该假 设用于导出下面的核心方程。
(3) 空间一致性 :相邻像素具有相似的运动。

import cv2
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)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

结果如下图所示,圆环网格表示流样本的位置,带有线条的流矢量显示了每个样本点是怎样运动的。
在这里插入图片描述

Lucas-Kanade算法

跟踪最基本的形式是跟随感兴趣点,比如角点。对此,一次流行的算法是Lucas-Kanade 跟踪算法,它利用了稀疏光流算法。Lucas-Kanade 跟踪算法可以应用于任何一种特征,不过通常使用一些角点,比如Harris 角点,角点是结构张量(Harris 矩阵)中有两个较大特征值的那些点,且更小的特征值要大于某个阈值。下面介绍一个利用相关函数建立一个Python跟踪类的过程:

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):"""  用金字塔光流Lucas-Kanade 跟踪类"""
def __init__(self,imnames):""" 使用图像名称列表初始化"""self.imnames = imnamesself.features = []self.tracks = []self.current_frame = 0def 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.gradef 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 = 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 = 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)def draw(self):""" 用OpenCV 自带的画图函数画出当前图像及跟踪点,按任意键关闭窗口""" # 用绿色圆圈画出跟踪点for point in self.features:cv2.circle(self.image,(int(point[0][0]),int(point[0][1])),3,(0,255,0),-1)cv2.imshow('LKtrack',self.image)cv2.waitKey()

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 2024考研数学真题解析-数二:
  • 图的应用(拓扑排序)
  • Linux:Bash中的文件描述符
  • C语言 | Leetcode C语言题解之题409题最长回文串
  • 深入分析几个难以理解的Comparator源码
  • 心觉:小时候常听到的这些教导,正在禁锢你的人生,该翻身了
  • 小程序开发设计-第一个小程序:注册小程序开发账号②
  • C# 比较对象新思路,利用反射技术打造更灵活的比较工具
  • 【MYSQL表的增删改查(进阶)】
  • 【JS】path的使用说明
  • 105.游戏安全项目-基址的技术原理-分析技巧
  • Unity 之 【Android Unity FBO渲染】之 [Unity 渲染 Android 端播放的视频] 的一种方法简单整理
  • Centos7更换阿里云的 YUM 镜像仓库
  • 计算机网络30——Linux-gdb调试命令makefile
  • Jenkins Docker Pipeline Clone Build Deploy mysqldump
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • Android组件 - 收藏集 - 掘金
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • gitlab-ci配置详解(一)
  • js算法-归并排序(merge_sort)
  • Lucene解析 - 基本概念
  • Python学习笔记 字符串拼接
  • Redash本地开发环境搭建
  • SpringBoot几种定时任务的实现方式
  • springMvc学习笔记(2)
  • Vue.js 移动端适配之 vw 解决方案
  • 大整数乘法-表格法
  • 动态魔术使用DBMS_SQL
  • 分类模型——Logistics Regression
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • 首页查询功能的一次实现过程
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​插件化DPI在商用WIFI中的价值
  • #define,static,const,三种常量的区别
  • $(selector).each()和$.each()的区别
  • (7)svelte 教程: Props(属性)
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (TOJ2804)Even? Odd?
  • (差分)胡桃爱原石
  • (分布式缓存)Redis持久化
  • (强烈推荐)移动端音视频从零到上手(上)
  • (数据结构)顺序表的定义
  • (四)opengl函数加载和错误处理
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • (一)模式识别——基于SVM的道路分割实验(附资源)
  • ./configure,make,make install的作用
  • .NET Core Web APi类库如何内嵌运行?
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET+WPF 桌面快速启动工具 GeekDesk
  • .Net6使用WebSocket与前端进行通信
  • ::什么意思
  • @JsonSerialize注解的使用