Skocz do zawartości

Open CV >> dopasowanie szablonu


Pomocna odpowiedź

Napisano

Witam !!

Poszukuję informacji, przykładowego programu, który na podstawie wgranego wzorca np czerwonego kwadratu znajdzie taki kwadrat w obrazie kamery i wrzuci informacje o współrzędnych znalezionego obiektu względem kamery 

Dobrze żeby to w było w pytonie 

Dziękuję i pozdrawiam !   

To co  daję Ci poniżej to odpowiedź czata, więc moja zasługa raczej niewielka, ale może przyda Ci się do dalszych przemyśleń i poszukiwań. (Wkleiłem Twoje Niczego nie sprawdzałem!, z moich doświadczeń z czatami, to dopiero początek długiej drogi.)

Jasne! Poniżej masz prosty, działający przykład w Pythonie z OpenCV: wykrywa czerwony kwadrat w strumieniu z kamery, wylicza pikselowe współrzędne środka względem środka obrazu, a opcjonalnie (jeśli podasz rzeczywisty bok kwadratu i ogniskową w pikselach) szacuje pozycję (X,Y,Z) w mm wobec kamery.

Plan (koncepcja)

  1. Przechwyć klatkę z kamery.

  2. Konwersja do HSV i progowanie na “czerwony” (dwa zakresy w HSV).

  3. Czyszczenie maski (morfologia), znajdź kontury.

  4. Z każdego konturu zrób aproksymację wielokąta; wybierz wypukłe, 4-wierzchołkowe z sensownym polem i proporcjami boków ~1:1.

  5. Wyznacz środek (centroid), kąt/rozmiar (minAreaRect).

  6. Zwróć:

    • offset w pikselach względem środka obrazu: Δx=xc−W/2, Δy=yc−H/2\Delta x = x_c - W/2,\ \Delta y = y_c - H/2Δx=xcW/2, Δy=ycH/2

    • (opcjonalnie) pozycję w mm:
      Z≈f⋅Sreal/SpxZ \approx f \cdot S_{\text{real}} / S_{\text{px}}ZfSreal/Spx,
      X≈Δx⋅Z/f, Y≈Δy⋅Z/fX \approx \Delta x \cdot Z / f,\ Y \approx \Delta y \cdot Z / fXΔxZ/f, YΔyZ/f


Minimalny działający przykład

 
 
# pip install opencv-python numpy
import cv2 as cv
import numpy as np
import argparse

