2008-12-27 21 views
11

J'ai besoin de convertir un IplImage de 8 bits en un IplImage de 32 bits. En utilisant la documentation de partout dans le web que j'ai essayé les choses suivantes:Comment convertir un IplImage * OpenCV 8 bits en un IplImage * 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. 

Comme vous le voyez, je ne sais pas vraiment ce que je fais. J'adorerais le savoir, mais je l'aimerais plus si je pouvais le faire correctement. Merci pour toute aide que je reçois!

Répondre

6

Peut-être que ce link peut vous aider?

Modifier En réponse à la deuxième édition de l'OP et le commentaire

Avez-vous essayé

float value = 0.5

au lieu de

float value = 0x0000001;

Je pensais que la gamme pour une valeur de couleur flottante va de 0,0 à 1,0, wh ere 1.0 est blanc.

+0

Il y a quelques informations intéressantes sur cette page, des morceaux de code qui expliquent ce que j'ai Les résultats sont les mêmes, cependant, s'il vous plaît voir le lien suivant pour un exemple de ce qui ne va pas tout le temps: http://files.dazjorz.com/cache/conversion.png – sgielen

+0

whoa, ouais, c'est un Donc, cela donne l'indice suivant: pour les points rouges, R est 1.0 et GB sont 0.0, et pour le blanc, tous les trois sont 1.0. Donc, tout en convertissant, les valeurs RVB devraient d être converti de 0 à 255 à 0,0 à 1,0. La modification de la valeur b/255 rend l'image noire + rouge. – sgielen

+0

J'ai compris! 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

couleurs à virgule flottante vont de 0,0 à 1,0, et uchars vont de 0 à 255. Le code suivant le fixe:

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

Un grand merci à Stefan Schmidt pour me aider à résoudre ce problème!

28

La fonction que vous recherchez est cvConvertScale(). Il fait automagiquement n'importe quelle conversion de type pour vous. Vous devez juste spécifier que vous voulez mettre à l'échelle par un facteur de 1/255 (qui mappe la plage [0 ... 255] à [0 ... 1]).

Exemple:

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

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

Notez le point dans 1/255. - pour forcer une double division. Sans cela vous obtenez une échelle de 0.

+0

J'ai essayé, mais il n'a pas accepté la sortie ou l'échelle d'entrée. Ou peut-être que je l'ai juste utilisé incorrectement. – sgielen

+11

Il est important que vous passiez un double comme facteur de mise à l'échelle (c'est pourquoi il y a '.' Derrière le 255). 1/255 évaluerait comme une division entière et conduirait à un facteur d'échelle de 0. Quel est exactement votre code qui n'a pas fonctionné avec cvConvertScale()? – Martin

+1

Je voudrais pouvoir mettre plus de votes upvotes, j'ai augmenté votre commentaire et votre réponse. J'ai lutté sur cela pendant au moins 8 heures goddammit! – Eric

1

Si vous ne mettez pas le point (.), Certains compilateurs comprendront comme une division int, vous donnant un résultat int (zéro dans ce cas).

1

Vous pouvez créer un wrapper IplImage en utilisant boost :: shared_ptr et template-metaprogramming. Je l'ai fait, et je récupère automatiquement les ordures, ainsi que les conversions d'images automatiques d'une profondeur à une autre, ou d'une image monocanal à multicanal.

J'ai appelé le blImageAPI API et il peut être trouvé ici: http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/

Il est très rapide, et rendre le code très lisible, (bon pour les algorithmes maintien)

Il est peut également être utilisé au lieu de IplImage dans les algorithmes opencv sans rien changer.

Bonne chance et amusez-vous à écrire des algorithmes !!!

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); 

// Pour la confirmation Vérifiez les valeurs de pixels (entre 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");