Go to the source code of this file.
Functions | |
QImage * | oilPaintingEffect (QString filename, ManipulationOptions *options) |
QImage* oilPaintingEffect | ( | QString | filename, | |
ManipulationOptions * | options | |||
) |
Definition at line 103 of file painting.cpp.
References Triplet::b, editedImage, findHighestCounts(), Triplet::g, ManipulationOptions::getStatus(), Histogram::highestCountIndex, StatusWidget::incrementProgress(), newProgress, Triplet::r, resetHistogram(), StatusWidget::showProgressBar(), status, updateIncrement, and Histogram::values.
Referenced by EditingInterface::applyEffect().
00104 { 00105 //load original image 00106 QImage originalImage( filename ); 00107 00108 //convert to 32-bit depth if necessary 00109 if( originalImage.depth() < 32 ) { originalImage = originalImage.convertDepth( 32, Qt::AutoColor ); } 00110 00111 //determine if busy indicators will be used 00112 bool useBusyIndicators = false; 00113 StatusWidget* status = NULL; 00114 if( options != NULL && options->getStatus() != NULL ) 00115 { 00116 useBusyIndicators = true; 00117 status = options->getStatus(); 00118 } 00119 00120 //setup progress bar 00121 if(useBusyIndicators) 00122 { 00123 QString statusMessage = qApp->translate( "oilPaintingEffect", "Applying Oil Painting Effect:" ); 00124 status->showProgressBar( statusMessage, 100 ); 00125 qApp->processEvents(); 00126 } 00127 00128 //update progress bar for every 1% of completion 00129 const int updateIncrement = (int) ( 0.01 * originalImage.width() * originalImage.height() ); 00130 int newProgress = 0; 00131 00132 //construct edited image 00133 QImage* editedImage = new QImage( filename ); 00134 00135 //convert to 32-bit depth if necessary 00136 if( editedImage->depth() < 32 ) 00137 { 00138 QImage* tmp = editedImage; 00139 editedImage = new QImage( tmp->convertDepth( 32, Qt::AutoColor ) ); 00140 delete tmp; tmp=NULL; 00141 } 00142 00143 //compute the radius using image resolution 00144 double minDimen = (double) QMIN( editedImage->width(), editedImage->height() ); 00145 const int RADIUS = (int) QMAX( 2, (sqrt(minDimen)/4) ); 00146 00147 //iterate over image 00148 int originalImageX, originalImageY; 00149 int editedImageX, editedImageY; 00150 int clampedX, clampedY; 00151 int trailingEdgeY, leadingEdgeY; 00152 00153 QRgb* rgb; 00154 uchar* scanLine; 00155 uchar* trailingScanLine; 00156 uchar* leadingScanLine; 00157 00158 //iterate over columns 00159 for( editedImageX=0; editedImageX < editedImage->width(); editedImageX++) 00160 { 00161 //------------------ 00162 //reset histogram object 00163 resetHistogram(); 00164 //------------------ 00165 //fill histogram with data that would have results from Y=-1 00166 for(originalImageY = 0 - 1 - RADIUS; 00167 originalImageY <= 0 - 1 + RADIUS; 00168 originalImageY++) 00169 { 00170 clampedY = QMAX( QMIN( originalImageY, originalImage.height() - 1 ), 0 ); 00171 scanLine = originalImage.scanLine( clampedY ); 00172 00173 for(originalImageX = editedImageX - RADIUS; 00174 originalImageX <= editedImageX + RADIUS; 00175 originalImageX++) 00176 { 00177 clampedX = QMAX( QMIN( originalImageX, originalImage.width() - 1 ), 0 ); 00178 00179 //get rgb value 00180 rgb = ((QRgb*)scanLine+clampedX); 00181 00182 //update counts for this r/g/b value 00183 histogram.values[ qRed(*rgb) ].r++; 00184 histogram.values[ qGreen(*rgb) ].g++; 00185 histogram.values[ qBlue(*rgb) ].b++; 00186 } //originalX 00187 } //originalY 00188 //------------------ 00189 00190 //now iterate over rows by simply removing trailing edge data and adding leading edge data 00191 for( editedImageY=0; editedImageY < editedImage->height(); editedImageY++) 00192 { 00193 trailingEdgeY = QMAX( QMIN( editedImageY-1-RADIUS, originalImage.height() - 1 ), 0 ); 00194 leadingEdgeY = QMAX( QMIN( editedImageY+RADIUS, originalImage.height() - 1 ), 0 ); 00195 00196 trailingScanLine = originalImage.scanLine( trailingEdgeY ); 00197 leadingScanLine = originalImage.scanLine( leadingEdgeY ); 00198 00199 for(originalImageX = editedImageX - RADIUS; 00200 originalImageX <= editedImageX + RADIUS; 00201 originalImageX++) 00202 { 00203 clampedX = QMAX( QMIN( originalImageX, originalImage.width() - 1 ), 0 ); 00204 00205 //remove trail edge data 00206 rgb = ((QRgb*)trailingScanLine+clampedX); 00207 histogram.values[ qRed(*rgb) ].r--; 00208 histogram.values[ qGreen(*rgb) ].g--; 00209 histogram.values[ qBlue(*rgb) ].b--; 00210 00211 //add leading edge data 00212 rgb = ((QRgb*)leadingScanLine+clampedX); 00213 histogram.values[ qRed(*rgb) ].r++; 00214 histogram.values[ qGreen(*rgb) ].g++; 00215 histogram.values[ qBlue(*rgb) ].b++; 00216 } //originalX 00217 00218 //find highest color counts 00219 findHighestCounts(); 00220 00221 //replace each color channel value with average of 00222 //current value and most occuring value within neighborhood 00223 scanLine = editedImage->scanLine( editedImageY ); 00224 rgb = ((QRgb*)scanLine+editedImageX); 00225 *rgb = qRgb( (qRed(*rgb) + histogram.highestCountIndex.r) / 2, 00226 (qGreen(*rgb) + histogram.highestCountIndex.g) / 2, 00227 (qBlue(*rgb) + histogram.highestCountIndex.b) / 2 ); 00228 00229 00230 //update status bar if significant progress has been made since last update 00231 if(useBusyIndicators) 00232 { 00233 newProgress++; 00234 if(newProgress >= updateIncrement) 00235 { 00236 newProgress = 0; 00237 status->incrementProgress(); 00238 qApp->processEvents(); 00239 } 00240 } 00241 00242 } //editedImageX 00243 } //editedImageY 00244 00245 //return pointer to edited image 00246 return editedImage; 00247 }