2015-09-05 14 views
5

Sto utilizzando la sottrazione dello sfondo per analizzare gli oggetti in movimento di una scena esterna. Quando esce il sole ho un problema con le ombre. Sto usando i contorni per isolare gli oggetti. Al momento analizzo semplicemente la metà superiore del contorno mentre l'ombra si trova normalmente nella metà inferiore.Posizione quota minima contorno OpenCV in python

Immaginate un contorno di un'anatra di gomma, quello che mi piacerebbe fare è trovare la posizione del collo dell'anatra, cioè il punto in cui il contorno si trova nella sua minima dimensione orizzontale. Qualcuno potrebbe indicarmi la giusta direzione su come trovare il "collo dell'anatra"?

enter image description here

Nel codice, binary è un'immagine soglia degli oggetti in movimento, e HIGHTWIDTH sono l'altezza e la larghezza dell'immagine, lab è la stessa immagine nello spazio colore LAB.

Desidero sostituire la linea half = int(h/2) con una funzione per trovare la posizione y di una linea orizzontale per tagliare il "collo ducks".

_,contours,_ = cv2.findContours(binary.copy(), cv2.RETR_EXTERNAL, 
          cv2.CHAIN_APPROX_SIMPLE) 

# loop over the contours 
for i, cnt in enumerate(contours): 

    # compute the bounding box for the contour 
    (x, y, w, h) = cv2.boundingRect(cnt) 

    # reject contours outside size range 
    if w > 250 or w < 30 or h > 250 or h < 30 : 
      continue 

    # make sure the box is inside the frame 
    if x <= 0 or y <= 0 or x+w >= (WIDTH -1) or y+h >= (HIGHT -1): 
      continue 

    # isolate feature 
    half = int(h/2) 
    roi = lab[y:y+half, x:x+w] 
    mask = binary[y:y+half, x:x+w] 

    # calculate the mean of the colour 
    mean = cv2.mean(roi, mask = mask) 
    # note: mean is L a b 
    L = int(mean[0]) 
    a = int(mean[1]) 
    b = int(mean[2]) 
    print L,a,b 

Sto usando OpenCV 3 e pitone 2.7

P.S. Ho provato lo sottrattore di sfondo MOG2 che si dice identifichi le ombre ma è un modo rumoroso per il mio uso e non praticabile.

+3

Aggiungi alla tua domanda alcune immagini con risultati effettivi e previsti. Fai clic sul link di modifica sotto i tag. Non hai abbastanza reputazione per aggiungere immagini, ma puoi pubblicare un link pubblico da imgur o simili. – Miki

+0

Ciao Miki, ho aggiunto uno schizzo che dovrebbe aiutare a chiarire, per favore sentiti libero di chiedere qualsiasi altra cosa. Ho pensato a 3 possibili soluzioni, 1) In qualche modo uso i momenti, 2) scorrere l'elenco dei contorni per trovare i punti di svolta, 3) Sommare le righe orizzontalmente per ottenere un profilo e quindi trovare i punti di svolta del profilo. I primi due non ne ho idea, quindi un aiuto su come utilizzare i momenti o su come accedere e interpretare la lista dei contorni sarebbe di grande aiuto. O qualsiasi altro suggerimento sarebbe molto apprezzato. – Johno

+0

Ci scusiamo per il dolore quando stai cercando di fare come richiesto, ma per favore evita Dropbox/altri collegamenti transitori se possibile - vogliamo che queste domande aiutino le persone per anni e, se in futuro eliminerai il tuo file dropbox, farebbe questa domanda è meno preziosa SO Avere un accordo con imgur per assicurarsi che tutte le immagini saranno in giro per la durata. L'ho fatto per te in questo caso. Spero che trovi la tua risposta! – Basic

risposta

0

È possibile definire una maschera per erodere l'immagine, in modo da poter rompere i blob in alto e in basso dalla valle. Puoi applicarlo al tuo codice come segue:

# loop over the contours 
for i, cnt in enumerate(contours): 

    # compute the bounding box for the contour 
    (x, y, w, h) = cv2.boundingRect(cnt) 

    # reject contours outside size range 
    if w > 250 or w < 30 or h > 250 or h < 30 : 
      continue 

    # make sure the box is inside the frame 
    if x <= 0 or y <= 0 or x+w >= (WIDTH -1) or y+h >= (HIGHT -1): 
      continue 

    # --------------- 
    # create a mask for erosion, you can play with the mask size/shape 
    mask = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) 
    # erode the original image 
    eroded_img = cv2.erode(binary,mask,iterations = 1) 
    cv2.imshow("Eroded image",eroded_img) 
    # find the middle of the two new contours 
    _,new_contours,_ = cv2.findContours(eroded_img, cv2.RETR_EXTERNAL, 
         cv2.CHAIN_APPROX_SIMPLE) 
    (_, y_t, _, h_t) = cv2.boundingRect(new_contours[0]) 
    (_, y_b, _, h_b) = cv2.boundingRect(new_contours[1]) 
    bottom_top_y = max(y_t, y_b) # highest y of bottom part 
    top_bottom_y = min(y_t+h_t, y_b+h_b) # lowest y of top part 
    half = top_bottom_y + (bottom_top_y - top_bottom_y)/2 
    # ------------ 

    # isolate feature 
    roi = lab[y:y+half, x:x+w] 
    mask = binary[y:y+half, x:x+w] 

    # calculate the mean of the colour 
    mean = cv2.mean(roi, mask = mask) 
    # note: mean is L a b 
    L = int(mean[0]) 
    a = int(mean[1]) 
    b = int(mean[2]) 
    print L,a,b 

Spero che sia d'aiuto! Per ulteriori esempi sulle operazioni morfologiche su immagini binarie, è possibile controllare here.

+0

Ike, grazie mille per il vostro contributo. Questo è sicuramente un modo per farlo.Uso già l'erode per ridurre le dimensioni della maschera in modo che i bordi stessi dell'oggetto non siano inclusi nei calcoli di riconoscimento. Forse eroderò in un ciclo fino a quando non ci saranno 2 contorni e poi ridurrò il contorno superiore alla dimensione quasi originale. Saluti :-) – Johno