En utilisant Opencv, comment détecter une boîte dans l'image tout en éliminant les objets imprimés à l'intérieur de la boîte ?
-
02-01-2020 - |
Question
J'essaie de développer une application de tri de boîtes dans Qt et en utilisant opencv.Je veux mesurer la largeur et la longueur de la boîte.
Comme le montre l'image ci-dessus, je souhaite détecter uniquement les lignes les plus extérieures (c.-à-d.bords de la boîte), ce qui me donnera la largeur et la longueur de la boîte, quel que soit ce qui est imprimé à l'intérieur de la boîte.
Ce que j'ai essayé :
J'ai d'abord essayé d'utiliser
Findcontours()
et le contour sélectionné avec une zone maximale, mais le contour du bord extérieur n'est pas inclus (cassé quelque part dans la sortie astucieuse) plusieurs fois et n'est donc pas détecté comme un contour.Bien que la transformation de ligne me donne trop de lignes, je ne sais pas comment obtenir seulement quatre lignes qui m'intéressent.
J'ai essayé mon algorithme comme,
Convertir l'image en échelle de gris.
Prenez une colonne d'image, comparez chaque pixel avec le pixel successif suivant de cette colonne, si la différence de valeur est supérieure à un certain seuil (disons 100) auquel ce pixel appartient au bord, stockez-le donc dans un tableau.Faites ceci pour toutes les colonnes et cela donnera la ligne supérieure de la boîte parallèle à l'axe des x.
Suivez la même procédure, mais à partir de la dernière colonne et de la dernière ligne (c.-à-d.de bas en haut), cela donnera une ligne inférieure parallèle à l’axe x.
Trouvez également des lignes parallèles à l’axe y.J'ai maintenant quatre tableaux de points, un pour chaque côté.
Maintenant, cela me donne de bons résultats si la boîte est placée de telle manière que ses côtés soient exactement parallèles aux axes X et Y.Si la boîte est placée même légèrement orientée dans une certaine direction, cela me donne des lignes diagonales qui sont évidentes, comme le montre l'image ci-dessous.
Comme le montre l'image ci-dessous, j'ai supprimé les 10 premiers et les 10 derniers points des quatre tableaux de points (qui sont responsables du dessin des lignes diagonales) et j'ai dessiné les lignes, ce qui ne fonctionnera pas lorsque la boîte est davantage inclinée et les mesures seront également erronées. .
Maintenant ma question est,
Existe-t-il un moyen plus simple dans opencv d'obtenir uniquement les bords extérieurs (rectangle) de la boîte et d'y obtenir les dimensions, en ignorant tout ce qui est imprimé sur la boîte et orienté dans n'importe quelle direction ?
Je ne demande pas nécessairement de corriger/améliorer mon algorithme, mais toute suggestion à ce sujet est également la bienvenue.Désolé pour un si gros post.
La solution
Je suggérerais les étapes suivantes:
1:Créez une image de masque en utilisant cv::inRange()
(Documentation) pour sélectionner la couleur d’arrière-plan.Utilisez ensuite cv::not()
pour inverser ce masque.Cela vous donnera uniquement la boîte.
2 :Si vous n'êtes pas préoccupé par les effets d'ombre et de profondeur rendant votre mesure inexacte, vous pouvez immédiatement essayer d'utiliser cv::findContours()
encore.Vous sélectionnez le plus grand contour et le stockez cv::rotatedRect
.
3 :Ce cv::rotatedRect
vous donnera un rotatedRect.size qui définit la largeur et la hauteur de votre boîte en pixels
Autres conseils
Étant donné que la boîte est placée sur un arrière-plan contrasté, vous devriez pouvoir utiliser le seuillage Otsu.
- seuiller l'image (utiliser la méthode Otsu)
- filtrer tous les pixels parasites qui se trouvent en dehors de la région de la boîte (espérons que vous n'obtiendrez pas beaucoup de ces pixels et que vous pourrez facilement les supprimer avec un filtre médian ou morphologique)
- trouver des contours
- combinez tous les points de contour et obtenez leur coque convexe (l'idée ici est de trouver la région convexe qui délimite tous ces contours dans la région de la boîte quelle que soit leur connectivité)
- appliquez une approximation de polygone (approxPolyDP) à cette coque convexe et vérifiez si vous obtenez un quadrilatère
- s'il n'y a pas de distorsion de perspective, vous devriez obtenir un rectangle, sinon vous devrez le corriger
- si vous obtenez un rectangle, vous avez ses dimensions.Vous pouvez également trouver le rectangle d'aire minimale (minAreaRect) de la coque convexe, qui devrait directement vous donner un RotatedRect