with recognition learning hog book and image image-processing opencv image-recognition

recognition - Detección de monedas(y elipses ajustados) en una imagen



object detection with deep learning and opencv (3)

Aquí hay alguna fuente C99 que implementa el enfoque tradicional (basado en 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); } }

Dada la imagen binaria que proporcionó Carnieri, este es el resultado:

./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

Y esta es la imagen de salida:

Lo que podrías mejorar:

  • Maneje diferentes orientaciones de elipse (actualmente, supongo que los ejes son perpendiculares / horizontales). Esto no sería difícil de hacer usando momentos de imagen.
  • Verifique la convexidad del objeto (eche un vistazo a cvConvexityDefects )

Tu mejor forma de distinguir monedas de otros objetos probablemente sea por forma. No puedo pensar en ninguna otra característica de imagen de bajo nivel (el color está obviamente fuera). Entonces, puedo pensar en dos enfoques:

Detección de objetos tradicionales

Su primera tarea es separar los objetos (monedas y no monedas) del fondo. El método de Ohtsu, como lo sugiere Carnieri, funcionará bien aquí. Parece que te preocupa que las imágenes sean bipartitas, pero no creo que esto sea un problema. Siempre que haya una cantidad significativa de escritorio visible, se garantiza que tendrá un pico en su histograma. Y mientras haya un par de objetos visualmente distinguibles en el escritorio, se le garantiza su segundo pico.

Dilate tu imagen binaria un par de veces para eliminar el ruido que deja el umbral. Las monedas son relativamente grandes, por lo que deberían sobrevivir a esta operación morfológica.

Agrupe los píxeles blancos en los objetos mediante el crecimiento de la región: solo conecte iterativamente los píxeles de primer plano adyacentes. Al final de esta operación, tendrá una lista de objetos disjuntos, y sabrá qué píxeles ocupa cada objeto.

A partir de esta información, sabrá el ancho y la altura del objeto (del paso anterior). Entonces, ahora puede estimar el tamaño de la elipse que rodearía el objeto, y luego ver qué tan bien este objeto en particular coincide con la elipse. Puede ser más fácil simplemente usar la relación ancho / alto.

Alternativamente, puede usar moments para determinar la forma del objeto de una manera más precisa.

Actualmente estoy trabajando en un proyecto en el que estoy tratando de detectar algunas monedas que yacen sobre una superficie plana (es decir, un escritorio). Las monedas no se superponen y no están ocultas por otros objetos. Pero puede haber otros objetos visibles y las condiciones de iluminación pueden no ser perfectas ... Básicamente considérese grabando su escritorio que tiene algunas monedas.

Entonces cada punto debe ser visible como una elipse. Como no conozco la posición de la cámara, la forma de las elipsis puede variar, desde el círculo (vista desde arriba) hasta las elipsis planas, dependiendo del ángulo desde el que se filman las monedas.

Mi problema es que no estoy seguro de cómo extraer las monedas y, finalmente, ajustar las elipsis sobre ellas (lo que estoy buscando para hacer más cálculos).

Por ahora acabo de hacer un primer intento al establecer un valor de umbral en OpenCV, usando findContours () para obtener las curvas de nivel y ajustar una elipse. Lamentablemente, las líneas de contorno rara vez me dan la forma de las monedas (reflejos, mala iluminación, ...) y de esta manera tampoco se prefiere, ya que no quiero que el usuario establezca ningún umbral.

Otra idea era usar un método de coincidencia de plantilla de una elipse en esa imagen, pero como no conozco el ángulo de la cámara ni el tamaño de las elipses, no creo que esto funcione bien ...

Así que quería preguntar si alguien podría decirme un método que funcionaría en mi caso ...

¿Hay una manera rápida de extraer las tres monedas de la imagen? Los cálculos deben realizarse en tiempo real en dispositivos móviles y el método no debe ser demasiado sensible para luces diferentes o cambiantes o el color del fondo.

Sería genial si alguien pudiera darme algún consejo sobre qué método podría funcionar para mí ...


No sé cuál es el mejor método para su problema. Sin embargo, sobre el umbraling específicamente, puede usar el método de Otsu, que automáticamente encuentra el valor de umbral óptimo basado en un análisis del histograma de la imagen. Use el método de threshold de OpenCV con el parámetro ThresholdType igual a THRESH_OTSU .

Tenga en cuenta, sin embargo, que el método de Otsu funciona bien solo en imágenes con histogramas bimodales (por ejemplo, imágenes con objetos brillantes sobre un fondo oscuro).

Probablemente haya visto esto, pero también hay un método para ajustar una elipse en torno a un conjunto de puntos 2D (por ejemplo, un componente conectado).

EDIT : método de Otsu aplicado a una imagen de muestra:

Imagen en escala de grises:

Resultado de aplicar el método de Otsu:


Si alguien más viene con este problema en el futuro como lo hice, pero usando C ++:

Una vez que haya utilizado findContours para encontrar los contornos (como en la respuesta de Misha anterior), puede ajustar fácilmente las elipsis usando fitEllipse , por ej.

vector<vector<Point> > contours; findContours(img, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0,0)); RotatedRect rotRecs[contours.size()]; for (int i = 0; i < contours.size(); i++) { rotRecs[i] = fitEllipse(contours[i]); }