Rysunek 1 Linia przenośnikowa na Made In Wrocław 2025

Kod źródłowy projektu (system wizyjny).

Linia w akcji.

W projekcie „Linia przenośnikowa” jednym z kluczowych elementów jest system wizyjny – „oczy” całej instalacji. Jego zadaniem jest wykrywanie okrągłych elementów (krążków / podkładek) na taśmie oraz rozpoznanie ich koloru. Na tej podstawie reszta systemu (sterowanie, sortowanie, statystyki) podejmuje decyzje, co dalej zrobić z danym elementem.

System został napisany w Pythonie z użyciem biblioteki OpenCV i pracuje przy dedykowanym oświetleniu LED zamontowanym nad taśmą. Stałe, kontrolowane światło z LED-ów znacząco poprawia powtarzalność pomiarów i stabilność klasyfikacji kolorów.

Jak wygląda pipeline wizyjny?

W uproszczeniu, dla każdej klatki z kamery robimy:

  1. Pobranie obrazu z kamery,
  2. Wykrycie okrągłych elementów (krążków) – algorytm Hougha dla okręgów,
  3. Odfiltrowanie duplikatów i elementów spoza interesującego nas obszaru taśmy,
  4. Dla każdego wykrytego okręgu:
    • analiza kolorów w jego wnętrzu (HSV),
    • decyzja, jaki to kolor,
    • zapisanie wyniku,
    • inkrementacja statystyk.

Na końcu funkcja detect_circles(…) zwraca listę słowników takich jak:
{„x”: a, „y”: b, „r”: r, „color”: „zielony”, „hsv”: [H, S, V]}
To gotowa informacja dla reszty systemu sterowania linii.

Hardware: kamera + oświetlenie LED

Rysunek 2 Linia przenośnikowa na DAS 2025

Aby system wizyjny działał stabilnie, potrzebuje nie tylko dobrego algorytmu, ale też powtarzalnych warunków oświetleniowych. W naszym projekcie nad taśmą zamontowaliśmy pasek / moduły LED o stałej temperaturze barwowej, skierowany na obszar roboczy kamery (ROI). Dzięki temu:

  • redukujemy zmiany jasności wynikające z oświetlenia hali,
  • kolory są bardziej przewidywalne w przestrzeni HSV,
  • możemy stosować stałe progi do klasyfikacji barw. Nawet najlepszy algorytm będzie się gubił, jeśli scena raz jest bardzo ciemna, a raz prześwietlona, więc stabilne LED-y są kluczowym elementem całego systemu.
Rysunek 3 Montaż ledów

Wykrywanie okręgów – HoughCircles w praktyce

Rysunek 4 Widok z kamery

Pierwszy krok po pobraniu klatki to przygotowanie obrazu. Najpierw konwersja do skali szarości, potem filtr medianowy:

gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
gray = cv.medianBlur(gray, 5)

Następnie używamy funkcji

cv.HoughCircles do wykrycia okręgów na podstawie krawędzi:

detected_circles = cv.HoughCircles(
    gray,
    cv.HOUGH_GRADIENT,
    dp=1,
    minDist=CIRCLE_MIN_RADIUS * 2,
    param1=param1,
    param2=param2,
    minRadius=CIRCLE_MIN_RADIUS,
    maxRadius=CIRCLE_MAX_RADIUS,
)

Krótko o parametrach:

  • dp – skala akumulatora względem obrazu; 1 oznacza pełną rozdzielczość (dokładniej, wolniej)
  • minDist – minimalna odległość między środkami wykrytych okręgów (eliminuje duplikaty)
  • param1 – górny próg dla detektora krawędzi Canny (ile krawędzi widzimy)
  • param2 – próg akumulatora
  • minRadius / maxRadius – zakres promieni okręgów odpowiadających naszym fizycznym elementom na taśmie

Po wykryciu okręgów sortujemy je od największego promienia do najmniejszego i eliminujemy te, które leżą wewnątrz już zaakceptowanych większych okręgów. Dodatkowo filtrujemy po prostokątnym obszarze interesu (ROI) określonym przez FRAME_LEFT_MARGIN, FRAME_TOP_MARGIN, FRAME_WIDTH i FRAME_HEIGHT – dzięki temu ignorujemy elementy spoza taśmy.

