使用opencv解析视频,通过图片比对,筛选出每一帧视频的变化
记录瞬间
最近碰到一个问题,在客户端上操作时,存在背景判断的情况,对自动化实现此操作增加难度。
所以考虑到实际的使用,将一些计算机视觉技术加入到实际的使用中,来解决此问题。
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()