• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDE Support
  • Sitemap
  • Contact Us
 

qimageblitz

histogram.cpp

Go to the documentation of this file.
00001 /* 
00002  Copyright (C) 1998, 1999, 2001, 2002, 2004, 2005, 2007
00003       Daniel M. Duley <daniel.duley@verizon.net>
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions
00007 are met:
00008 
00009 1. Redistributions of source code must retain the above copyright
00010    notice, this list of conditions and the following disclaimer.
00011 2. Redistributions in binary form must reproduce the above copyright
00012    notice, this list of conditions and the following disclaimer in the
00013    documentation and/or other materials provided with the distribution.
00014 
00015 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00017 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00018 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00019 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00020 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00021 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00022 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00023 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00024 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00025 
00026 */
00027 
00028 /*
00029  Portions of this software are were originally based on ImageMagick's
00030  algorithms. ImageMagick is copyrighted under the following conditions:
00031 
00032 Copyright (C) 2003 ImageMagick Studio, a non-profit organization dedicated to
00033 making software imaging solutions freely available.
00034 
00035 Permission is hereby granted, free of charge, to any person obtaining a copy
00036 of this software and associated documentation files ("ImageMagick"), to deal
00037 in ImageMagick without restriction, including without limitation the rights
00038 to use, copy, modify, merge, publish, distribute, sublicense,  and/or sell
00039 copies of ImageMagick, and to permit persons to whom the ImageMagick is
00040 furnished to do so, subject to the following conditions:
00041 
00042 The above copyright notice and this permission notice shall be included in all
00043 copies or substantial portions of ImageMagick.
00044 
00045 The software is provided "as is", without warranty of any kind, express or
00046 implied, including but not limited to the warranties of merchantability,
00047 fitness for a particular purpose and noninfringement.  In no event shall
00048 ImageMagick Studio be liable for any claim, damages or other liability,
00049 whether in an action of contract, tort or otherwise, arising from, out of or
00050 in connection with ImageMagick or the use or other dealings in ImageMagick.
00051 
00052 Except as contained in this notice, the name of the ImageMagick Studio shall
00053 not be used in advertising or otherwise to promote the sale, use or other
00054 dealings in ImageMagick without prior written authorization from the
00055 ImageMagick Studio.
00056 */
00057 
00058 
00059 #include "qimageblitz.h"
00060 #include "private/blitz_p.h"
00061 #include <QString>
00062 #include <QVector>
00063 
00064 // These are used as accumulators
00065 
00066 typedef struct
00067 {
00068     quint32 red, green, blue, alpha;
00069 } IntegerPixel;
00070 
00071 typedef struct
00072 {
00073     quint16 red, green, blue, alpha;
00074 } ShortPixel;
00075 
00076 typedef struct
00077 {
00078     // Yes, a normal pixel can be used instead but this is easier to read
00079     // and no shifts to get components.
00080     quint8 red, green, blue, alpha;
00081 } CharPixel;
00082 
00083 typedef struct
00084 {
00085     quint32 red, green, blue, alpha;
00086 } HistogramListItem;
00087 
00088 
00089 bool Blitz::equalize(QImage &img)
00090 {
00091     if(img.isNull())
00092         return(false);
00093 
00094     HistogramListItem *histogram;
00095     IntegerPixel *map;
00096     IntegerPixel intensity, high, low;
00097     CharPixel *equalize_map;
00098     int i, count;
00099     QRgb pixel, *dest;
00100     unsigned char r, g, b;
00101 
00102     if(img.depth() < 32){
00103         img = img.convertToFormat(img.hasAlphaChannel() ?
00104                                   QImage::Format_ARGB32 :
00105                                   QImage::Format_RGB32);
00106     }
00107     count = img.width()*img.height();
00108 
00109     map = new IntegerPixel[256];
00110     histogram = new HistogramListItem[256];
00111     equalize_map = new CharPixel[256];
00112 
00113     // form histogram
00114     memset(histogram, 0, 256*sizeof(HistogramListItem));
00115     dest = (QRgb *)img.bits();
00116 
00117     if(img.format() == QImage::Format_ARGB32_Premultiplied){
00118         for(i=0; i < count; ++i, ++dest){
00119             pixel = BlitzPrivate::convertFromPremult(*dest);
00120             histogram[qRed(pixel)].red++;
00121             histogram[qGreen(pixel)].green++;
00122             histogram[qBlue(pixel)].blue++;
00123             histogram[qAlpha(pixel)].alpha++;
00124         }
00125     }
00126     else{
00127         for(i=0; i < count; ++i){
00128             pixel = *dest++;
00129             histogram[qRed(pixel)].red++;
00130             histogram[qGreen(pixel)].green++;
00131             histogram[qBlue(pixel)].blue++;
00132             histogram[qAlpha(pixel)].alpha++;
00133         }
00134     }
00135 
00136     // integrate the histogram to get the equalization map
00137     memset(&intensity, 0, sizeof(IntegerPixel));
00138     for(i=0; i < 256; ++i){
00139         intensity.red += histogram[i].red;
00140         intensity.green += histogram[i].green;
00141         intensity.blue += histogram[i].blue;
00142         map[i] = intensity;
00143     }
00144 
00145     low = map[0];
00146     high = map[255];
00147     memset(equalize_map, 0, 256*sizeof(CharPixel));
00148     for(i=0; i < 256; ++i){
00149         if(high.red != low.red)
00150             equalize_map[i].red=(unsigned char)
00151                 ((255*(map[i].red-low.red))/(high.red-low.red));
00152         if(high.green != low.green)
00153             equalize_map[i].green=(unsigned char)
00154                 ((255*(map[i].green-low.green))/(high.green-low.green));
00155         if(high.blue != low.blue)
00156             equalize_map[i].blue=(unsigned char)
00157                 ((255*(map[i].blue-low.blue))/(high.blue-low.blue));
00158     }
00159 
00160     // stretch the histogram and write
00161     dest = (QRgb *)img.bits();
00162     if(img.format() == QImage::Format_ARGB32_Premultiplied){
00163         for(i=0; i < count; ++i, ++dest){
00164             pixel = BlitzPrivate::convertFromPremult(*dest);
00165             r = (low.red != high.red) ? equalize_map[qRed(pixel)].red :
00166                 qRed(pixel);
00167             g = (low.green != high.green) ? equalize_map[qGreen(pixel)].green :
00168                 qGreen(pixel);
00169             b = (low.blue != high.blue) ?  equalize_map[qBlue(pixel)].blue :
00170                 qBlue(pixel);
00171             *dest = BlitzPrivate::convertToPremult(qRgba(r, g, b, qAlpha(pixel)));
00172         }
00173     }
00174     else{
00175         for(i=0; i < count; ++i){
00176             pixel = *dest;
00177             r = (low.red != high.red) ? equalize_map[qRed(pixel)].red :
00178                 qRed(pixel);
00179             g = (low.green != high.green) ? equalize_map[qGreen(pixel)].green :
00180                 qGreen(pixel);
00181             b = (low.blue != high.blue) ?  equalize_map[qBlue(pixel)].blue :
00182                 qBlue(pixel);
00183             *dest++ = qRgba(r, g, b, qAlpha(pixel));
00184         }
00185     }
00186 
00187     delete[] histogram;
00188     delete[] map;
00189     delete[] equalize_map;
00190     return(true);
00191 }
00192 
00193 bool Blitz::normalize(QImage &img)
00194 {
00195     if(img.isNull())
00196         return(false);
00197 
00198     IntegerPixel intensity;
00199     HistogramListItem *histogram;
00200     CharPixel *normalize_map;
00201     ShortPixel high, low;
00202 
00203     uint threshold_intensity;
00204     int i, count;
00205     QRgb pixel, *dest;
00206     unsigned char r, g, b;
00207 
00208     if(img.depth() < 32){
00209         img = img.convertToFormat(img.hasAlphaChannel() ?
00210                                   QImage::Format_ARGB32 :
00211                                   QImage::Format_RGB32);
00212     }
00213     count = img.width()*img.height();
00214 
00215     histogram = new HistogramListItem[256];
00216     normalize_map = new CharPixel[256];
00217 
00218     // form histogram
00219     memset(histogram, 0, 256*sizeof(HistogramListItem));
00220     dest = (QRgb *)img.bits();
00221 
00222     if(img.format() == QImage::Format_ARGB32_Premultiplied){
00223         for(i=0; i < count; ++i, ++dest){
00224             pixel = BlitzPrivate::convertFromPremult(*dest);
00225             histogram[qRed(pixel)].red++;
00226             histogram[qGreen(pixel)].green++;
00227             histogram[qBlue(pixel)].blue++;
00228             histogram[qAlpha(pixel)].alpha++;
00229         }
00230     }
00231     else{
00232         for(i=0; i < count; ++i){
00233             pixel = *dest++;
00234             histogram[qRed(pixel)].red++;
00235             histogram[qGreen(pixel)].green++;
00236             histogram[qBlue(pixel)].blue++;
00237             histogram[qAlpha(pixel)].alpha++;
00238         }
00239     }
00240 
00241     // find the histogram boundaries by locating the .01 percent levels.
00242     threshold_intensity = count/1000;
00243 
00244     memset(&intensity, 0, sizeof(IntegerPixel));
00245     for(low.red=0; low.red < 256; ++low.red){
00246         intensity.red += histogram[low.red].red;
00247         if(intensity.red > threshold_intensity)
00248             break;
00249     }
00250     memset(&intensity, 0, sizeof(IntegerPixel));
00251     for(high.red=255; high.red >= 0; --high.red){
00252         intensity.red += histogram[high.red].red;
00253         if(intensity.red > threshold_intensity)
00254             break;
00255     }
00256     memset(&intensity, 0, sizeof(IntegerPixel));
00257     for(low.green=low.red; low.green < high.red; ++low.green){
00258         intensity.green += histogram[low.green].green;
00259         if(intensity.green > threshold_intensity)
00260             break;
00261     }
00262     memset(&intensity, 0, sizeof(IntegerPixel));
00263     for(high.green=high.red; high.green != low.red; --high.green){
00264         intensity.green += histogram[high.green].green;
00265         if(intensity.green > threshold_intensity)
00266             break;
00267     }
00268     memset(&intensity, 0, sizeof(IntegerPixel));
00269     for(low.blue=low.green; low.blue < high.green; ++low.blue){
00270         intensity.blue += histogram[low.blue].blue;
00271         if(intensity.blue > threshold_intensity)
00272             break;
00273     }
00274     memset(&intensity, 0, sizeof(IntegerPixel));
00275     for(high.blue=high.green; high.blue != low.green; --high.blue){
00276         intensity.blue += histogram[high.blue].blue;
00277         if(intensity.blue > threshold_intensity)
00278             break;
00279     }
00280 
00281     delete[] histogram;
00282 
00283     // stretch the histogram to create the normalized image mapping.
00284     for(i=0; i < 256; i++){
00285         if(i < low.red)
00286             normalize_map[i].red = 0;
00287         else{
00288             if(i > high.red)
00289                 normalize_map[i].red = 255;
00290             else if(low.red != high.red)
00291                 normalize_map[i].red = (255*(i-low.red))/
00292                     (high.red-low.red);
00293         }
00294 
00295         if(i < low.green)
00296             normalize_map[i].green = 0;
00297         else{
00298             if(i > high.green)
00299                 normalize_map[i].green = 255;
00300             else if(low.green != high.green)
00301                 normalize_map[i].green = (255*(i-low.green))/
00302                     (high.green-low.green);
00303         }
00304 
00305         if(i < low.blue)
00306             normalize_map[i].blue = 0;
00307         else{
00308             if(i > high.blue)
00309                 normalize_map[i].blue = 255;
00310             else if(low.blue != high.blue)
00311                 normalize_map[i].blue = (255*(i-low.blue))/
00312                     (high.blue-low.blue);
00313         }
00314     }
00315 
00316     // write
00317     dest = (QRgb *)img.bits();
00318     if(img.format() == QImage::Format_ARGB32_Premultiplied){
00319         for(i=0; i < count; ++i, ++dest){
00320             pixel = BlitzPrivate::convertFromPremult(*dest);
00321             r = (low.red != high.red) ? normalize_map[qRed(pixel)].red :
00322                 qRed(pixel);
00323             g = (low.green != high.green) ? normalize_map[qGreen(pixel)].green :
00324                 qGreen(pixel);
00325             b = (low.blue != high.blue) ?  normalize_map[qBlue(pixel)].blue :
00326                 qBlue(pixel);
00327             *dest = BlitzPrivate::convertToPremult(qRgba(r, g, b, qAlpha(pixel)));
00328         }
00329     }
00330     else{
00331         for(i=0; i < count; ++i){
00332             pixel = *dest;
00333             r = (low.red != high.red) ? normalize_map[qRed(pixel)].red :
00334                 qRed(pixel);
00335             g = (low.green != high.green) ? normalize_map[qGreen(pixel)].green :
00336                 qGreen(pixel);
00337             b = (low.blue != high.blue) ?  normalize_map[qBlue(pixel)].blue :
00338                 qBlue(pixel);
00339             *dest++ = qRgba(r, g, b, qAlpha(pixel));
00340         }
00341     }
00342 
00343     delete[] normalize_map;
00344     return(true);
00345 }
00346 
00347 QImage Blitz::oilPaint(QImage &img, float radius,
00348                        EffectQuality quality)
00349 {
00350     int matrix_size = BlitzPrivate::defaultConvolveMatrixSize(radius, 0.5,
00351                                                               quality == High);
00352     int i, x, y, w, h, matrix_x, matrix_y;
00353     int edge = matrix_size/2;
00354     unsigned int max, value;
00355     QRgb *dest, *src, *s, **scanblock;
00356 
00357     w = img.width();
00358     h = img.height();
00359     if(w < 3 || h < 3){
00360         qWarning("Blitz::oilPaint(): Image is too small!");
00361         return(img);
00362     }
00363 
00364     if(img.format() == QImage::Format_ARGB32_Premultiplied)
00365         img = img.convertToFormat(QImage::Format_ARGB32);
00366     else if(img.depth() < 32){
00367         img = img.convertToFormat(img.hasAlphaChannel() ?
00368                                   QImage::Format_ARGB32 :
00369                                   QImage::Format_RGB32);
00370     }
00371     QImage buffer(w, h, img.format());
00372 
00373     scanblock = new QRgb* [matrix_size];
00374     unsigned int *histogram = new unsigned int[256];
00375 
00376     for(y=0; y < h; ++y){
00377         src = (QRgb *)img.scanLine(y);
00378         dest = (QRgb *)buffer.scanLine(y);
00379         // Read in scanlines to pixel neighborhood. If the scanline is outside
00380         // the image use the top or bottom edge.
00381         for(x=y-edge, i=0; x <= y+edge; ++i, ++x){
00382             scanblock[i] = (QRgb *)
00383                 img.scanLine((x < 0) ? 0 : (x > h-1) ? h-1 : x);
00384         }
00385 
00386         // Now we are about to start processing scanlines. First handle the
00387         // part where the pixel neighborhood extends off the left edge.
00388         for(x=0; x-edge < 0 ; ++x){
00389             (void)memset(histogram, 0, 256*sizeof(unsigned int));
00390             max = 0;
00391             for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
00392                 s = scanblock[matrix_y];
00393                 matrix_x = -edge;
00394                 while(x+matrix_x < 0){
00395                     value = qGray(*s);
00396                     histogram[value]++;
00397                     if(histogram[value] > max){
00398                         max = histogram[value];
00399                         *dest = *s;
00400                     }
00401                     ++matrix_x;
00402                 }
00403                 while(matrix_x <= edge){
00404                     value = qGray(*s);
00405                     histogram[value]++;
00406                     if(histogram[value] > max){
00407                         max = histogram[value];
00408                         *dest = *s;
00409                     }
00410                     ++matrix_x; ++s;
00411                 }
00412             }
00413             ++dest;
00414         }
00415 
00416         // Okay, now process the middle part where the entire neighborhood
00417         // is on the image.
00418         for(; x+edge < w; ++x){
00419             (void)memset(histogram, 0, 256*sizeof(unsigned int));
00420             max = 0;
00421             for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
00422                 s = scanblock[matrix_y] + (x-edge);
00423                 for(matrix_x = -edge; matrix_x <= edge; ++matrix_x, ++s){
00424                     value = qGray(*s);
00425                     histogram[value]++;
00426                     if(histogram[value] > max){
00427                         max = histogram[value];
00428                         *dest = *s;
00429                     }
00430                 }
00431             }
00432             ++dest;
00433         }
00434 
00435         // Finally process the right part where the neighborhood extends off
00436         // the right edge of the image
00437         for(; x < w; ++x){
00438             (void)memset(histogram, 0, 256*sizeof(unsigned int));
00439             max = 0;
00440             for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
00441                 s = scanblock[matrix_y];
00442                 s += x-edge;
00443                 matrix_x = -edge;
00444                 while(x+matrix_x < w){
00445                     value = qGray(*s);
00446                     histogram[value]++;
00447                     if(histogram[value] > max){
00448                         max = histogram[value];
00449                         *dest = *s;
00450                     }
00451                     ++matrix_x, ++s;
00452                 }
00453                 --s;
00454                 while(matrix_x <= edge){
00455                     value = qGray(*s);
00456                     histogram[value]++;
00457                     if(histogram[value] > max){
00458                         max = histogram[value];
00459                         *dest = *s;
00460                     }
00461                     ++matrix_x;
00462                 }
00463             }
00464             ++dest;
00465         }
00466     }
00467 
00468     delete[] histogram;
00469     delete[] scanblock;
00470     return(buffer);
00471 }
00472 

qimageblitz

Skip menu "qimageblitz"
  • Main Page
  • Namespace List
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

KDE Support

Skip menu "KDE Support"
  • akonadi
  • Decibel
  • grantlee
  • kdewin
  • phonon
  •     Backend
  • polkit-qt
  • qca
  • qimageblitz
  • soprano
  • strigi
  •     searchclient
  •     streamanalyzer
  •     streams
Generated for KDE Support by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal