Voici quelques C99 source de la mise en œuvre de l'approche traditionnelle (basée sur OpenCV doco):
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
//
// We need this to be high enough to get rid of things that are too small too
// have a definite shape. Otherwise, they will end up as ellipse false positives.
//
#define MIN_AREA 100.00
//
// One way to tell if an object is an ellipse is to look at the relationship
// of its area to its dimensions. If its actual occupied area can be estimated
// using the well-known area formula Area = PI*A*B, then it has a good chance of
// being an ellipse.
//
// This value is the maximum permissible error between actual and estimated area.
//
#define MAX_TOL 100.00
int main( int argc, char** argv )
{
IplImage* src;
// the first command line parameter must be file name of binary (black-n-white) image
if( argc == 2 && (src=cvLoadImage(argv[1], 0))!= 0)
{
IplImage* dst = cvCreateImage( cvGetSize(src), 8, 3 );
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contour = 0;
cvThreshold( src, src, 1, 255, CV_THRESH_BINARY );
//
// Invert the image such that white is foreground, black is background.
// Dilate to get rid of noise.
//
cvXorS(src, cvScalar(255, 0, 0, 0), src, NULL);
cvDilate(src, src, NULL, 2);
cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
cvZero( dst );
for( ; contour != 0; contour = contour->h_next )
{
double actual_area = fabs(cvContourArea(contour, CV_WHOLE_SEQ, 0));
if (actual_area < MIN_AREA)
continue;
//
// FIXME:
// Assuming the axes of the ellipse are vertical/perpendicular.
//
CvRect rect = ((CvContour *)contour)->rect;
int A = rect.width / 2;
int B = rect.height / 2;
double estimated_area = M_PI * A * B;
double error = fabs(actual_area - estimated_area);
if (error > MAX_TOL)
continue;
printf
(
"center x: %d y: %d A: %d B: %d\n",
rect.x + A,
rect.y + B,
A,
B
);
CvScalar color = CV_RGB( rand() % 255, rand() % 255, rand() % 255 );
cvDrawContours( dst, contour, color, color, -1, CV_FILLED, 8, cvPoint(0,0));
}
cvSaveImage("coins.png", dst, 0);
}
}
Compte tenu de l'image binaire qui Carnieri fourni, c'est la sortie:
./opencv-contour.out coin-ohtsu.pbm
center x: 291 y: 328 A: 54 B: 42
center x: 286 y: 225 A: 46 B: 32
center x: 471 y: 221 A: 48 B: 33
center x: 140 y: 210 A: 42 B: 28
center x: 419 y: 116 A: 32 B: 19
Et c'est l'image de sortie:
Ce que tu pourrais améliorer:
- De gérer les différents ellipse orientations (actuellement, je suppose que les axes sont perpendiculaires à l'horizontal). Ce ne serait pas difficile de le faire à l'aide de l'image de moments.
- Vérifiez pour objet de convexité (regardez
cvConvexityDefects
)
Votre meilleure manière de distinguer les pièces de monnaie à partir d'autres objets va probablement être en forme. Je ne peux pas penser à d'autres images de bas niveau des fonctions (la couleur est évidemment out). Donc, je pense à deux approches:
Traditionnelles de détection d'un objet
Votre première tâche consiste à séparer les objets (pièces de monnaie, et non des pièces) à partir de l'arrière-plan. Ohtsu de la méthode, comme suggéré par Carnieri, fonctionne bien ici. Vous semblez vous soucier de l'image bipartite , mais je ne pense pas que ce sera un problème. Tant qu'il y a une quantité importante de bureau visible, vous avez la garantie d'avoir un pic dans votre histogramme. Et aussi longtemps que il ya un couple de distinguables visuellement les objets sur le bureau, vous avez la garantie de votre deuxième pic.
Dilater votre image binaire d'un couple de fois pour se débarrasser du bruit de gauche par seuillage. Les pièces sont relativement grand, de sorte qu'ils doivent survivre à ce fonctionnement morphologique.
Groupe les pixels blancs dans les objets à l'aide de la région de la croissance-seulement de manière itérative connecter adjacentes de pixels d'avant-plan. À la fin de cette opération, vous aurez une liste d'objets disjoints, et vous savez lequel les pixels de chaque objet occupe.
À partir de cette information, vous permettra de connaître la largeur et la hauteur de l'objet (de l'étape précédente). Alors, maintenant, vous pouvez estimer la taille de l'ellipse qui entourent l'objet, puis de voir comment cet objet correspond à l'ellipse. Il peut être plus facile que d'utiliser la largeur vs ratio de hauteur.
Alternativement, vous pouvez alors utiliser les moments de pour déterminer la forme de l'objet de façon plus précise.