python计算机视觉编程——10.OpenCV
- 10.OpenCV
- 10.2 OpenCV基础知识
- 10.2.1 读取和写入图像
- 10.2.2 颜色空间
- 10.2.3 显示图像及结果
- 10.3 处理视频
- 10.3.1 视频输入
- 10.3.2 将视频读取到NumPy数组中
- 10.4 跟踪
- 10.4.1 光流
- 10.4.2 Lucas-Kanade算法
- 使用跟踪器
- 使用发生器
- 10.5 更多示例
- 10.5.1图像修复
10.OpenCV
10.2 OpenCV基础知识
10.2.1 读取和写入图像
import cv2
from pylab import *
im=cv2.imread('sun.jpg')
h,w=im.shape[:2]
print(h,w)
cv2.imwrite('result.png',im)
10.2.2 颜色空间
im=cv2.imread('sun.jpg')
# 创建灰度图像
# COLOR_BGR2GRAY、COLOR_BGR2RGB、COLOR_GRAY2BGR
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
imshow(gray)
10.2.3 显示图像及结果
import cv2
# 读取图像
im = cv2.imread('sun.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 = 'sun.jpg'
im = cv2.imread(filename)
h,w = im.shape[:2]
# 泛洪填充
diff = (6,6,6)
mask = np.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)
from pylab import *
im1=cv2.imread('result_10.2.3-1.jpg')
im2=cv2.imread('result_10.2.3-2.jpg')
gray()
subplot(121)
imshow(im1)
subplot(122)
imshow(im2)
import cv2
# 初始化 ORB 检测器
orb = cv2.ORB_create()
# 读取图像
image = cv2.imread('sun.jpg', cv2.IMREAD_GRAYSCALE)
# 检测关键点和描述符
keypoints, descriptors = orb.detectAndCompute(image, None)
# 在图像上绘制关键点
output_image = cv2.drawKeypoints(image, keypoints, None)
# 显示结果
cv2.imshow('ORB Keypoints', output_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
10.3 处理视频
10.3.1 视频输入
import cv2
#设置视频捕获
# cap = cv2.VideoCapture(0) #可以是摄像头的索引
cap = cv2.VideoCapture('MARSCONCERT.mp4') #也可以是视频的名称
if not cap.isOpened():
print("无法打摄像机")
exit()
while True:
ret,im = cap.read()
cv2.imshow('video_test',im)
key = cv2.waitKey(10)
if key == 27: #Esc键退出
break
if key == ord(' '): #空格抓拍
cv2.imwrite('vid_result.jpg',im)
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
还可以对实时显示的图像进行模糊
import cv2
# 1. 捕获视频
cap = cv2.VideoCapture('MARSCONCERT.mp4') # 0通常代表默认的摄像头,也可以替换为视频文件的路径
# 检查摄像头是否成功打开
if not cap.isOpened():
print("Error opening video stream or file")
exit()
# 2. 设置输出视频参数
# fourcc = cv2.VideoWriter_fourcc(*'XVID') # 选择编码器
# out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480)) # 输出视频文件名、编码器、帧率、分辨率
# 3. 读取并处理帧
while(cap.isOpened()):
ret, frame = cap.read() # 读取一帧
if ret == True:
blur = cv2.GaussianBlur(frame,(0,0),5)
# 将处理后的帧写入输出视频
# out.write(gray)
# 显示帧(可选)
cv2.imshow('frame', blur)
key = cv2.waitKey(10)
if key == 27: #(Esc键)
break
if key == ord(' '):
cv2.imwrite('vid_result.jpg',im)
else:
break
# 完成后释放资源
cap.release()
# out.release()
cv2.destroyAllWindows()
10.3.2 将视频读取到NumPy数组中
import cv2
import numpy as np
cap = cv2.VideoCapture('MARSCONCERT.mp4')
frames=[]
# 获取帧,存储到数组中
flag=0
while True:
ret,im = cap.read()
if flag==0:
print(im.shape)
flag=1
if ret == True:
cv2.imshow('video',im)
frames.append(im)
if cv2.waitKey(10) == 27:
print(im.shape)
break
else:
break
frames = np.array(frames)
# 检查尺寸
print(frames.shape)
# 完成后释放资源
cap.release()
cv2.destroyAllWindows() # 有帧数、帧高、帧宽及颜色通道数(3个),共记录了181帧
10.4 跟踪
10.4.1 光流
- 光流法主要依赖于三个假设。
- 亮度恒定:图像中目标的像素强度在连续帧之间不会发生变化。
- 时间规律:相邻帧之间的时间足够短,以至于在考虑运行变化时可以忽略它们之 间的差异。该假设用于导出下面的核心方程。
- 空间一致性:相邻像素具有相似的运动。
import cv2
import numpy as np
def draw_flow(im,flow,step=16):
""" 在间隔分开的像素采样点处绘制光流"""
h,w = im.shape[:2] # 获取图像的高度和宽度
y,x = np.mgrid[step/2:h:step,step/2:w:step].reshape(2,-1) # 生成间隔分开的采样点坐标
y, x = y.astype(np.int32), x.astype(np.int32) # 转换为整数类型
# print(y,x)
fx,fy = flow[y,x].T # 获取每个采样点的光流向量分量
# 创建线的终点
lines = np.vstack([x,y,x+fx,y+fy]).T.reshape(-1,2,2)
lines = np.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('小镇里的花.mp4')
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
cap.release()
cv2.destroyAllWindows()
10.4.2 Lucas-Kanade算法
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 = imnames
self.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 = features
self.tracks = [[p] for p in features.reshape((-1,2))]
self.prev_gray = self.gray
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.gray
def 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()
import numpy as np
imnames = ['bt.003.pgm', 'bt.002.pgm', 'bt.001.pgm', 'bt.000.pgm']
# 创建跟踪对象
lkt = LKTracker(imnames)
# 在第一帧进行检测,跟踪剩下的帧
lkt.detect_points()
lkt.draw()
for i in range(len(imnames)-1):
lkt.track_points()
lkt.draw()
cv2.waitKey(0)
cv2.destroyAllWindows()
将下面的方法添加到LKTracker类:
def track(self):
""" 发生器,用于遍历整个序列"""
for i in range(len(self.imnames)):
if self.features == []:
self.detect_points()
else:
self.track_points()
# 创建一份RGB副本
f = array(self.features).reshape(-1,2)
im = cv2.cvtColor(self.image,cv2.COLOR_BGR2RGB)
yield im,f
from pylab import *
imnames = ['viff.000.ppm', 'viff.001.ppm','viff.002.ppm', 'viff.003.ppm', 'viff.004.ppm']
# 用LKTracker 发生器进行跟踪
lkt = LKTracker(imnames)
for im,ft in lkt.track():
print('tracking %d features' % len(ft))
# 画出轨迹
figure()
imshow(im)
for p in ft:
plot(p[0],p[1],'bo')
for t in lkt.tracks:
plot([p[0] for p in t],[p[1] for p in t])
axis('off')
show()
10.5 更多示例
10.5.1图像修复
import numpy as np
import cv2
#读取图片
img = cv2.imread('repair.png')
#图像转换为灰度图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#灰度二值化
_,mask = cv2.threshold(cv2.cvtColor(img,cv2.COLOR_BGR2GRAY),100,255,cv2.THRESH_BINARY_INV)
dst = cv2.inpaint(img,mask,10,cv2.INPAINT_NS) #3:领域大小
cv2.imshow('img0',img)
#cv2.imshow('img10',mask1)
cv2.imshow('img1',mask)
cv2.imshow('img2',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
下图为修复前的图像
下图为掩模图
下图为修复图像,可以看到,虽然黑线被修复了,但是整体图像中,原本不需要修复的地方,会被修复函数当作是需要修复的