2008-12-27 36 views
11

Necesito convertir una IplImage de 8 bits a una imagen Ipl de 32 bits. Utilizando la documentación de toda la web He intentado lo siguiente:¿Cómo convertir una imagen IplImage * OpenCV de 8 bits a una IplImage * de 32 bits?

// general code 
img2 = cvCreateImage(cvSize(img->width, img->height), 32, 3); 
int height = img->height; 
int width  = img->width; 
int channels = img->nChannels; 
int step1  = img->widthStep; 
int step2  = img2->widthStep; 
int depth1 = img->depth; 
int depth2 = img2->depth; 
uchar *data1 = (uchar *)img->imageData; 
uchar *data2 = (uchar *)img2->imageData; 

for(h=0;h<height;h++) for(w=0;w<width;w++) for(c=0;c<channels;c++) { 
    // attempt code... 
} 

// attempt one 
// result: white image, two red spots which appear in the original image too. 
// this is the closest result, what's going wrong?! 
// see: http://files.dazjorz.com/cache/conversion.png 
((float*)data2+h*step2+w*channels+c)[0] = data1[h*step1+w*channels+c]; 

// attempt two 
// when I change float to unsigned long in both previous examples, I get a black screen. 

// attempt three 
// result: seemingly random data to the top of the screen. 
data2[h*step2+w*channels*3+c] = data1[h*step1+w*channels+c]; 
data2[h*step2+w*channels*3+c+1] = 0x00; 
data2[h*step2+w*channels*3+c+2] = 0x00; 

// and then some other things. Nothing did what I wanted. I couldn't get an output 
// image which looked the same as the input image. 

Como se puede ver que no se sabe muy bien lo que estoy haciendo. Me encantaría saberlo, pero me gustaría más si pudiera hacer esto correctamente. ¡Gracias por cualquier ayuda que reciba!

Respuesta

6

Quizás esto link puede ayudarle?

Editar En respuesta a la segunda edición de la OP y el comentario

¿Ha intentado

float value = 0.5

en lugar de

float value = 0x0000001;

me pareció que el rango para un valor de color flotante va de 0.0 a 1.0, wh ere 1.0 es blanco.

+0

Hay algo de información interesante en esa página, piezas de código que explican lo que he ya lo intenté. Sin embargo, los resultados son los mismos. Consulte el siguiente enlace para ver un ejemplo de lo que va mal todo el tiempo: http://files.dazjorz.com/cache/conversion.png – sgielen

+0

Whoa, sí, eso es un bueno, tienes razón! Así que da la siguiente pista: para los puntos rojos, R es 1.0 y GB son 0.0, y para el blanco, los tres son 1.0. Por lo tanto, al convertir, los valores RGB deberían d se convertirá de 0 a 255 a 0.0 a 1.0. Cambiar el valor a b/255 hace que la imagen sea negra + roja. – sgielen

+0

¡Entendido! int b = ((uchar *) (img-> imageData + h * img-> widthStep)) [w * img-> nChannels + 0]; // B ((float *) (img2-> imageData + h * img2-> widthStep)) [w * img2-> nChannels + 0] = ((float) b)/255.0; – sgielen

2

flotantes colores puntuales van de 0,0 a 1,0, y uchars van de 0 a 255. El siguiente código lo fija:

// h is height, w is width, c is current channel (0 to 2) 
int b = ((uchar *)(img->imageData + h*img->widthStep))[w*img->nChannels + c]; 
((float *)(img2->imageData + h*img2->widthStep))[w*img2->nChannels + c] = ((float)b)/255.0; 

Muchas, muchas gracias a Stefan Schmidt para ayudar a solucionar este!

28

La función que está buscando es cvConvertScale(). Automáticamente hace cualquier tipo de conversión para usted. Solo tiene que especificar que desea escalar por un factor de 1/255 (que mapea el rango [0 ... 255] a [0 ... 1]).

Ejemplo:

IplImage *im8 = cvLoadImage(argv[1]); 
IplImage *im32 = cvCreateImage(cvSize(im8->width, im8->height), 32, 3); 

cvConvertScale(im8, im32, 1/255.); 

Nota el punto en 1/255. - para forzar un doble división. Sin él obtendrá una escala de 0.

+0

Lo intenté, pero no aceptó ni la salida ni la escala de entrada. O tal vez lo utilicé incorrectamente. – sgielen

+11

Es importante que pase un doble como factor de escala (por lo que hay '.' Detrás de 255). 1/255 se evaluaría como división entera y conduciría a un factor de escala de 0. ¿Cuál es exactamente el código que no funcionó con cvConvertScale()? – Martin

+1

Ojalá pudiera poner más votos positivos, he votado a favor y en contra también su respuesta. He estado luchando en esto durante al menos 8 horas maldita sea! – Eric

1

Si no coloca el punto (.), Algunos compiladores lo entenderán como una división int, que le da un resultado int (cero en este caso).

1

Puede crear un contenedor IplImage utilizando boost :: shared_ptr y template-metaprogramming. Lo he hecho y obtengo recolección de basura automática, junto con conversiones de imagen automáticas de una profundidad a otra, o de imágenes de un canal a multicanal.

que he llamado el blImageAPI activos y de productos que se pueden encontrar aquí: http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/

Es muy rápido, y crea un código muy legible, (bueno para los algoritmos de mantenimiento)

Es también puede ser utilizado en lugar de IplImage en algoritmos opencv sin cambiar nada.

¡Buena suerte y diviértete escribiendo algoritmos!

0

IplImage * img8, * img32;
img8 = cvLoadImage ("a.jpg", 1);

cvNamedWindow("Convert",1); 
    img32 = cvCreateImage(cvGetSize(img8),IPL_DEPTH_32F,3); 
    cvConvertScale(img8,img32,1.0/255.0,0.0); 

// Para la Confirmación Compruebe los valores de los píxeles (de 0 - 1)

for(int row = 0; row < img32->height; row++){ 
       float* pt = (float*) (img32->imageData + row * img32->widthStep); 
       for (int col = 0; col < width; col++) 
          printf("\n %3.3f , %3.3f , %3.3f ",pt[3*col],pt[3*col+1],pt[3*col+2]);     
      } 

    cvShowImage("Convert",img32); 
    cvWaitKey(0); 
    cvReleaseImage(&img8); 
    cvReleaseImage(&img32); 
    cvDestroyWindow("Convert"); 
Cuestiones relacionadas