视频检查V1(同时输出多动作)

import cv2
import matplotlib.pyplot as plt
import numpy as np
import json
import string
import os, sys
import shutil
import operator
video_base_dir = "E:\\migu_bangong\\new_shipin"  #视频目录
save_base_dir = "E:\\migu\\new_valide"  #保存目录
run_type = "debug"   # debug:不同动作在视频上显示在不同行 为空或为其他值,不同动作显示在同一行
all_video_count = 0
action_dict = { 'wh': 'paida', 'gz': 'guzhang', 'rh': 'huishou', 'ra': 'huishoubi', 'ch': 'taishou'}
debug_action_idx = { 'wh': 1, 'gz': 2, 'rh': 3, 'ra': 4, 'ch': 5}
video_sufix = ['.mp4', '.MOV', '.MP4']
def parse_json(video_path, label, action_dict):
    #label = [" " if l == "" else l for l in label]
    label = np.array(label)
    idxs = np.where(label)[0]
    flag = label[idxs]
    anno = {}
    str_label = '#'.join(label)
    for action in action_dict.keys():
        a_s, a_e = action + '_s', action + '_e' 
        if action not in str_label:
            continue
        idx_s = np.where(
            np.core.defchararray.find(
                label, a_s
            ) != -1
        )[0]
        idx_e = np.where(
            np.core.defchararray.find(
                label, a_e
            ) != -1
        )[0]
        # 长度不对,必是标错了
        if len(idx_s) < len(idx_e):
            
            print("\033[31m视频文件: \033[0m", video_path,action_dict[action], " \033[31m标签有误, idx_s个数 < idx_e个数\033[0m")
            return {}
            
        elif len(idx_s) > len(idx_e):
            print("\033[31m视频文件: \033[0m", video_path,action_dict[action], "\033[31m标签有误, idx_s个数 > idx_e个数\033[0m")
            return {}
        
        # 遍历一遍如果出现idx_s >= idx_e 也是标错了
        for i in range(len(idx_s)):
            if idx_s[i] >= idx_e[i]:
                print("\033[31m视频文件: \033[0m", video_path,action_dict[action], " \033[31m标签有误, 存在idx_s标到idx_e之后的情况\033[0m")
                return {}
        
        idx = np.vstack((idx_s, idx_e)).T
        anno[action] = idx.astype(int)

    return anno
def mk_video_writer(vc, video_path):
    #print("保存视频路径: ", video_path)
    width = int(vc.get(cv2.CAP_PROP_FRAME_WIDTH)) #获取原视频的宽
    height = int(vc.get(cv2.CAP_PROP_FRAME_HEIGHT)) #获取原视频的搞
    fps = int(vc.get(cv2.CAP_PROP_FPS)) #帧率
    fourcc = cv2.VideoWriter_fourcc(*"mp4v") #视频的编码
    out = cv2.VideoWriter(video_path, fourcc, 20.0, (width, height))
    print(video_path)
    return out
def annotation_check_and_delete(root, filename):
    
    video_check_flag = False
    video_path = ""
    for i in range(len(video_sufix)):
        if os.path.exists(os.path.join(root, filename) + video_sufix[i]):
            video_check_flag = True
            video_path = os.path.join(root, filename) + video_sufix[i]
    
    hand_json = os.path.join(root, filename) + ".json"
    det_json = os.path.join(root, filename) + "_det.json"
    if not os.path.exists(hand_json) or not video_check_flag:
        
        # 删video
        if os.path.exists(video_path):
          #  print("删除"+small_case_video_path)
            os.remove(video_path)

        # 删json
        if os.path.exists(hand_json):
            #print("删除"+hand_json)
            os.remove(hand_json)

        # 删det_json
        if os.path.exists(det_json):
            #print("删除"+det_json)
            os.remove(det_json)

        return True
    return False
