2008-12-27 17 views
11

Ich muss ein 8-Bit IplImage in ein 32-Bit IplImage konvertieren. Mit der Dokumentation aus dem ganzen Web ich folgende Dinge ausprobiert habe:Wie konvertiert man ein 8-Bit OpenCV IplImage * in ein 32-Bit IplImage *?

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

Wie Sie sehen, ich weiß wirklich nicht, was ich tue. Ich würde es gerne herausfinden, aber ich würde es mehr lieben, wenn ich das richtig machen könnte. Danke für jede Hilfe, die ich bekomme!

Antwort

6

Vielleicht kann diese link Ihnen helfen?

bearbeiten Als Antwort auf die zweite Bearbeitung der OP und der Kommentar

Sie

float value = 0.5

statt

float value = 0x0000001;

versucht haben, dachte ich, den Bereich für einen Float-Farbwert geht von 0,0 bis 1,0, wh Ere 1.0 ist weiß.

+0

Dort auf dieser Seite, Teile des Codes einige interessante Informationen ist, die erklären, was ich habe bereits versucht, aber die Ergebnisse sind die gleichen. Bitte beachten Sie den folgenden Link für ein Beispiel für das, was schief geht: http://files.dazjorz.com/cache/conversion.png – sgielen

+0

whoa, ja, das ist ein Nun, das ist der richtige Hinweis: Für die roten Punkte ist R 1.0 und GB 0.0, und für das Weiß sind alle drei 1.0, also beim Konvertieren die RGB-Werte d wird von 0 bis 255 auf 0,0 bis 1,0 umgerechnet. Wenn Sie den Wert auf b/255 ändern, wird das Bild schwarz + rot. – sgielen

+0

Verstanden! int b = ((uchar *) (img-> imageData + h * img-> widthStep)) [w * img-> nKanäle + 0]; // B ((float *) (img2-> imageData + h * img2-> breiteStep)) [w * img2-> nKanäle + 0] = ((float) b)/255.0; – sgielen

2

Gleitkomma-Farben von 0,0 bis 1,0 gehen, und uchars geht von 0 bis 255. Der folgende Code behebt es:

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

Vielen, vielen Dank an Stefan Schmidt für die Hilfe dieses Problem zu beheben!

28

Die Funktion, nach der Sie suchen, ist cvConvertScale(). Es macht automatisch jede Art von Konvertierung für Sie. Sie müssen nur angeben, dass Sie um den Faktor 1/255 skalieren möchten (wodurch der Bereich [0 ... 255] auf [0 ... 1] abgebildet wird).

Beispiel:

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

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

Hinweis der Punkt in 1/255. - eine doppelte Teilung zu erzwingen. Ohne es erhalten Sie eine Skala von 0.

+0

Ich habe das versucht, aber es hat weder die Ausgabe noch die Eingabeskala akzeptiert. Oder vielleicht habe ich es einfach falsch benutzt. – sgielen

+11

Es ist wichtig, dass Sie einen doppelten Skalierungsfaktor übergeben (deshalb gibt es hinter der 255 '.'). 1/255 würde als Ganzzahldivision ausgewertet werden und zu einem Skalierungsfaktor von 0 führen. Was genau ist Ihr Code, der nicht mit cvConvertScale() funktioniert? – Martin

+1

Ich wünschte, ich könnte mehr upvotes, ich hob Ihren Kommentar und Ihre Antwort. Ich habe seit mindestens 8 Stunden damit zu kämpfen, verdammt noch mal! – Eric

1

Wenn Sie den Punkt (.) Nicht setzen, wird einige Compiler als eine int-Division verstehen, die Ihnen ein int-Ergebnis (Null in diesem Fall).

1

Sie können einen IplImage-Wrapper mit boost :: shared_ptr und template-metaprogramming erstellen. Ich habe das getan, und ich bekomme automatische Speicherbereinigung, zusammen mit automatischen Bildumwandlungen von einer Tiefe zu einer anderen oder von Einkanal- zu Mehrkanalbildern.

Ich habe die API blImageAPI genannt, und es ist hier zu finden: http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/

Es ist sehr schnell, und Code machen sehr gut lesbar, (gut für die Aufrechterhaltung der Algorithmen)

Es kann auch verwendet werden, anstelle von IplImage in opencv-Algorithmen, ohne etwas zu ändern.

Viel Glück und viel Spaß beim Schreiben von Algorithmen !!!

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

// Zur Bestätigung der Pixelwerte prüfen (von 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");