Hardi Kurnianto
Published

Computer Vision for Multi-Core Fiber Alignment

Automating multi-core optical fiber alignment inspection using computer vision for faster, more accurate quality control

IntermediateShowcase (no instructions)5 hours4
Computer Vision for Multi-Core Fiber Alignment

Things used in this project

Software apps and online services

VS Code
Microsoft VS Code

Story

Read more

Code

Visual Code

Python
import cv2
import numpy as np
import math

# Video capture (ganti ke 0 untuk webcam)
cap = cv2.VideoCapture('MCF_sample.mp4')

# Cek ukuran frame video
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(cap.get(cv2.CAP_PROP_FPS))

# Video writer untuk simpan hasil
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output_result.mp4', fourcc, fps, (frame_width, frame_height))

# Data referensi (x, y, r)
reference_data = {
    'Core 1': (157, 275, 17),
    'Core 2': (280, 157, 17),
    'Core 3': (277, 397, 18),
    'Core 4': (401, 278, 19),
    'Marker C': (401, 105, 15)
}

kecepatan_derajat_per_detik = 180

while cap.isOpened():
    ret, img = cap.read()
    if not ret:
        break

    output = img.copy()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray_blur = cv2.GaussianBlur(gray, (9, 9), 2)

    circles = cv2.HoughCircles(
        gray_blur,
        cv2.HOUGH_GRADIENT,
        dp=1.2,
        minDist=40,
        param1=50,
        param2=30,
        minRadius=10,
        maxRadius=30
    )

    center_x, center_y = img.shape[1] // 2, img.shape[0] // 2

    if circles is not None:
        circles = np.uint16(np.around(circles))
        circle_list = []

        for i in circles[0, :]:
            x, y, r = i[0], i[1], i[2]
            distance = math.hypot(x - center_x, y - center_y)
            circle_list.append((x, y, r, distance))

            cv2.circle(output, (x, y), r, (0, 255, 0), 2)
            cv2.circle(output, (x, y), 2, (0, 0, 255), 3)

        circle_list.sort(key=lambda x: x[3])

        labels = ['Core 1', 'Core 2', 'Core 3', 'Core 4', 'Marker C']

        selisih_sudut_total = 0
        jumlah_sudut = 0

        for idx, (x, y, r, d) in enumerate(circle_list):
            label = labels[idx] if idx < len(labels) else f'Unknown {idx}'

            if label in reference_data:
                ref_x, ref_y, ref_r = reference_data[label]
                diff_x = x - ref_x
                diff_y = y - ref_y
                diff_r = r - ref_r

                theta_ref = math.degrees(math.atan2(ref_y - center_y, ref_x - center_x))
                theta_now = math.degrees(math.atan2(y - center_y, x - center_x))
                selisih_sudut = theta_now - theta_ref

                if selisih_sudut > 180:
                    selisih_sudut -= 360
                elif selisih_sudut < -180:
                    selisih_sudut += 360

                selisih_sudut_total += selisih_sudut
                jumlah_sudut += 1

                cv2.putText(output, label, (x-40, y-30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)

        if jumlah_sudut > 0:
            rata2_selisih_sudut = selisih_sudut_total / jumlah_sudut

            if rata2_selisih_sudut > 0:
                arah = 'CW'
            elif rata2_selisih_sudut < 0:
                arah = 'CCW'
            else:
                arah = 'OK'

            waktu_rotasi_detik = abs(rata2_selisih_sudut) / kecepatan_derajat_per_detik

            rekom_text_y = img.shape[0] - 20
            text = f"{rata2_selisih_sudut:.2f} deg | {arah} | {waktu_rotasi_detik:.3f} s "
            font = cv2.FONT_HERSHEY_SIMPLEX
            font_scale = 0.5
            thickness = 1
            (text_width, text_height), _ = cv2.getTextSize(text, font, font_scale, thickness)
            rekom_text_x = (img.shape[1] - text_width) // 2
            cv2.putText(output, text, (rekom_text_x, rekom_text_y), font, font_scale, (255, 255, 255), thickness)

    # Tampilkan hasil
    cv2.imshow("MCF Detector Video", output)

    # Simpan ke video
    out.write(output)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Release semuanya
cap.release()
out.release()
cv2.destroyAllWindows()

Credits

Hardi Kurnianto
20 projects • 18 followers
Master student at Intelligent Control and Systems Engineering Department

Comments