2012-07-09 9 views
9

Estoy desarrollando un proyecto de identificación de formas usando JavaCV y he encontrado algunos códigos OpenCV para identificar las formas U en una imagen particular. Intenté convertirlo en JavaCV, pero no da el mismo resultado. ¿Puedes ayudarme a convertir este código OpenCV en JavaCV?opencv/javacv: ¿Cómo iterar sobre los contornos para la identificación de formas?

Este es el código de OpenCV:

import cv2 
import numpy as np 

img = cv2.imread('sofud.jpg') 
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
ret,thresh = cv2.threshold(gray,127,255,1) 
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 

for cnt in contours: 
    x,y,w,h = cv2.boundingRect(cnt) 
    if 10 < w/float(h) or w/float(h) < 0.1: 
     cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2) 

cv2.imshow('res',img) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

Esta es la salida esperada

enter image description here

Este es el código convertido:

import com.googlecode.javacpp.Loader; 
import com.googlecode.javacv.CanvasFrame; 
import static com.googlecode.javacpp.Loader.*; 
import static com.googlecode.javacv.cpp.opencv_core.*; 
import static com.googlecode.javacv.cpp.opencv_imgproc.*; 
import static com.googlecode.javacv.cpp.opencv_highgui.*; 
import java.io.File; 
import javax.swing.JFileChooser; 

public class TestBeam { 
    public static void main(String[] args) { 
     CvMemStorage storage=CvMemStorage.create(); 
     CvSeq squares = new CvContour(); 
     squares = cvCreateSeq(0, sizeof(CvContour.class), sizeof(CvSeq.class), storage); 
     JFileChooser f=new JFileChooser(); 
     int result=f.showOpenDialog(f);//show dialog box to choose files 
      File myfile=null; 
      String path=""; 
     if(result==0){ 
      myfile=f.getSelectedFile();//selected file taken to myfile 
      path=myfile.getAbsolutePath();//get the path of the file 
     } 
     IplImage src = cvLoadImage(path);//hear path is actual path to image 
     IplImage grayImage = IplImage.create(src.width(), src.height(), IPL_DEPTH_8U, 1); 
     cvCvtColor(src, grayImage, CV_RGB2GRAY); 
     cvThreshold(grayImage, grayImage, 127, 255, CV_THRESH_BINARY); 
     CvSeq cvSeq=new CvSeq(); 
     CvMemStorage memory=CvMemStorage.create(); 
     cvFindContours(grayImage, memory, cvSeq, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); 
     System.out.println(cvSeq.total()); 
     for (int i = 0; i < cvSeq.total(); i++) { 
      CvRect rect=cvBoundingRect(cvSeq, i); 
      int x=rect.x(),y=rect.y(),h=rect.height(),w=rect.width(); 
      if (10 < (w/h) || (w/h) < 0.1){ 
       cvRectangle(src, cvPoint(x, y), cvPoint(x+w, y+h), CvScalar.RED, 1, CV_AA, 0); 
       //cvSeqPush(squares, rect); 
      } 
     } 
     CanvasFrame cnvs=new CanvasFrame("Beam"); 
     cnvs.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); 
     cnvs.showImage(src); 
     //cvShowImage("Final ", src); 

    } 
} 

Esta es la salida que yo tiene. Por favor alguien puede ayudarme a resolver este problema?

enter image description here

+0

No veo ningún C++, por lo que eliminé la etiqueta. Supongo que el primer ejemplo es Python. –

+1

Tengo una pequeña pregunta con respecto a esta pregunta. Por favor, ¿alguien puede explicar el valor del método "cvSeq.total()" después de ejecutar el método "cvFindContours()"? –

Respuesta

5

EDIT: Aquí es el descubrimiento más interesante - creo que no está iterando correctamente a través de los contornos - usted debe hacer algo como:

CvRect rect = cvBoundingRect(cvGetSeqElem(cvSeq, i),0); //python default? 

O:

// ... 
CvSeq contours = new CvSeq(); 
CvSeq ptr = new CvSeq(); 
CvRect rect = null; 
// ... 
cvFindContours(..., contours, ...); 

for (ptr = contours; ptr != null; ptr = ptr.h_next()) { 
    rect = cvBoundingRect(ptr, 0); 
    // ... Draw the box if meets criteria 
} 

En primer lugar, piense que pst tiene razón con respecto al cálculo de la relación: debe fundir el ancho para flotar.

En segundo lugar, veo que cuando está haciendo la imagen gris en python usa COLOR_BGR2GRAY y en java está usando CV_RGB2GRAY que podría conducir a una imagen gris totalmente diferente. Agregaría algunos pasos de depuración en ambos programas para guardar las imágenes grises temp y las compararía como también impresiones para los valores de x,y,w y h cuando (10 < (w/h) || (w/h) < 0.1) es verdadero.

Otra cosa es que en la solución de Java utiliza CV_RETR_CCOMP para obtener los contornos y en la solución de pitón que utilice CV_RETR_LIST de acuerdo a la documentación:

