使用opencv解析视频,通过图片比对,筛选出每一帧视频的变化

发布时间 2023-09-19 12:03:36作者: wozijisun

记录瞬间

最近碰到一个问题,在客户端上操作时,存在背景判断的情况,对自动化实现此操作增加难度。

 

所以考虑到实际的使用,将一些计算机视觉技术加入到实际的使用中,来解决此问题。

 

import os
import cv2
import numpy


# 打开视频文件
video = cv2.VideoCapture('./video/path.mp4')
phone_width = 1080      # 手机设备的宽度
phone_height = 2400     # 手机设备的高度
# 获取视频的帧率和尺寸
fps = video.get(cv2.CAP_PROP_FPS)
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
print("fps:", fps, "width:", width, "height:", height)

# 创建VideoWriter对象以保存提取的帧为新的视频文件
# output = cv2.VideoWriter('path_to_output_file.mp4', cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height))
count = 0
# 循环读取视频帧并保存
while video.isOpened():
    ret, frame = video.read()

    if not ret:
        break

    # 将帧写入输出文件
    # output.write(frame)

    # 显示帧(可选)
    # cv2.imshow('Video', frame)
    new_img = frame[:phone_height, :phone_width, :]
    cv2.imwrite(f"./image/{count}.png", new_img)
    count += 1

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源
video.release()
# output.release()
cv2.destroyAllWindows()

"""
# 以下是判断图片内容,以第一个图片为准,其他图片作为对比结果,对比相似度
# 但是此方法需要设定一个对比的相似度的值,不是很能说明问题,这个值的取值怎么定,为啥这么定,谁能给出解释?
all_values = {}
img0 = "./image/0.png"
read_img0 = cv2.imread(img0)
H1 = cv2.calcHist([read_img0], [1], None, [256], [0, 256])
H1 = cv2.normalize(H1, H1, 0, 1, cv2.NORM_MINMAX, -1)
for img in os.listdir("./image"):
    compare = cv2.imread(f"./image/{img}")
    H2 = cv2.calcHist([compare], [1], None, [256], [0, 256])
    H2 = cv2.normalize(H2, H2, 0, 1, cv2.NORM_MINMAX, -1)
    similarity = cv2.compareHist(H1, H2, 0)
    if similarity > 0.99:
        try:
            all_values[similarity] = f"./image/{img}"
        except:
            print(f"存在相同的key值{similarity}的数据,预判一下这个预判。好像也没啥用")
            continue
    else:
        print(f"./image/{img}", similarity)

keys = list(all_values.keys())
keys.sort()
print(keys[0], keys[-1], all_values[keys[0]], all_values[keys[-1]])
for data in keys:
    print(all_values[data])
"""

def match_template(source, template, threshod=0.9, method=cv2.TM_CCOEFF_NORMED):
    """
    返回小图左上角的点,在大图中的坐标。
    :param threshod: 相似度
    :param template: 目标对比图片
    :param source: 原始图片
    :param method:
    :return: list[tuple(x,y),...]
    """
    try:
        result = cv2.matchTemplate(source, template, method)
        locations = numpy.where(result >= threshod)
        res = list(zip(locations[1], locations[0]))  # 返回的是匹配到的template左上角那个坐标点在image中的位置,可能有多个值
        return res
    except cv2.error as e:
        print(e)

# 另一个方法,是可以通过某一个图片的坐标来判断,主要是判断y坐标的最大值变化,来进行实际操作
img0 = "./image/0.png"
source = cv2.imread(img0, cv2.IMREAD_UNCHANGED)
images = ["./image/pic_path.png", "./image/pic_path.png"]      # 判断一个不变的元素图片
exist_img = ""
for img in images:
    template = cv2.imread(img, cv2.IMREAD_UNCHANGED)
    get_pos = match_template(source, template)
    print(get_pos)
    if len(get_pos) > 0:
        exist_img = img
if len(exist_img) > 0:
    target = cv2.imread(exist_img, cv2.IMREAD_UNCHANGED)
    max_y_pos = 0
    max_target_image = ""
    for img in os.listdir("./image"):
        temp_img = cv2.imread(f"./image/{img}", cv2.IMREAD_UNCHANGED)
        get_pos = match_template(temp_img, target, threshod=0.86)
        print(get_pos, img)
        try:
            if get_pos[0][1] > max_y_pos:
                max_y_pos = get_pos[0][1]
                max_target_image = img
        except:
            print(img)

    print(max_target_image, max_y_pos)

 

其中图片相似的判断方法,可以参考:https://blog.csdn.net/qq_39706141/article/details/118730137

以上简单的代码逻辑,实现了设备录屏后,抓取视频文件,解析视频每一帧,并保存每一帧为图片,后续将图片进行解析,判断固定元素在图片中 纵坐标的最大值,即为查看结果的最终图片数据。

录屏可以通过客户端工具如 airtest、appium等。

 

from airtest.core.api import *
import time

auto_setup(__file__)

init_device(platform="Android", uuid="phoneid")
dev = device()

wake()
stop_app('appname')
start_app('appname')

sleep(3.0)

touch(Template(r"pic.png", record_pos=(-0.002, 1.046), resolution=(1080, 2400)))

# 录屏开始
dev.start_recording()

swipe(Template(r"pic_swipe.png", record_pos=(0.002, 0.076), resolution=(1080, 2400)), vector=[0.0722, 0.3658], duration=1.0)
sleep(8.0)

# 结束录屏
dev.stop_recording()