Das Thema ist ja schon öfters an diversen Orten diskutiert worden, und endete meist mit leichten Vorteilen für double Variablen (zumindest auf halbwegs moderner PC Hardware).
Bei meinem aktuellen Projekt konnte ich das weitgehend bestätigen. Es geht dabei um die Erzeugung kleiner Vorschaubilder für eine Anwendung, die das betreffende Bild nur in einem kleinen Fenster-Bereich anzeigen soll. Mein Toolkit (FLTK) verwendet dafür standardmäßig den Nearest-Neighbour Algorithmus, der zwar der absolut schnellste ist, allerdings bei Bildern mit technischen Zeichnungen oder schrägen Kanten, sehr schlechte Ergebnisse bring. Daher habe ich versucht etwas eigenes zu machen, was jetzt im Prinzip auch funktioniert.
Was mich dabei überrascht hat, ist die Tatsache, das ich trotzdem bei Verwendung von float's für die Bildung der Pixel Summen im Array sum[] (RGBA) einen leichten Geschwindigkeitsvorteil erzielen konnte, den ich mir noch nicht erklären kann (wir reden hier von 20 ms bei einer Gesamtzeit von ca. 600 ms). Bei der Verwendung von int's für das sum[] Array ist das Ergebnis übrigens nochmal um ca. 20 ms schlechter (bezogen immer auf das selbe Digitalfoto).
Woran liegt das?
Zum Verständnis hier mal ein (nicht ganz) kurzer Code Abschnitt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | // Downscale an image by averaging Fl_Image * MainWindow::down_scale( Fl_Shared_Image * simg, int w, int h ) { Fl_RGB_Image * new_image; const unsigned char * sp; // source pixel pointer unsigned char * dp; // destination pixel pointer unsigned char * t_array; // temporary pixel data, first run unsigned char * n_array; // new image pixel data array, second run //int sum[4]; // pixel sum for up to 4 channels float sum[4]; // pixel sum for up to 4 channels int depth = simg->d(); // must be 1 to 4 int s_width = simg->w(); // source image width int s_hight = simg->h(); // source image hight double x_size = (double)s_width / (double)w; double x_wight = 1.0 / x_size; double y_size = (double)s_hight / (double)h; double y_wight = 1.0 / y_size; double delta; double pxfract; // fractional pixel factor int i, l; if( depth < 1 || depth > 4 || simg->ld() != 0 || simg->count() != 1 ) { ... return NULL; } // horizontal scaling t_array = new unsigned char [w * s_hight * depth]; dp = t_array; sp = (const unsigned char *)simg->data()[0]; // pointer to pixel array for( l = 0; l < s_hight; l++ ) { delta = 0.0; sum[0] = sum[1] = sum[2] = sum[3] = 0; for( i = 0; i < s_width; i++ ) { delta += 1.0; if( delta < x_size && i < s_width-1 ) { for( int c = 0; c < depth; c++ ) sum[c] += *sp++; // add whole pixel to scaled pixel } else { // split the pixel delta -= x_size; pxfract = 1.0 - delta; for( int c = 0; c < depth; c++) { // for all cannels ... <<< sum[c] += *sp * pxfract; // left fraction <<< *dp++ = (unsigned char)((sum[c] * x_wight) + 0.499); <<< sum[c] = *sp++ * delta; // right fraction <<< } <<< } } } // vertical scaling ... new_image = new Fl_RGB_Image( n_array, w, h, depth ); delete [] t_array; return new_image; } |
Der hierfür relevante Bereich ist mit "<<<" gekennzeichnet.