2012-03-29 6 views
7

Obtuve el libro 'Learning OpenCV' de O'Reilly no hace mucho tiempo, y desde entonces he estado ocupado convirtiendo todo el código de ejemplo que veo allí de OpenCV a JavaCV, generalmente seguido de un poco de mi propia modificación también. Mientras tanto, trato de mantener el código puro OpenCV (lenguaje C) tanto como sea posible y evitar Java. Por ejemplo, implementé todos los elementos de la interfaz directamente a través del paquete OpenCV highgui en JavaCV, en lugar de a través de Java Swing. Al hacer esto, espero aprender la biblioteca OpenCV y algo de C en relativamente poco tiempo, así como establecer una biblioteca de funciones útiles que podré convertir a C fácilmente si decido luego cambiar a OpenCV puro.Convertir el bucle de matriz OpenCV a JavaCV

De todos modos, tengo poco conocimiento de C y algunas veces me meto en problemas cuando trato con punteros. El libro recomienda el siguiente código como un medio óptimo por el cual para iterar a través de una matriz de 3 canales:

float sum(const CvMat* mat) { 
    float s = 0.0f; 
    for(int row=0; row<mat->rows; row++) { 
     const float* ptr = (const float*)(mat->data.ptr + row * mat->step); 
     for(col=0; col<mat->cols; col++) { 
      s += *ptr++; 
     } 
    } 
    return(s); 
} 

Aquí es la explicación incluido para este código:

Cuando se calcula el puntero en la matriz , recuerde que los datos del elemento de matriz son una unión. Por lo tanto, al quitar la referencia de este puntero, debe indicar el elemento correcto de la unión para obtener el tipo de puntero correcto. Para desactivar el indicador , debe usar el elemento de paso de la matriz. Como se indicó anteriormente, el elemento del paso está en bytes. Para estar seguro, lo mejor es hacer la aritmética de su puntero en bytes y luego lanzarlo al tipo apropiado, en este caso flotar. Aunque la estructura CVMat tiene> el concepto de altura y ancho para compatibilidad con la estructura IplImage anterior,> utilizamos las filas y cols más actualizadas. Finalmente, tenga en cuenta que recalculamos ptr para> cada fila en lugar de simplemente comenzar desde el principio y luego incrementar ese puntero cada lectura. Esto puede parecer excesivo, pero debido a que el puntero de datos CvMat podría solo señalar un ROI dentro de una matriz más grande, no hay garantía de que los datos sean> contiguos entre filas.

Sin embargo, estoy teniendo problemas para convertirlo a JavaCV. El campo ptr (puntero) parece ser un flotador, lo cual me confunde. Supongo que no es realmente un "puntero", sino un valor al que se agrega el valor de cada píxel. ¿O es en realidad un puntero, cuyo valor s encuentra la suma total de todas las columnas dentro de una fila determinada?

De todos modos, agradecería que alguien me enviara algún código JavaCV para un ciclo equivalente. Sé que hay otras maneras de acceder a cada píxel en un CvMat, pero AFAIK son menos eficientes o inexactos.

+0

Por lo que puede ver en el ejemplo, la matriz se dirige como 2-dimensional, en escala de grises, flotador de tipo de datos. Todos los valores de píxel se suman en s, que se convertirán en el brillo acumulativo. El NAD es en realidad un puntero que apunta en la matriz en un punto arbitrario y 'ptr [x]' es igual a '(const float *) (mat-> data.ptr + fila * mat-> paso) [x]; '. ptr se inicializa para un píxel dado y se incrementa, por lo que '[x]' no es necesario y simplemente se desreferencia con '*', igual a '[0]'. –

+0

@zom ¿Cómo se incrementa el puntero? Por lo que entiendo del código, ¿al puntero se le asigna el valor del píxel? ¿O se le asigna la posición del píxel? Si el caso anterior, cuando ocurre la operación 'ptr ++', ¿no aumentaría el valor del píxel asignado, en lugar de hacer que el puntero apunte al siguiente píxel? Y si el caso posterior, ¿cuándo y dónde está el valor real del píxel asignado a 's'? Muchas preguntas. –

+0

ve a leer esto primero: http://c-faq.com/ptrs/index.html –

Respuesta

6

El ejemplo particular que usted proporciona se convierte de forma óptima a Java como

float sum(CvMat mat) { 
    final int rows = mat.rows(); 
    final int cols = mat.cols(); 
    final int step = mat.step()/4; 
    FloatBuffer buf = mat.getFloatBuffer(); 
    float s = 0.0f; 
    for (int row = 0; row < rows; row++) { 
     buf.position(row * step); 
     for (int col = 0; col< cols; col++) { 
      s += buf.get(); 
     } 
    } 
    return s; 
} 
+0

Gracias Sam, ¡es bueno recibir la respuesta del propio desarrollador de JavaCV! Ya lo he resuelto a través de –

+0

Ok, ¡genial! pero deberías aceptar la respuesta de todos modos, si responde la pregunta que inicialmente publicaste es ... –

0

Aquí es una variante con el tiempo llegué a través de ensayo & de error; para iterar a través de una matriz de 3 canales y aplicar un filtro muy simple (creo que el ejemplo de Samuel ya cubre muy bien la suma de los valores de la escala de grises).

static IplImage setSaturate_sv(IplImage imgIn) { 
    IplImage imgOut = cvCloneImage(imgIn); 
    ByteBuffer pointer = imgOut.getByteBuffer(); 

    int height = imgIn.height(); 
    int width = imgIn.width(); 
    int widthStep = imgIn.widthStep(); 
    int nChannels = imgIn.nChannels(); 
    int rowIndex; 

    for (int row = 0; row < height; row++) { 
     rowIndex = row * widthStep; 
     for (int col = 0; col < width; col++) { 
      pointer.put((rowIndex + (col * nChannels) + 1), (byte)255); 
      pointer.put((rowIndex + (col * nChannels) + 2), (byte)255); 
      pointer.put((rowIndex + (col * nChannels) + 3), /* leave alone */); 
     } 
    } 
    return imgOut; 
} 
Cuestiones relacionadas