0

Je suis un débutant à la vision de l'ordinateur, et je suis en train de détecter toutes les bandelettes de test dans cette image:Comment détecter les bandelettes de test avec OpenCV?

source

Le résultat que je suis en train de faire:

result

Je suppose que cela devrait être très facile, car tous les objets cibles sont de forme rectangulaire et ont un rapport d'aspect fixe. Mais je n'ai aucune idée quel algorithme ou fonction devrais-je utiliser.

J'ai essayé la détection de contours et l'exemple de détection de caractéristiques 2D dans OpenCV, mais le résultat n'est pas idéal. Comment devrais-je détecter ces objets similaires mais avec de petites différences?

Mise à jour:

Les bandelettes de test peuvent varier en couleurs, et bien sûr, l'ombre des lignes de résultat. Mais ils ont tous les mêmes références lignes, comme montrant dans l'image:

variations of test strips

Je ne sais pas comment dois-je décrire ces caractéristiques simples pour la détection d'objets, comme la plupart des exemples que je trouve sont en ligne pour les objets complexes comme un bâtiment ou un visage.

+1

juste quelques sugestions, 1) essayez d'éliminer l'arrière-plan (seuil). 2) trouver des lignes, peut-être [hough line transformer] (http://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html) peut aider, 3) trouver des intersections de telles lignes 4) créer des rectangles avec ces intersections. Bonus) Vous pouvez essayer d'isoler chaque objet (le contour) du reste (le reste = noir) et les analyser 1 par 1 sans aucune autre donnée qui peut perturber vos résultats. – api55

+0

Avez-vous d'autres images pour en voir les variations? –

+0

@MarkSetchell Veuillez voir mes mises à jour – zhengyue

Répondre

2

La solution n'est pas exacte, mais elle constitue un bon point de départ. Vous devez jouer avec les paramètres cependant. Cela vous serait très utile si vous partitionnez les bandes en utilisant une méthode de seuil et que vous appliquez des lignes de creux individuellement comme @ api55 mentionné.

Voici les résultats que j'ai obtenus.

after laplacianafter thresholding and median filteringfinal image

Code.

import cv2 
import numpy as np 

# read image 
img = cv2.imread('KbxN6.jpg') 
# filter it 
img = cv2.GaussianBlur(img, (11, 11), 0) 
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 

# get edges using laplacian 
laplacian_val = cv2.Laplacian(gray_img, cv2.CV_32F) 

# lap_img = np.zeros_like(laplacian_val, dtype=np.float32) 
# cv2.normalize(laplacian_val, lap_img, 1, 255, cv2.NORM_MINMAX) 
# cv2.imwrite('laplacian_val.jpg', lap_img) 

# apply threshold to edges 
ret, laplacian_th = cv2.threshold(laplacian_val, thresh=2, maxval=255, type=cv2.THRESH_BINARY) 
# filter out salt and pepper noise 
laplacian_med = cv2.medianBlur(laplacian_th, 5) 
# cv2.imwrite('laplacian_blur.jpg', laplacian_med) 
laplacian_fin = np.array(laplacian_med, dtype=np.uint8) 

# get lines in the filtered laplacian using Hough lines 
lines = cv2.HoughLines(laplacian_fin,1,np.pi/180,480) 
for rho,theta in lines[0]: 
    a = np.cos(theta) 
    b = np.sin(theta) 
    x0 = a*rho 
    y0 = b*rho 
    x1 = int(x0 + 1000*(-b)) 
    y1 = int(y0 + 1000*(a)) 
    x2 = int(x0 - 1000*(-b)) 
    y2 = int(y0 - 1000*(a)) 
    # overlay line on original image 
    cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2) 

# cv2.imwrite('processed.jpg', img) 
# cv2.imshow('Window', img) 
# cv2.waitKey(0) 
+0

Merci! Je vais essayer et mettre à jour le résultat. – zhengyue

0

Ceci est une solution alternative en utilisant la fonction findCountours en combinaison avec la détection de bord canny. Le code est basé très légèrement sur ce tutorial

import cv2 
import numpy as np 
import imutils 

image = cv2.imread('test.jpg') 
resized = imutils.resize(image, width=300) 
ratio = image.shape[0]/float(resized.shape[0]) 

# convert the resized image to grayscale, blur it slightly, 
# and threshold it 
gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY) 
edges = cv2.Canny(resized,100,200) 
cv2.imshow('dsd2', edges) 
cv2.waitKey(0) 
cnts = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, 
    cv2.CHAIN_APPROX_NONE) 
cnts = cnts[0] if imutils.is_cv2() else cnts[1] 
sd = ShapeDetector() 

# loop over the contours 
for c in cnts: 
    # compute the center of the contour, then detect the name of the 
    # shape using only the contour 
    M = cv2.moments(c) 
    cX = int((M["m10"]/M["m00"]) * ratio) 
    cY = int((M["m01"]/M["m00"]) * ratio) 


    # multiply the contour (x, y)-coordinates by the resize ratio, 
    # then draw the contours and the name of the shape on the image 
    c = c.astype("float") 
    c *= ratio 
    c = c.astype("int") 
    cv2.drawContours(image, [c], -1, (0, 255, 0), 2) 
    #show the output image 
    #cv2.imshow("Image", image) 
    #cv2.waitKey(0) 
cv2.imwrite("erg.jpg",image) 

Résultat: enter image description here


je suppose qu'il peut être amélioré en réglant les paramètres suivants:

Il est peut-être aussi utile pour filtrer les petits contours ou fusionner les contours qui sont proches les uns des autres.