CV_RETR_LIST recupera todos los contornos sin establecer ningún relaciones jerárquicas CV_RETR_CCOMP recupera todos los contornos y los organiza en una jerarquía de dos niveles: en el nivel superior están los límites externos de los componentes, en el segundo nivel están los contornos de los agujeros. Si dentro de un agujero de un componente conectado hay otro contorno, todavía será puesto en el nivel superior

Así que primero me gustaría corroborar que todos los parámetros de cv en ambos programas son los mismos, entonces yo añadiría depurar los pasos para ver que las variables intermedias contienen los mismos datos.

+0

En javacv cvBoundingRect() no podemos pasar el puntero como parámetro porque requirió CvArr, así que creo que no puede ser el problema. –

+0

@GumSlashy - ver mi edición. Según el README de javacv (http://code.google.com/p/javacv/source/browse/README.txt), esta es una forma correcta de iterar sobre los contornos. También encontré esta pregunta en SO http://stackoverflow.com/questions/9648482/ocr-with-javacv que usa el mismo método para obtener contornos y dibujar sus recuadros delimitadores. – zenpoy

+0

Intento poner cvBoundingRect (cvGetSeqElem (cvSeq, i), 0); en el problema, pero no funcionó para mí y he puesto la respuesta de que tengo los resultados correctos. de todos modos muchas gracias por su respuesta. –

3

Compruebe sus promociones tipo, ej .:

if (10 < (w/h) || (w/h) < 0.1){ 

.. es altamente sospechoso. Para obtener una división punto flotante, uno (o ambos) de los operandos debe ser al menos un float (y también un double para división doble). De lo contrario, como en este caso, es una división entera. (Tenga en cuenta que la código original de tiene el ascenso a float también.)

Por ejemplo:

float ratio = (float)w/h; // (float/int) => (float/float) -> float 
if (10 < ratio || ratio < 0.1) { 

(Aunque no estoy seguro de si esto es el tema aquí.)

feliz ¡codificación!

+1

Gracias por su respuesta rápida y he intentado su sugerencia, pero dio el mismo resultado. –

+0

Creo que sería útil actualizar tu código con tus cambios. Tal vez todavía hay una división entera allí? – Noremac

+1

He puesto la respuesta y en eso también intento arrojar el valor de w/h para flotar, pero no dio un efecto significativo. Pero es cierto que podría estar afectando significativamente en algunos otros casos. Muchas gracias por su respuesta. –

2

Este código funciona para mí y acabo de poner cvSeq = cvSeq.h_next(); ingrese al programa y elimine el bucle for para agregar el bucle while para thet.

package Beam; 
    import com.googlecode.javacpp.Loader; 
    import com.googlecode.javacv.CanvasFrame; 
    import static com.googlecode.javacpp.Loader.*; 
    import static com.googlecode.javacv.cpp.opencv_core.*; 
    import static com.googlecode.javacv.cpp.opencv_imgproc.*; 
    import static com.googlecode.javacv.cpp.opencv_highgui.*; 
    import java.io.File; 
    import javax.swing.JFileChooser; 

    public class TestBeam2 { 
     public static void main(String[] args) { 
      JFileChooser f=new JFileChooser(); 
      int result=f.showOpenDialog(f);//show dialog box to choose files 
       File myfile=null; 
       String path=""; 
      if(result==0){ 
       myfile=f.getSelectedFile();//selected file taken to myfile 
       path=myfile.getAbsolutePath();//get the path of the file 
      } 
      IplImage src = cvLoadImage(path);//hear path is actual path to image 
      IplImage grayImage = IplImage.create(src.width(), src.height(), IPL_DEPTH_8U, 1); 
      cvCvtColor(src, grayImage, CV_RGB2GRAY); 
      cvThreshold(grayImage, grayImage, 127, 255, CV_THRESH_BINARY); 
      CvSeq cvSeq=new CvSeq(); 
      CvMemStorage memory=CvMemStorage.create(); 
      cvFindContours(grayImage, memory, cvSeq, Loader.sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); 

      while (cvSeq != null && !cvSeq.isNull()) { 
       CvRect rect=cvBoundingRect(cvSeq, 0); 
       int x=rect.x(),y=rect.y(),h=rect.height(),w=rect.width(); 
       if (10 < w/h || w/h < 0.1){ 
        cvRectangle(src, cvPoint(x, y), cvPoint(x+w, y+h), CvScalar.RED, 1, CV_AA, 0); 
       } 
       cvSeq=cvSeq.h_next(); 
      } 
      CanvasFrame cnvs=new CanvasFrame("Beam"); 
      cnvs.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); 
      cnvs.showImage(src); 
      //cvShowImage("Final ", src); 
     } 
    } 
+2

Este es exactamente el mismo método que sugerí hace unos días: es una lástima que no lo haya intentado: '// ... CvSeq contours = new CvSeq(); CvSeq ptr = new CvSeq(); CvRect rect = null; // ... cvFindContours (..., contornos, ...); para (ptr = contornos; ptr! = Null; ptr = ptr.h_next()) { rect = cvBoundingRect (ptr, 0); // ... Dibuje el cuadro si cumple los criterios } ' – zenpoy

Cuestiones relacionadas