Za klasyfikację kolorów odpowiada funkcja get_circle_color_info(a, b, r, frame). Pierwszy krok to przejście z BGR do HSV:

hsv_frame = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

HSV (Hue, Saturation, Value) dzieli kolor na odcień (H), nasycenie (S) i jasność (V). W tej przestrzeni dużo łatwiej jest zdefiniować „czerwony”, „zielony” czy „niebieski” jako zakresy wartości H.

Następnie przechodzimy po pikselach znajdujących się wewnątrz okręgu i zliczamy średnie HSV oraz wszystkie wartości H:

average = np.array([0.0, 0.0, 0.0])
count = 0
hue_list = []
for y in range(b - floor(r), b + floor(r)):
    for x in range(a - floor(r), a + floor(r)):
        if 0 <= y < hsv_frame.shape[0] and 0 <= x < hsv_frame.shape[1]:
            if (x - a) ** 2 + (y - b) ** 2 <= r**2:
                average += hsv_frame[y, x, :]
                count += 1
                hue_list.append(hsv_frame[y, x, 0])

Jeśli zebraliśmy jakiekolwiek piksele, dzielimy średnią przez count, a następnie bierzemy najczęściej występującą wartość H jako reprezentatywny odcień dla całego okręgu:

if count > 0:
    average /= count
if hue_list:
    hue_value = int(np.bincount(np.array(hue_list, dtype=np.uint8)).argmax())
else:
    hue_value = 0
average[0] = hue_value

Zastosowanie najczęściej występującego odcienia (a nie średniej H) ogranicza wpływ pojedynczych, zaszumionych pikseli.

Mapowanie HSV → nazwa koloru

Rysunek 5 Okrąg kolorów HSV

Na podstawie hue_value oraz jasności i nasycenia wybieramy nazwę koloru. W kodzie wygląda to następująco:

if average[2] < 80 or (average[2] < 150 and average[1] < 100):
    color = "czarny"
elif hue_value < 7.5:
    color = "czerwony"
elif hue_value < 19:
    color = "pomaranczowy"
elif hue_value < 35:
    color = "zolty"
elif hue_value < 80:
    color = "zielony"
elif hue_value < 122.5:
    color = "niebieski"
elif hue_value < 140:
    color = "fioletowy"
elif hue_value < 162.5:
    color = "rozowy"
else:
    color = "czerwony"

Progi zostały dobrane eksperymentalnie pod konkretne elementy i warunki oświetleniowe na linii. Czerń rozpoznajemy głównie po niskiej jasności (V) i niskim nasyceniu (S), a pozostałe kolory na podstawie zakresów H.

Integracja z resztą systemu

System wizyjny nie działa w próżni – wyniki z detect_circles(…) są dalej wykorzystywane m.in. do sterowania elementami wykonawczymi (siłowniki, sortowniki, wyrzutniki), synchronizacji z położeniem na taśmie, wyświetlania podglądu na aplikacji webowej oraz logowania zdarzeń.

Dla każdej klatki mamy zestaw obiektów z pozycją (x, y), promieniem r i pewnym kolorem, na podstawie którego reszta systemu podejmuje decyzje. System wizyjny nie działa w próżni – wyniki z detect_circles(…) są dalej wykorzystywane m.in. do sterowania elementami wykonawczymi (siłowniki, sortowniki, wyrzutniki), synchronizacji z położeniem na taśmie, wyświetlania podglądu na aplikacji webowej oraz logowania zdarzeń.

Dla każdej klatki mamy zestaw obiektów z pozycją (x, y), promieniem r i pewnym kolorem, na podstawie którego reszta systemu podejmuje decyzje.

Co dalej?

Rozwinięcia systemu wizyjnego, nad którymi można pracować w ramach koła, obejmują m.in.:

  • wykrywanie innych kształtów (np. prostokątnych etykiet),
  • integrację z sieciami neuronowymi (CNN) do bardziej złożonych zadań.

System wizyjny z projektu linii przenośnikowej pokazuje, że relatywnie prostymi metodami (Hough + HSV) można zbudować stabilne, działające w czasie rzeczywistym rozwiązanie, które realnie współpracuje z automatyką przemysłową w warunkach koła naukowego.

Autor: Marvin Ruciński

Kategorie: Aktualności

0 komentarzy

Dodaj komentarz

Symbol zastępczy awatara

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *