Opencv——视频融合及人物影像探测


前言

【知识点】
视觉处理技术结合模式识别方法。

【素材准备】
准备视频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://pan.baidu.com/s/1XVcz9U_M9vLfr4k_4JMJhg?pwd=lkqd
提取码:lkqd

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值