208 lines
8.6 KiB
Python
208 lines
8.6 KiB
Python
import cv2
|
|
import os
|
|
import json
|
|
import numpy as np
|
|
|
|
# State constants
|
|
STATE_TRUCK = 0
|
|
STATE_DETECTION = 1
|
|
STATE_LINE = 2
|
|
STATE_DONE = 3
|
|
|
|
state = STATE_TRUCK
|
|
points_truck = []
|
|
points_detection = []
|
|
points_line = []
|
|
|
|
def click_event(event, x, y, flags, params):
|
|
global state
|
|
if event == cv2.EVENT_LBUTTONDOWN:
|
|
if state == STATE_TRUCK:
|
|
points_truck.append([x, y])
|
|
print(f"Truck Area - Point {len(points_truck)}: [{x}, {y}]")
|
|
if len(points_truck) == 4:
|
|
state = STATE_DETECTION
|
|
print("\n-> Area Truk Berhasil Dipilih (4 titik).")
|
|
print("-> SILAHKAN PILIH AREA DETEKSI (Klik Kiri 4 Titik secara berurutan: Top-Left, Top-Right, Bottom-Right, Bottom-Left).")
|
|
elif state == STATE_DETECTION:
|
|
points_detection.append([x, y])
|
|
print(f"Detection Area - Point {len(points_detection)}: [{x}, {y}]")
|
|
if len(points_detection) == 4:
|
|
state = STATE_LINE
|
|
print("\n-> Area Deteksi Berhasil Dipilih (4 titik).")
|
|
print("-> SILAHKAN PILIH COUNT LINE (Klik Kiri Titik Mulai dan Titik Selesai).")
|
|
elif state == STATE_LINE:
|
|
points_line.append([x, y])
|
|
print(f"Count Line - Point {len(points_line)}: [{x}, {y}]")
|
|
if len(points_line) == 2:
|
|
state = STATE_DONE
|
|
print("\n-> Count Line Berhasil Dipilih.")
|
|
print("-> Semua koordinat telah lengkap! Tekan 's' untuk mencetak & menyimpan koordinat.")
|
|
|
|
draw_frame()
|
|
|
|
def draw_frame():
|
|
img_copy = img.copy()
|
|
h, w, _ = img_copy.shape
|
|
|
|
# 1. Draw Area Truk (Orange Polygon)
|
|
for pt in points_truck:
|
|
cv2.circle(img_copy, tuple(pt), 5, (0, 165, 255), -1)
|
|
if len(points_truck) == 4:
|
|
pts = np.array(points_truck, np.int32)
|
|
cv2.polylines(img_copy, [pts], True, (0, 165, 255), 2)
|
|
cv2.putText(img_copy, "TRUCK AREA", tuple(points_truck[0]),
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 165, 255), 1)
|
|
|
|
# 2. Draw Area Deteksi (Cyan Polygon)
|
|
for pt in points_detection:
|
|
cv2.circle(img_copy, tuple(pt), 5, (255, 255, 0), -1)
|
|
if len(points_detection) == 4:
|
|
pts = np.array(points_detection, np.int32)
|
|
cv2.polylines(img_copy, [pts], True, (255, 255, 0), 2)
|
|
cv2.putText(img_copy, "DETECTION AREA", tuple(points_detection[0]),
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 1)
|
|
|
|
# 3. Draw Count Line (Magenta Line)
|
|
if len(points_line) > 0:
|
|
cv2.circle(img_copy, tuple(points_line[0]), 5, (255, 0, 255), -1)
|
|
if len(points_line) == 2:
|
|
cv2.line(img_copy, tuple(points_line[0]), tuple(points_line[1]), (255, 0, 255), 3)
|
|
# Draw midpoint circle
|
|
mid_x = int((points_line[0][0] + points_line[1][0]) / 2)
|
|
mid_y = int((points_line[0][1] + points_line[1][1]) / 2)
|
|
cv2.circle(img_copy, (mid_x, mid_y), 6, (0, 255, 0), -1)
|
|
cv2.putText(img_copy, f"LINE (y={mid_y})", (mid_x + 10, mid_y - 10),
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 255), 1)
|
|
|
|
# Draw Instruction Overlay on Top
|
|
overlay_y = 35
|
|
if state == STATE_TRUCK:
|
|
txt = f"1. PILIH AREA TRUK (Klik Kiri 4 Titik, saat ini: {len(points_truck)}/4)"
|
|
color = (0, 165, 255)
|
|
elif state == STATE_DETECTION:
|
|
txt = f"2. PILIH AREA DETEKSI (Klik Kiri 4 Titik, saat ini: {len(points_detection)}/4)"
|
|
color = (255, 255, 0)
|
|
elif state == STATE_LINE:
|
|
txt = f"3. PILIH COUNT LINE (Klik Kiri Titik Awal lalu Titik Akhir, saat ini: {len(points_line)}/2)"
|
|
color = (255, 0, 255)
|
|
else:
|
|
txt = "SELESAI! Tekan 's' untuk simpan atau 'c' untuk ulang."
|
|
color = (0, 255, 0)
|
|
|
|
# Draw background panel for text
|
|
cv2.rectangle(img_copy, (10, 10), (w - 10, 50), (0, 0, 0), -1)
|
|
cv2.putText(img_copy, txt, (20, overlay_y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
|
|
|
|
cv2.imshow('Interactive 4-Point Zone Selector', img_copy)
|
|
|
|
if __name__ == "__main__":
|
|
source_img = "gambar_terbaru.jpg" if os.path.exists("gambar_terbaru.jpg") else "calib_frame.jpg"
|
|
video_source = "0727.mp4"
|
|
|
|
if os.path.exists(source_img):
|
|
img = cv2.imread(source_img)
|
|
print(f"Loaded image: {source_img}")
|
|
elif os.path.exists(video_source):
|
|
print(f"Grabbing frame from video: {video_source}")
|
|
cap = cv2.VideoCapture(video_source)
|
|
for _ in range(10):
|
|
ret, img = cap.read()
|
|
cap.release()
|
|
if not ret:
|
|
print("Error: Could not grab frame from video.")
|
|
exit(1)
|
|
else:
|
|
print("Error: Neither calib_frame.jpg nor the video file exists.")
|
|
exit(1)
|
|
|
|
cv2.namedWindow('Interactive 4-Point Zone Selector')
|
|
cv2.setMouseCallback('Interactive 4-Point Zone Selector', click_event)
|
|
|
|
print("\n=== OpenCV 4-Point Zone Coordinate Selector ===")
|
|
print("Instructions:")
|
|
print("1. Left-click to select coordinates for each step.")
|
|
print("2. Press 'c' at any time to clear selection and restart.")
|
|
print("3. Press 's' when done to print python snippets and save to zones_output.json.")
|
|
print("4. Press 'q' or 'ESC' to quit.")
|
|
print("========================================\n")
|
|
print("-> SILAHKAN PILIH AREA TRUK (Klik Kiri 4 Titik secara berurutan: Top-Left, Top-Right, Bottom-Right, Bottom-Left).")
|
|
|
|
draw_frame()
|
|
|
|
while True:
|
|
key = cv2.waitKey(1) & 0xFF
|
|
if key == ord('c') or key == ord('C'):
|
|
state = STATE_TRUCK
|
|
points_truck = []
|
|
points_detection = []
|
|
points_line = []
|
|
print("\nCleared selection. Restarting from Step 1 (Area Truk)...")
|
|
draw_frame()
|
|
elif key == ord('s') or key == ord('S'):
|
|
if state != STATE_DONE:
|
|
print(f"Warning: Harap selesaikan semua langkah terlebih dahulu. State saat ini: {state}")
|
|
continue
|
|
|
|
lx1, ly1 = points_line[0]
|
|
lx2, ly2 = points_line[1]
|
|
line_y_avg = int((ly1 + ly2) / 2)
|
|
|
|
output_data = {
|
|
"truck_poly": points_truck,
|
|
"detection_poly": points_detection,
|
|
"count_line": {
|
|
"x_start": lx1, "x_end": lx2, "y": line_y_avg
|
|
}
|
|
}
|
|
|
|
# Print configuration code snippets
|
|
print("\n" + "="*50)
|
|
print("KOORDINAT BERHASIL DI-GENERATE!")
|
|
print("="*50)
|
|
print("\n--- SALIN KODE DI BAWAH INI KE predict.py ---\n")
|
|
print(f" # 1. Detection Area (4-point Polygon)")
|
|
print(f" detection_poly_pts = [")
|
|
for pt in points_detection:
|
|
print(f" [int({pt[0]} * scale_x), int({pt[1]} * scale_y)],")
|
|
print(f" ]")
|
|
print(f" detection_polygon = Polygon(detection_poly_pts)")
|
|
print()
|
|
print(f" # 2. Count Line coordinates")
|
|
print(f" static_line_y = int({line_y_avg} * scale_y)")
|
|
print(f" static_line_x_start = int({lx1} * scale_x)")
|
|
print(f" static_line_x_end = int({lx2} * scale_x)")
|
|
print()
|
|
print(f" # 3. Truck Area (4-point Polygon for presence check)")
|
|
print(f" truck_poly_pts = [")
|
|
for pt in points_truck:
|
|
print(f" [int({pt[0]} * scale_x), int({pt[1]} * scale_y)],")
|
|
print(f" ]")
|
|
print(f" truck_polygon = Polygon(truck_poly_pts)")
|
|
print()
|
|
|
|
# Calculate bounding box of truck_polygon to maintain backward compatibility with static_roi
|
|
tx_coords = [p[0] for p in points_truck]
|
|
ty_coords = [p[1] for p in points_truck]
|
|
min_tx, max_tx = min(tx_coords), max(tx_coords)
|
|
min_ty, max_ty = min(ty_coords), max(ty_coords)
|
|
print(f" static_roi = TruckROI(")
|
|
print(f" x1=int({min_tx} * scale_x),")
|
|
print(f" y1=int({min_ty} * scale_y),")
|
|
print(f" x2=int({max_tx} * scale_x),")
|
|
print(f" y2=int({max_ty} * scale_y),")
|
|
print(f" line_y=static_line_y,")
|
|
print(f" confidence=1.0")
|
|
print(f" )")
|
|
print("\n" + "="*50)
|
|
|
|
# Save to json file
|
|
with open("zones_output.json", "w") as f:
|
|
json.dump(output_data, f, indent=4)
|
|
print("Koordinat juga telah disimpan ke 'zones_output.json'\n")
|
|
|
|
elif key == ord('q') or key == 27:
|
|
break
|
|
|
|
cv2.destroyAllWindows()
|