def find_red_squares(frame):
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

    # Dwa zakresy czerwieni (wrap-around na H)
    lower1 = np.array([0, 100, 80])
    upper1 = np.array([10, 255, 255])
    lower2 = np.array([170, 100, 80])
    upper2 = np.array([180, 255, 255])

    mask1 = cv.inRange(hsv, lower1, upper1)
    mask2 = cv.inRange(hsv, lower2, upper2)
    mask = cv.bitwise_or(mask1, mask2)

    # Morfologia: usuń szum, wypełnij dziury
    kernel = np.ones((5,5), np.uint8)
    mask = cv.morphologyEx(mask, cv.MORPH_OPEN, kernel, iterations=1)
    mask = cv.morphologyEx(mask, cv.MORPH_CLOSE, kernel, iterations=2)

    contours, _ = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

    candidates = []
    for cnt in contours:
        area = cv.contourArea(cnt)
        if area < 800:  # ignoruj drobne śmieci – dostosuj do swojej sceny
            continue

        peri = cv.arcLength(cnt, True)
        approx = cv.approxPolyDP(cnt, 0.04 * peri, True)

        if len(approx) == 4 and cv.isContourConvex(approx):
            rect = cv.minAreaRect(approx)
            (cx, cy), (w, h), angle = rect
            if min(w, h) == 0:
                continue
            aspect = max(w, h) / min(w, h)
            if aspect < 1.2:  # ~kwadrat
                candidates.append((area, rect, approx))

    # zwróć największy kwadrat (najpewniejszy)
    if candidates:
        candidates.sort(key=lambda x: x[0], reverse=True)
        return candidates[0]  # (area, rect, approx)
    return None

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--cam", type=int, default=0, help="Index kamery")
    ap.add_argument("--square_mm", type=float, default=None,
                    help="Rzeczywisty bok kwadratu w mm (opcjonalnie)")
    ap.add_argument("--focal_px", type=float, default=None,
                    help="Ogniskowa w pikselach (opcjonalnie, do estymacji Z)")
    args = ap.parse_args()

    cap = cv.VideoCapture(args.cam)
    if not cap.isOpened():
        raise SystemExit("Nie można otworzyć kamery.")

    print("q – wyjście")
    while True:
        ok, frame = cap.read()
        if not ok:
            break

        H, W = frame.shape[:2]
        found = find_red_squares(frame)

        if found:
            area, rect, approx = found
            (cx, cy), (w, h), angle = rect
            # środek względem środka obrazu (piksele)
            dx = cx - W/2
            dy = cy - H/2

            # rysowanie
            box = cv.boxPoints(rect).astype(int)
            cv.drawContours(frame, [box], 0, (0,255,0), 2)
            cv.circle(frame, (int(cx), int(cy)), 5, (255,255,255), -1)
            cv.line(frame, (W//2, H//2), (int(cx), int(cy)), (255,0,0), 2)

            # metryka w px – przyjmij średni bok z minAreaRect
            side_px = (w + h) / 2.0

            info = f"center_px=({cx:.1f},{cy:.1f})  d(px)=({dx:+.1f},{dy:+.1f})  side_px={side_px:.1f}"
            if args.square_mm and args.focal_px:
                # Prosty model dziurki od szpilki (pinhole)
                Z = args.focal_px * args.square_mm / side_px  # mm
                X = dx * Z / args.focal_px
                Y = dy * Z / args.focal_px
                info += f"  |  pos_mm: X={X:+.0f} Y={Y:+.0f} Z={Z:.0f}"

            cv.putText(frame, info, (10, 30), cv.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,0), 3, cv.LINE_AA)
            cv.putText(frame, info, (10, 30), cv.FONT_HERSHEY_SIMPLEX, 0.7, (255,255,255), 1, cv.LINE_AA)
        else:
            cv.putText(frame, "Nie znaleziono czerwonego kwadratu", (10, 30),
                       cv.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,255), 2, cv.LINE_AA)

        # krzyż środka kadru
        cv.drawMarker(frame, (W//2, H//2), (0,255,255), markerType=cv.MARKER_CROSS, markerSize=20, thickness=2)
        cv.imshow("Red square tracker", frame)

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

    cap.release()
    cv.destroyAllWindows()

if __name__ == "__main__":
    main()

Jak użyć

  • Uruchom bez parametrów, żeby widzieć współrzędne pikselowe i offset:
    python red_square_tracker.py

  • Jeśli znasz rzeczywisty bok (np. 50 mm) oraz ogniskową w pikselach (z kalibracji lub z (W/2)/tan⁡(FOV/2)(W/2)/\tan(FOV/2)(W/2)/tan(FOV/2)), dostaniesz także X,Y,Z w mm:
    python red_square_tracker.py --square_mm 50 --focal_px 920

Uwaga praktyczna

  • Najlepiej mieć wydrukowany czerwony kwadrat na neutralnym tle. Jeśli tło bywa czerwone, można doprecyzować filtr HSV (progi lower*/upper*) lub dodać warunek na minimalny rozmiar/pionowość.

  • Dokładne X,Y,Z wymagają kalibracji kamery (f, dystorsja). Powyższy model (pinhole) jest przybliżeniem – do precyzyjnego pozycjonowania warto użyć kalibracji (cv2.calibrateCamera) lub markerów ArUco.

(edytowany)

 

dziękuje!! Dużo mi to rozjaśniło Testuje - dam znać 
 

Działa i wykrywa czerwony kwadrat. Jakbym chciał żeby jeszcze wykrywał żółty kwadrat  w tym samym programie to jak to zmodyfikować ? 

Szory za głupie pytania ale się uczę 

Pozdrawiam ! 

Edytowano przez robo1973

@robo1973Jedynym znanym mi sposobem, aby nauczyć się programować, jest programować. Postaraj się zrozumieć jak działa ten program i próbuj go modyfikować. Ustal gdzie rozpoznaje kwadrat, a gdzie robi coś innego i w jakim celu. Rozwiń znajdujące się w programie komentarze. Jeśli nie jesteś w stanie tego zrobić, to zacznij od prostszych programów.
Pytanie nie jest głupie, ale uważam, że właśnie w ramach nauki, mając działający - jak sam mówisz - przykład, powinieneś próbować sam na nie odpowiedzieć.
                                        Pozdrawiam i życzę powodzenia.

(edytowany)
 # Dwa zakresy żółtego (wrap-around na H)
    lower1_Y= np.array([, ,])
    upper1_Y = np.array([, , ])
    lower2_Y = np.array([, , ])

jakie będzie zakres HSV dla koloru żółtego ? 

Edytowano przez robo1973

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...