├── outputs └── .gitkeep ├── video └── .gitkeep ├── .gitignore ├── requirements.txt └── main.py /outputs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /video/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | video/* 2 | !video/.gitkeep 3 | outputs/* 4 | !outputs/.gitkeep -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | hyperlpr3==0.1.3 2 | opencv_python==4.10.0.84 3 | tqdm==4.66.4 4 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import datetime 3 | import json 4 | import os 5 | import sys 6 | 7 | import cv2 8 | import hyperlpr3 as lpr3 9 | from tqdm import tqdm 10 | 11 | 12 | def draw_plate_on_image(img, box): 13 | x1, y1, x2, y2 = box 14 | h, w, _ = img.shape 15 | img_crop = img[y1:y2, x1:x2].copy() 16 | cv2.rectangle(img, (max(0, x1 - 5), max(0, y1 - 5)), (min(x2 + 5, 17 | w - 1), min(y2 + 5, h - 1)), (0, 255, 0), 5, cv2.LINE_AA) 18 | return img, img_crop 19 | 20 | 21 | def main(video_input: str, output_path: str): 22 | capture = cv2.VideoCapture(video_input) 23 | catcher = lpr3.LicensePlateCatcher(detect_level=lpr3.DETECT_LEVEL_HIGH) 24 | total_frames = int(capture.get(cv2.CAP_PROP_FRAME_COUNT)) 25 | video_fps = capture.get(cv2.CAP_PROP_FPS) 26 | 27 | box_id = 0 28 | result = {} 29 | 30 | for i in tqdm(range(total_frames), dynamic_ncols=True): 31 | ret, frame = capture.read() 32 | if not ret: 33 | break 34 | 35 | results = catcher(frame) 36 | 37 | for code, confidence, _, box in results: 38 | if (confidence < 0.85): 39 | continue 40 | 41 | if code not in result: 42 | result[code] = [] 43 | 44 | result[code].append({ 45 | 'frame_id': i, 46 | 'box_id': box_id, 47 | 'confidence': float(confidence), 48 | 'box': box 49 | }) 50 | 51 | img_boxed, img_crop = draw_plate_on_image(frame, box) 52 | 53 | cv2.imwrite(os.path.join( 54 | output_path, f"boxed/{box_id}.jpg"), img_boxed) 55 | cv2.imwrite(os.path.join( 56 | output_path, f"crop/{box_id}.jpg"), img_crop) 57 | 58 | box_id += 1 59 | 60 | with open(os.path.join(output_path, 'result.json'), 'w', encoding='utf-8') as f: 61 | json.dump({ 62 | 'total_frames': total_frames, 63 | 'video_fps': video_fps, 64 | 'total_boxes': box_id, 65 | 'result': result 66 | }, f, indent=None, ensure_ascii=False) 67 | 68 | 69 | if __name__ == '__main__': 70 | default_output_path = f'outputs/{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}' 71 | 72 | paser = argparse.ArgumentParser() 73 | paser.add_argument('--input_video', type=str, default='video/test.mp4') 74 | paser.add_argument('--output_path', type=str, default=default_output_path) 75 | paser.add_argument('--log_file', type=str, default=None) 76 | args = paser.parse_args() 77 | 78 | if not os.path.exists(args.output_path): 79 | os.makedirs(args.output_path) 80 | 81 | if not os.path.exists(os.path.join(args.output_path, 'boxed')): 82 | os.makedirs(os.path.join(args.output_path, 'boxed')) 83 | 84 | if not os.path.exists(os.path.join(args.output_path, 'crop')): 85 | os.makedirs(os.path.join(args.output_path, 'crop')) 86 | 87 | if args.log_file is not None: 88 | log_file = open(f"{args.output_path}/{args.log_file}", 89 | 'w', encoding='utf-8') 90 | sys.stdout = log_file 91 | sys.stderr = log_file 92 | 93 | main(args.input_video, args.output_path) 94 | 95 | if args.log_file is not None: 96 | log_file.close() 97 | --------------------------------------------------------------------------------