def handle_single(filename, json_path, video_path, action_dict):
    label_count_dict = {'paida': 0, 'guzhang': 0, 'huishou': 0, 'huishoubi': 0, 'taishou': 0}
    try:
        labelme_json = json.load(open(json_path, encoding='utf-8'))
    except UnicodeError:
        print("标签文件: ", json_path, " 格式有误!")
        return label_count_dict
    
    label = labelme_json['label']
    anno = parse_json(video_path, label, action_dict)
    # 标签出错不继续执行
    if len(anno.keys()) == 0:
        return label_count_dict
    
    vc = cv2.VideoCapture(video_path)
    
    i = 0  #当前帧数
    n = 0  #当前是第几次动作(一个连续动作为1次)

    # 视频有多个动作
    action_name = 'nullact'
    idx_list = []
    for key in anno.keys():
        for pair in anno[key]:
            idx_list.append([pair, key])
    
    idx_list.sort(key = lambda pair: (pair[0][0], pair[0][1]))
    print(idx_list)
    max_n = len(idx_list)
    text = 'null'
    open_mp4 = True
    out = mk_video_writer(vc, os.path.join(save_base_dir, video_path.split(video_base_dir)[1][1:]))
    
    if not vc.isOpened():
        open_mp4 = False
    while open_mp4:
          ret,frame = vc.read()
          if frame is None:
            break
          if ret == True:
            f_id = 'frame:%06d' % i
            if n < max_n and i in np.array(range(idx_list[n][0][0], idx_list[n][0][1] + 1)): # 动作开始到动作结束之间
                pre_n = n
                while n < max_n and i >= idx_list[n][0][0]:
                    if i in np.array(range(idx_list[n][0][0], idx_list[n][0][1] + 1)):
                        if i == idx_list[n][0][0]:
                            label_count_dict[action_dict[idx_list[n][1]]] += 1
#                         print(i, idx_list[n])
                        text = 'action:%s' % action_dict[idx_list[n][1]] + str(label_count_dict[action_dict[idx_list[n][1]]])
                        cv2.putText(frame, f_id, (5,50 ), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
                        cv2.putText(frame, text, (5,50 + (25 * debug_action_idx[idx_list[n][1]] if run_type == 'debug' else 25)), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
                    n = n + 1
                i = i + 1
                n = pre_n
                while n < max_n and i == idx_list[n][0][1]:
                    n = n + 1
            elif n < max_n and i < idx_list[n][0][0]: # 动作开始前
                #只打印帧数
                cv2.putText(frame, f_id, (5,50 ), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
                i = i + 1
            else :
                while n < max_n and i > idx_list[n][0][1]:
                    n += 1
                #只打印帧数
                cv2.putText(frame, f_id, (5,50 ), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
                i = i + 1
            #cv2.imshow('result',frame)
            #if cv2.waitKey(1)&0xFF==27:#括号中数字越大,视频播放速度越慢。0xFF==27表示按ESC后退出视频播放
                #break
            out.write(frame) #写入视频
    #然后保存视频
    vc.release()
    out.release()
    cv2.destroyAllWindows()
    cv2.waitKey(1)

    return label_count_dict
def process(root, files, action_dict):

    video_count = 0
    
    print()
    print("\033[34m当前目录\033[0m"+root)
    for file in files:
        filename = file[:-4]
        if file.endswith(".json"):
            filename = file[:-9] if file.endswith("_det.json") else file[:-5]
        # 如果没有json文件就直接删了也不用走接下来的步骤
        if annotation_check_and_delete(root, filename):
            continue
        if not file[-4:] in video_sufix or not os.path.exists(os.path.join(root, file)):
            continue
        
        video_path = os.path.join(root, file)
        hand_json = video_path[:-4] + '.json'
        
        video_count += 1
        label_count_dict = handle_single(file, hand_json, video_path, action_dict)
        print("视频: ", file , " 动作统计为: ", label_count_dict)
    return video_count
#root保存的就是当前遍历的文件夹的绝对路径;
#dirs保存当前文件夹下的所有子文件夹的名称(仅一层,孙子文件夹不包括)
#files保存当前文件夹下的所有文件的名称
#深度遍历
for root, dirs, files in os.walk(video_base_dir):
    if len(files) <= 0:
        continue
    if os.path.exists(os.path.join(save_base_dir, root.split(video_base_dir)[1][1:])):
        shutil.rmtree(os.path.join(save_base_dir, root.split(video_base_dir)[1][1:]))
    os.makedirs(os.path.join(save_base_dir, root.split(video_base_dir)[1][1:]))
    all_video_count += process(root, files, action_dict)
print("共处理:", all_video_count, " 个视频")

你可能感兴趣的:(python)