前言
【知识点】
视觉处理技术结合模式识别方法。
【素材准备】
准备视频A和视频B。
其中 视频A 是网上下载的风景区的视频录制(如张家界、武夷山或五大名山之一)。
视频B是个人在白墙或纯色背景前的行走视频。
【要求】
(i)通过阈值方法,结合OPENCV的与或运算,将视频B的个人影像(消除背景后)融入视频A,得到视频C。(50%)
(ii)设计一种特征值,使得个人的影像能在图像中被探测到。 (20%)
(iii)利用 (ii) 的特征值计算方法,在视频C中找出个人在每帧中的位置,用矩形绘出大致位置(30%)
一、视频准备及函数定义
import os
import cv2
import matplotlib.pyplot as plt
os.chdir('C:/Users/Bert/PycharmProjects/模式识别与计算机视觉/实验三/video/')
# 定义视频路径
A_video = "A_3.mp4" # 背景视频
B_video = "B_5.mp4" # 人物视频
result_video = "A3_mingle_B5.mp4" # 输出视频
# Define the codec and create VideoWriter object
cap_A = cv2.VideoCapture(A_video) # 读取视频A
cap_B = cv2.VideoCapture(B_video) # 读取视频B
fps_video_A = cap_A.get(cv2.CAP_PROP_FPS) # 获取视频A帧率
fps_video_B = cap_B.get(cv2.CAP_PROP_FPS) # 获取视频B帧率
fourcc = cv2.VideoWriter_fourcc(*"mp4v") # 设置写入视频的编码格式
width_A = int(cap_A.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取视频A宽度
width_B = int(cap_B.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取视频B宽度
height_A = int(cap_A.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频A高度
height_B = int(cap_B.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频B高度
roi_width = int((width_A - width_B) / 2) # 人物视频在背景视频起始宽度
roi_height = int((height_A - height_B) / 2) # 人物视频在背景视频起始高度
videoWriter = cv2.VideoWriter(result_video, fourcc, fps_video_A, (width_A, height_A)) # 保存视频
print("视频A的宽度:{} 视频A的高度:{} 视频A的帧率:{}".format(width_A, height_A, fps_video_A))
print("视频B的宽度:{} 视频B的高度:{} 视频B的帧率:{}".format(width_B, height_B, fps_video_B))
## 去除视频的水印
def process_watermarkn(image):
# 需要注意的是第一个范围是y轴坐标的范围,第二个是x轴坐标的范围
image[140:220, 0:255] = image[140 - 80:220 - 80, 0:255]
return image
## 视频融合
def video_mingle(frame_g, frame_m):
## 1. 根据背景大小提取感兴趣区域roi
# 把人物放在背景视频中心位置,提取原图中要放置人物的区域roi
rows, cols = frame_m.shape[:2]
roi = frame_g[roi_height:rows + roi_height, roi_width:cols + roi_width]
## 2. 创建掩膜mask:用一副二值化图片对另外一幅图片进行局部的遮挡。
img2gray = cv2.cvtColor(frame_m, cv2.COLOR_BGR2GRAY) # 将图片灰度化,如果在读取人物时直接灰度化,该步骤可省略
# cv2.THRESH_BINARY:如果一个像素值低于200,则像素值转换为255(白色色素值),否则转换成0(黑色色素值)
# 即有内容的地方为黑色0,无内容的地方为白色255.
# 白色的地方还是白色,除了白色的地方全变成黑色
ret, mask = cv2.threshold(img2gray, 190, 255, cv2.THRESH_BINARY) # 阙值操作
mask_inv = cv2.bitwise_not(mask) # 与mask颜色相反,白色变成黑色,黑变白
## 3. 人物与感兴趣区域roi融合
# 保留除人物外的背景
img1_bg = cv2.bitwise_and(roi, roi, mask=mask)
img2_fg = cv2.bitwise_and(frame_m, frame_m, mask=mask_inv)
dst = cv2.add(img1_bg, img2_fg) # 人物与感兴趣区域roi进行融合
frame_g[roi_height:rows + roi_height, roi_width:cols + roi_width] = dst # 将融合后的区域放进原图
img_new = frame_g.copy() # 对处理后的图像进行拷贝
return img2gray, mask, mask_inv, roi, img1_bg, img2_fg, dst, img_new
## cv2与matplotlib的图像颜色模式转换,cv2是BGR格式,matplotlib是RGB格式
def img_convert(cv2_img):
# 灰度图片直接返回
if len(cv2_img.shape) == 2:
return cv2_img
# 3通道的BGR图片
elif len(cv2_img.shape) == 3 and cv2_img.shape[2] == 3:
b, g, r = cv2.split(cv2_img) # 分离原图像通道
return cv2.merge((r, g, b)) # 合并新的图像通道
# 4通道的BGR图片
elif len(cv2_img.shape) == 3 and cv2_img.shape[2] == 4:
b, g, r, a = cv2.split(cv2_img)
return cv2.merge((r, g, b, a))
# 未知图片格式
else:
return cv2_img
二、视频融合和抽取融合中视频帧变化过程
抽取第一张图片查看融合中视频帧变化过程,其余则根据cap_A.isOpened() & cap_B.isOpened()都为True条件下进行视频融合。
frame_id = 0
while cap_A.isOpened() & cap_B.isOpened():
ret_A, frame_A = cap_A.read() # 背景视频
ret_B, frame_B = cap_B.read() # 人物视频
if ret_A == True & ret_B == True:
frame_id += 1
## 抽取融合中视频帧变化过程
if frame_id == 1:
frame_B = process_watermarkn(frame_B)
capture_new = video_mingle(frame_A, frame_B)
titles = ['B', 'B_gray', 'B_mask', 'B_mask_inv', 'roi', 'img1_bg', 'img2_fg', 'dst']
imgs = [frame_B, capture_new[0], capture_new[1], capture_new[2], capture_new[3], capture_new[4],
capture_new[5], capture_new[6]]
for i in range(len(imgs)):
plt.subplot(2, 4, i + 1), plt.imshow(img_convert(imgs[i]), 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
plt.close()
continue
## 视频A和视频B融合过程
else:
frame_B = process_watermarkn(frame_B)
img_new_add = video_mingle(frame_A, frame_B)[-1]
videoWriter.write(img_new_add)
else:
break
# Release everything if job is finished
cap_A.release()
cap_B.release()
videoWriter.release()
cv2.destroyAllWindows()
结果如下:
原A.mp4:
原B.mp4:
A_mingle_B.mp4:
视频帧变化过程:
参考链接:
OpenCV_Python官方文档7+——按位运算之给图像加logo
三、人物影像探测
将以上得到的融合视频进行特征检测,使得个人的影像能在图像中被探测到。 在视频中找出个人在每帧中的位置,用矩形绘出大致位置。
import cv2
#定义视频路径
org_video = "./video/A3_mingle_B5.mp4"
sub_video = "./video/A3_feature_extract_B5.mp4"
# Define the codec and create VideoWriter object
cap = cv2.VideoCapture(org_video) # 读取视频
fps_video = cap.get(cv2.CAP_PROP_FPS)# 获取视频帧率
fourcc = cv2.VideoWriter_fourcc(*"mp4v")# 设置写入视频的编码格式
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))# 获取视频宽度
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))# 获取视频高度
videoWriter = cv2.VideoWriter(sub_video, fourcc, fps_video, (width, height))#保存视频
print(width,height)
def is_inside(o, i):
'''
判断矩形o是不是在i矩形中
args:
o:矩形o (x,y,w,h)
i:矩形i (x,y,w,h)
'''
ox, oy, ow, oh = o
ix, iy, iw, ih = i
return ox > ix and oy > iy and ox + ow < ix + iw and oy + oh < iy + ih
def draw_person(img, person):
'''
在img图像上绘制矩形框person
args:
img:图像img
person:人所在的边框位置 (x,y,w,h)
'''
x, y, w, h = person
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
def detect_test(img):
hog = cv2.HOGDescriptor()
detector = cv2.HOGDescriptor_getDefaultPeopleDetector()
hog.setSVMDetector(detector)
# 多尺度检测,found是一个数组,每一个元素都是对应一个矩形,即检测到的目标框
found, w = hog.detectMultiScale(img)
# 过滤一些矩形,如果矩形o在矩形i中,则过滤掉o
found_filtered = []
for ri, r in enumerate(found):
for qi, q in enumerate(found):
if ri != qi and is_inside(r, q):
break
else:
found_filtered.append(r)
for person in found_filtered:
draw_person(img, person)
return img
while cap.isOpened():
ret, frame = cap.read()
if ret == True:
# HOG:对象检测与模式匹配中是一种常见的特征提取算法,是基于本地像素块进行特征直方图提取的一种算法 + SVM
# 方向梯度直方图:计算和统计图像局部区域的梯度方向直方图来构成特征.
frame = detect_test(frame)
videoWriter.write(frame)
else:
break
# Release everything if job is finished
cap.release()
videoWriter.release()
cv2.destroyAllWindows()
结果如下:
参考链接:HOG特征详解与行人检测
四、建议
1.视频最终效果与视频B是个人在白墙或纯色背景前的行走视频有关,最好选取白色背景明显,整个人物明显区分于白色背景的视频,如面色,衣服等。
2.通过调节阈值也可以增强实验效果,具体代码在这一步:
ret, mask = cv2.threshold(img2gray, 215, 255, cv2.THRESH_BINARY) # 阙值操作
该代码的解释为:将灰度图中灰度值小于215的点置0,灰度值大于215的点置255。因此可以改变代码中215数值来增强视频效果。
3.注意视频尺寸:背景视频尺寸一定要大于人物视频尺寸,无论长和宽。
4.人物影像探测那里建议适当添加如下参数值获取更好效果,但会增加检测时延:
found, w = hog.detectMultiScale(img)
如以下参数值winStride=(4, 4), padding=(8, 8), scale=1.25, useMeanshiftGrouping=False。具体用法可以搜索 hog.detectMultiScale()用法文章来源:https://www.toymoban.com/news/detail-405853.html
视频文件及代码链接:
https://pan.baidu.com/s/1XVcz9U_M9vLfr4k_4JMJhg?pwd=lkqd
提取码:lkqd文章来源地址https://www.toymoban.com/news/detail-405853.html
到了这里,关于Opencv——视频融合及人物影像探测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!