|
|
import os |
|
|
from matplotlib import pyplot as plt |
|
|
import skimage |
|
|
from skimage import io as skimage_io |
|
|
import numpy as np |
|
|
import re |
|
|
import cv2 |
|
|
|
|
|
|
|
|
def rescale_detection_box(boxes, image): |
|
|
h_img, w_img, _ = image.shape |
|
|
size = max(h_img, w_img) |
|
|
|
|
|
pad_h = size - h_img |
|
|
pad_w = size - w_img |
|
|
|
|
|
recovered_boxes = [] |
|
|
for box in boxes: |
|
|
cx, cy, w, h = box |
|
|
cx = cx * size |
|
|
cy = cy * size |
|
|
w = w * size |
|
|
h = h * size |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
x1 = cx - w / 2 |
|
|
y1 = cy - h / 2 |
|
|
x2 = cx + w / 2 |
|
|
y2 = cy + h / 2 |
|
|
recovered_boxes.append((x1, y1, x2, y2)) |
|
|
return recovered_boxes |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def read_images(image_dir): |
|
|
images = [] |
|
|
filenames = [p for p in os.listdir(image_dir) if os.path.splitext(p)[-1].lower() in [".png", ".jpg", ".jpeg",]] |
|
|
filenames.sort(key=lambda p: os.path.splitext(p)[0]) |
|
|
for filename in filenames: |
|
|
file_path = os.path.join(image_dir, filename) |
|
|
image_uint8 = skimage_io.imread(file_path) |
|
|
image = image_uint8.astype(np.float32) / 255.0 |
|
|
images.append(image) |
|
|
return images, filenames |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def preprocess_images(images, model_input_size): |
|
|
processed_images = [] |
|
|
for image in images: |
|
|
|
|
|
h, w, d = image.shape |
|
|
size = max(h, w) |
|
|
image_padded = np.pad(image, ((0, size - h), (0, size - w), (0, 0)), constant_values=0.5) |
|
|
|
|
|
image_resized = skimage.transform.resize( |
|
|
image_padded, |
|
|
(model_input_size, model_input_size), |
|
|
anti_aliasing=True, |
|
|
) |
|
|
processed_images.append(image_resized) |
|
|
|
|
|
return np.array(processed_images, dtype=np.float32) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def too_small(bbox, threshold=400): |
|
|
x1, y1, x2, y2 = bbox |
|
|
width = max(0, x2 - x1) |
|
|
height = max(0, y2 - y1) |
|
|
area = width * height |
|
|
|
|
|
return area < threshold |
|
|
|
|
|
|
|
|
def too_large(bbox, image, threshold=0.9): |
|
|
x1, y1, x2, y2 = bbox |
|
|
|
|
|
bbox_width = x2 - x1 |
|
|
bbox_height = y2 - y1 |
|
|
bbox_area = bbox_width * bbox_height |
|
|
|
|
|
image_height, image_width = image.shape[:2] |
|
|
image_area = image_width * image_height |
|
|
|
|
|
area_ratio = bbox_area / image_area |
|
|
return area_ratio >= threshold |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def plot_bboxes_on_orig_image(image, boxes, output_path): |
|
|
plt.clf() |
|
|
plt.imshow(image) |
|
|
plt.axis('off') |
|
|
|
|
|
for box in boxes: |
|
|
x1, y1, x2, y2 = box |
|
|
plt.plot( |
|
|
[x1, x2, x2, x1, x1], |
|
|
[y1, y1, y2, y2, y1], |
|
|
linewidth=0.8, alpha=0.6 |
|
|
) |
|
|
|
|
|
plt.savefig(output_path, bbox_inches='tight', pad_inches=0.1, dpi=300) |
|
|
plt.close() |
|
|
print(f" Done! Visualization saved to {output_path}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def compute_iou(box1, box2): |
|
|
x1_inter = max(box1[0], box2[0]) |
|
|
y1_inter = max(box1[1], box2[1]) |
|
|
x2_inter = min(box1[2], box2[2]) |
|
|
y2_inter = min(box1[3], box2[3]) |
|
|
inter_width = max(0, x2_inter - x1_inter) |
|
|
inter_height = max(0, y2_inter - y1_inter) |
|
|
inter_area = inter_width * inter_height |
|
|
box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1]) |
|
|
box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1]) |
|
|
union_area = box1_area + box2_area - inter_area |
|
|
return inter_area / union_area if union_area > 0 else 0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def remove_overlapping_bboxes(bboxes, iou_threshold=0.7): |
|
|
if not bboxes: |
|
|
return [] |
|
|
bboxes = sorted(bboxes, key=lambda x: (x[2] - x[0]) * (x[3] - x[1]), reverse=True) |
|
|
keep = [] |
|
|
for bbox in bboxes: |
|
|
should_keep = True |
|
|
for kept_bbox in keep: |
|
|
if compute_iou(bbox, kept_bbox) > iou_threshold: |
|
|
should_keep = False |
|
|
break |
|
|
if should_keep: |
|
|
keep.append(bbox) |
|
|
return keep |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_centroid(bbox): |
|
|
x1, y1, x2, y2 = bbox |
|
|
cx = (x1 + x2) / 2 |
|
|
cy = (y1 + y2) / 2 |
|
|
return (int(cx), int(cy)) |