goat / Scripts /eval_edge_refine.py
LightChuan's picture
Upload folder using huggingface_hub
6a5bb7e verified
Raw
History Blame Contribute Delete
6.46 kB
"""Edge-Guided Bbox Refinement
================================
For each box edge, scan outward and find the image gradient peak.
More constrained than Snake, less likely to drift to wrong edges.
CPU-only, 0 training.
"""
import sys, os
import numpy as np
import cv2
from PIL import Image
from tqdm import tqdm
PROJECT_DIR = '/home/user/goat'
os.chdir(PROJECT_DIR)
sys.path.insert(0, PROJECT_DIR)
from ultralytics import YOLO
def refine_edge(gray, x1, y1, x2, y2, edge, scan_range=10):
"""Refine one edge of a bbox using gradient search.
edge: 'left', 'right', 'top', 'bottom'
Returns: adjusted coordinate
"""
h, w = gray.shape
best_pos = None
best_grad = 0
if edge == 'left':
x_center = int(x1)
for dx in range(-scan_range, scan_range + 1):
new_x = int(x1 + dx)
if new_x < 1 or new_x > w - 2:
continue
# Gradient along vertical strip at new_x
strip = gray[max(0, int(y1)):min(h, int(y2)), new_x]
if len(strip) < 3:
continue
grad = np.abs(np.diff(strip)).mean()
if grad > best_grad:
best_grad = grad
best_pos = new_x
return best_pos if best_pos is not None else x1
elif edge == 'right':
x_center = int(x2)
for dx in range(-scan_range, scan_range + 1):
new_x = int(x2 + dx)
if new_x < 1 or new_x > w - 2:
continue
strip = gray[max(0, int(y1)):min(h, int(y2)), new_x]
if len(strip) < 3:
continue
grad = np.abs(np.diff(strip)).mean()
if grad > best_grad:
best_grad = grad
best_pos = new_x
return best_pos if best_pos is not None else x2
elif edge == 'top':
y_center = int(y1)
for dy in range(-scan_range, scan_range + 1):
new_y = int(y1 + dy)
if new_y < 1 or new_y > h - 2:
continue
strip = gray[new_y, max(0, int(x1)):min(w, int(x2))]
if len(strip) < 3:
continue
grad = np.abs(np.diff(strip)).mean()
if grad > best_grad:
best_grad = grad
best_pos = new_y
return best_pos if best_pos is not None else y1
elif edge == 'bottom':
y_center = int(y2)
for dy in range(-scan_range, scan_range + 1):
new_y = int(y2 + dy)
if new_y < 1 or new_y > h - 2:
continue
strip = gray[new_y, max(0, int(x1)):min(w, int(x2))]
if len(strip) < 3:
continue
grad = np.abs(np.diff(strip)).mean()
if grad > best_grad:
best_grad = grad
best_pos = new_y
return best_pos if best_pos is not None else y2
return x1 if edge in ('left', 'right') else y1
def refine_box(img_gray, box, scan_range=8):
"""Refine all 4 edges of a box using gradient search."""
x1, y1, x2, y2 = box
w, h = x2 - x1, y2 - y1
if w < 10 or h < 10:
return box
new_x1 = refine_edge(img_gray, x1, y1, x2, y2, 'left', scan_range)
new_x2 = refine_edge(img_gray, x1, y1, x2, y2, 'right', scan_range)
new_y1 = refine_edge(img_gray, x1, y1, x2, y2, 'top', scan_range)
new_y2 = refine_edge(img_gray, x1, y1, x2, y2, 'bottom', scan_range)
# Constrain: don't let the box shrink too much
min_w, min_h = w * 0.5, h * 0.5
max_w, max_h = w * 1.5, h * 1.5
if new_x2 - new_x1 < min_w:
mid = (new_x1 + new_x2) / 2
new_x1 = mid - min_w / 2
new_x2 = mid + min_w / 2
if new_y2 - new_y1 < min_h:
mid = (new_y1 + new_y2) / 2
new_y1 = mid - min_h / 2
new_y2 = mid + min_h / 2
if new_x2 - new_x1 > max_w:
mid = (new_x1 + new_x2) / 2
new_x1 = mid - max_w / 2
new_x2 = mid + max_w / 2
if new_y2 - new_y1 > max_h:
mid = (new_y1 + new_y2) / 2
new_y1 = mid - max_h / 2
new_y2 = mid + max_h / 2
return np.array([new_x1, new_y1, new_x2, new_y2])
def compute_iou(b1, b2):
x1, y1 = max(b1[0], b2[0]), max(b1[1], b2[1])
x2, y2 = min(b1[2], b2[2]), min(b1[3], b2[3])
inter = max(0, x2-x1) * max(0, y2-y1)
a1 = (b1[2]-b1[0])*(b1[3]-b1[1])
a2 = (b2[2]-b2[0])*(b2[3]-b2[1])
return inter/(a1+a2-inter+1e-8)
def main():
model = YOLO('runs/detect/Detection_experiments/v6_1_s_refined/weights/best.pt')
val_img_dir = 'Data/Detection_dataset/images/val'
val_label_dir = 'Data/Detection_dataset/labels/val'
val_files = sorted([f for f in os.listdir(val_img_dir) if f.endswith('.jpg')])
# Quick test on 5 images
test_files = val_files[:5]
improved, degraded, total = 0, 0, 0
print('Edge-Guided Refinement test:')
for img_file in test_files:
img_path = os.path.join(val_img_dir, img_file)
img = Image.open(img_path)
gray = np.array(img.convert('L'), dtype=float)
r = model.predict(img, imgsz=1536, conf=0.25, verbose=False)
if not r or len(r[0].boxes) == 0:
continue
boxes = r[0].boxes.xyxy.cpu().numpy()
# GT
lf = img_file.replace('.jpg', '.txt')
gt_boxes = []
with open(os.path.join(val_label_dir, lf)) as f:
for line in f:
p = line.strip().split()
if len(p) >= 5:
cx,cy,w,h = [float(x) for x in p[1:5]]
gt_boxes.append([(cx-w/2)*img.size[0], (cy-h/2)*img.size[1], (cx+w/2)*img.size[0], (cy+h/2)*img.size[1]])
for box in boxes[:10]:
refined = refine_box(gray, box)
total += 1
best_orig = max(compute_iou(box, gt) for gt in gt_boxes) if gt_boxes else 0
best_ref = max(compute_iou(refined, gt) for gt in gt_boxes) if gt_boxes else 0
if best_ref > best_orig + 0.005:
improved += 1
elif best_ref < best_orig - 0.005:
degraded += 1
print(f' Improved: {improved}/{total} ({improved/total*100:.0f}%)')
print(f' Degraded: {degraded}/{total} ({degraded/total*100:.0f}%)')
print(f' Unchanged: {total-improved-degraded}/{total}')
if improved > degraded:
print(' Edge refinement LOOKS PROMISING!')
else:
print(' Edge refinement not clearly beneficial')
if __name__ == '__main__':
main()