| import cv2 |
| import os |
| import yaml |
| import numpy as np |
|
|
| |
| DATASET_BASE_DIR = "dataset" |
| DATA_YAML_PATH = os.path.join(DATASET_BASE_DIR, "data.yaml") |
| SPLIT_TO_VIEW = "train" |
|
|
| IMAGE_DIR = os.path.join(DATASET_BASE_DIR, SPLIT_TO_VIEW, "images") |
| LABEL_DIR = os.path.join(DATASET_BASE_DIR, SPLIT_TO_VIEW, "labels") |
|
|
| |
| DEFAULT_MAX_WIDTH = 1280 |
| DEFAULT_MAX_HEIGHT = 720 |
| DEFAULT_SCALE_FACTOR = 1.0 |
|
|
| |
| try: |
| with open(DATA_YAML_PATH, "r") as f: |
| data_yaml = yaml.safe_load(f) |
| CLASS_NAMES = data_yaml["names"] |
| print(f"Found these classes: {CLASS_NAMES}") |
| except Exception as e: |
| print(f"Couldn't read the class names from {DATA_YAML_PATH}: {e}") |
| CLASS_NAMES = None |
|
|
|
|
| |
| def visualize_yolo_annotations(image_dir, label_dir, class_names): |
| image_files = sorted( |
| [ |
| f |
| for f in os.listdir(image_dir) |
| if f.lower().endswith((".png", ".jpg", ".jpeg")) |
| ] |
| ) |
| num_images = len(image_files) |
| current_index = 0 |
| scale_factor = DEFAULT_SCALE_FACTOR |
|
|
| |
| window_name = "YOLO Annotations - n:next p:prev q:quit +/-:zoom r:reset" |
| cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) |
|
|
| while True: |
| if current_index < 0: |
| current_index = 0 |
| if current_index >= num_images: |
| current_index = num_images - 1 |
|
|
| img_filename = image_files[current_index] |
| img_path = os.path.join(image_dir, img_filename) |
| label_filename = os.path.splitext(img_filename)[0] + ".txt" |
| label_path = os.path.join(label_dir, label_filename) |
|
|
| |
| image = cv2.imread(img_path) |
| if image is None: |
| print(f"Can't load this image: {img_path}") |
| key = cv2.waitKey(0) |
| if key == ord("q"): |
| break |
| elif key == ord("n"): |
| current_index += 1 |
| continue |
| elif key == ord("p"): |
| current_index -= 1 |
| continue |
| else: |
| continue |
|
|
| orig_h, orig_w, _ = image.shape |
| vis_image = image.copy() |
|
|
| |
| if os.path.exists(label_path): |
| try: |
| with open(label_path, "r") as f: |
| for line in f: |
| parts = line.strip().split() |
| if len(parts) >= 5: |
| ( |
| class_id, |
| x_center_norm, |
| y_center_norm, |
| width_norm, |
| height_norm, |
| ) = map(float, parts[:5]) |
| class_id = int(class_id) |
|
|
| |
| box_w = width_norm * orig_w |
| box_h = height_norm * orig_h |
| center_x = x_center_norm * orig_w |
| center_y = y_center_norm * orig_h |
|
|
| x_min = int(center_x - (box_w / 2)) |
| y_min = int(center_y - (box_h / 2)) |
| x_max = int(center_x + (box_w / 2)) |
| y_max = int(center_y + (box_h / 2)) |
|
|
| |
| cv2.rectangle( |
| vis_image, |
| (x_min, y_min), |
| (x_max, y_max), |
| (0, 255, 0), |
| 2, |
| ) |
|
|
| |
| if class_names and 0 <= class_id < len(class_names): |
| label = class_names[class_id] |
| else: |
| label = f"Class_{class_id}" |
|
|
| |
| (text_width, text_height), baseline = cv2.getTextSize( |
| label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1 |
| ) |
| cv2.rectangle( |
| vis_image, |
| (x_min, y_min - text_height - baseline), |
| (x_min + text_width, y_min), |
| (0, 255, 0), |
| -1, |
| ) |
| cv2.putText( |
| vis_image, |
| label, |
| (x_min, y_min - baseline), |
| cv2.FONT_HERSHEY_SIMPLEX, |
| 0.5, |
| (0, 0, 0), |
| 1, |
| ) |
|
|
| except Exception as e: |
| print(f"Problem reading label file {label_path}: {e}") |
| else: |
| print(f"No label file for this image: {label_path}") |
|
|
| |
| display_text = f"{SPLIT_TO_VIEW}: {img_filename} ({current_index + 1}/{num_images}) - Scale: {scale_factor:.2f}x" |
| cv2.putText( |
| vis_image, |
| display_text, |
| (10, 25), |
| cv2.FONT_HERSHEY_SIMPLEX, |
| 0.7, |
| (0, 0, 255), |
| 2, |
| ) |
|
|
| |
| display_h, display_w = int(orig_h * scale_factor), int(orig_w * scale_factor) |
|
|
| |
| if display_w != orig_w or display_h != orig_h: |
| vis_image = cv2.resize( |
| vis_image, |
| (display_w, display_h), |
| interpolation=cv2.INTER_AREA if scale_factor < 1 else cv2.INTER_LINEAR, |
| ) |
|
|
| |
| window_w = min(display_w, DEFAULT_MAX_WIDTH) |
| window_h = min(display_h, DEFAULT_MAX_HEIGHT) |
| cv2.resizeWindow(window_name, window_w, window_h) |
|
|
| |
| cv2.imshow(window_name, vis_image) |
|
|
| |
| key = cv2.waitKey(0) |
| if key == ord("q"): |
| break |
| elif key == ord("n"): |
| current_index += 1 |
| elif key == ord("p"): |
| current_index -= 1 |
| elif key == ord("+") or key == ord("="): |
| scale_factor *= 1.2 |
| elif key == ord("-") or key == ord("_"): |
| scale_factor /= 1.2 |
| elif key == ord("r"): |
| scale_factor = DEFAULT_SCALE_FACTOR |
| elif key == 32: |
| if ( |
| cv2.getWindowProperty(window_name, cv2.WND_PROP_FULLSCREEN) |
| == cv2.WINDOW_FULLSCREEN |
| ): |
| cv2.setWindowProperty( |
| window_name, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_NORMAL |
| ) |
| else: |
| cv2.setWindowProperty( |
| window_name, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN |
| ) |
|
|
| cv2.destroyAllWindows() |
| print("All done viewing annotations!") |
|
|
|
|
| |
| if __name__ == "__main__": |
| if not os.path.exists(IMAGE_DIR) or not os.path.exists(LABEL_DIR): |
| print( |
| f"Can't find images or labels. Check these folders: {IMAGE_DIR} and {LABEL_DIR}" |
| ) |
| elif CLASS_NAMES is None: |
| print("No class names found. Make sure data.yaml exists and is formatted correctly.") |
| else: |
| visualize_yolo_annotations(IMAGE_DIR, LABEL_DIR, CLASS_NAMES) |
|
|