diff --git a/imageviewer-qt4.cpp b/imageviewer-qt4.cpp index 5f727af..a3af53d 100644 --- a/imageviewer-qt4.cpp +++ b/imageviewer-qt4.cpp @@ -45,9 +45,8 @@ * @brief ImageViewer::ImageViewer */ ImageViewer::ImageViewer() { - original_image = NULL; - image = NULL; - histogramm = NULL; + original = NULL; + working_copy = NULL; startLogging(); generateMainGui(); renewLogging(); @@ -66,44 +65,27 @@ ImageViewer::ImageViewer() { * @brief ImageViewer::initializeImage */ void ImageViewer::initializeImage() { - if(image==NULL) { + if(original->getImage() == NULL) { std::cout << "Error! No image provided!" << std::endl; return; } analyzeImage(); } -/** - * Uses simple weights to calculate intensity of a pixel. - * Using qRound() to reduce the error of the int cast. - * - * @brief ImageViewer::calcIntensity - */ -int ImageViewer::calcIntensity(int r, int g, int b) { - return (int) qRound(0.299*r + 0.587*g + 0.114*b); -} - /** * In case it is needed, convert the loaded image into grayscale. - * This is one of the only methods modifying original_image! + * This is the only method modifying the original image! * * @brief ImageViewer::convertToMonochrome */ void ImageViewer::convertToMonochrome() { - if(image!=NULL) { + if(original->getImage() != NULL) { logFile << "Converting image to monochrome..."; renewLogging(); - for(int x=0; xwidth(); x++) { - for(int y=0; yheight(); y++) { - int r,g,b; - QColor color = QColor::fromRgb(image->pixel(x, y)); - color.getRgb(&r,&g,&b); - int intensity = calcIntensity(r, g, b); - color = QColor::fromRgb(intensity, intensity, intensity); - image->setPixel(x, y, color.rgb()); - original_image->setPixel(x, y, color.rgb()); - } - } + + original->convertToMonochrome(); + working_copy->convertToMonochrome(); + updateImageDisplay(); logFile << "done." << std::endl; renewLogging(); @@ -115,9 +97,9 @@ void ImageViewer::convertToMonochrome() { * @brief ImageViewer::drawBlackLine */ void ImageViewer::drawBlackLine() { - if(image!=NULL) { - for(int i=0;iwidth(),image->height());i++) { - image->setPixel(i,i,0); + if(original->getImage() != NULL) { + for(int i=0;igetImage()->width(),working_copy->getImage()->height());i++) { + working_copy->getImage()->setPixel(i,i,0); } updateImageDisplay(); logFile << "Black line drawn." << std::endl; @@ -130,13 +112,13 @@ void ImageViewer::drawBlackLine() { * @brief ImageViewer::drawDiagonalCross */ void ImageViewer::drawDiagonalCross() { - if(image!=NULL) { + if(original->getImage() != NULL) { int color = QColor::fromHsl(120,255,125).rgb(); - int width = image->width(); - int height = image->height(); - for(int y=0; yheight(); y++) { - image->setPixel((1.0*y/height)*width,y,color); - image->setPixel((1.0-(1.0*y/height))*width,y,color); + int width = working_copy->getImage()->width(); + int height = working_copy->getImage()->height(); + for(int y=0; ygetImage()->height(); y++) { + working_copy->getImage()->setPixel((1.0*y/height)*width,y,color); + working_copy->getImage()->setPixel((1.0-(1.0*y/height))*width,y,color); } } updateImageDisplay(); @@ -160,17 +142,17 @@ void ImageViewer::drawRainbowCross() { * @param initialHue */ void ImageViewer::drawRainbowCross(int initialHue=0) { - if(image!=NULL) { + if(original->getImage() != NULL) { int h = initialHue; QColor myColor = QColor::fromHsl(h, 255, 125); - int image_width = image->width()-1; + int image_width = working_copy->getImage()->width()-1; int range = line_slider->value(); - if(range > image->width()-2) range = image->width()-2; - for(int i=0;iwidth(),image->height());i++) { + if(range > working_copy->getImage()->width()-2) range = working_copy->getImage()->width()-2; + for(int i=0;igetImage()->width(),working_copy->getImage()->height());i++) { int color = myColor.rgb(); for(int r=0; rsetPixel(i+r,i,color); - image->setPixel((image_width-i)-r,i,color); + working_copy->getImage()->setPixel(i+r,i,color); + working_copy->getImage()->setPixel((image_width-i)-r,i,color); } h++; if(h > 359) h = 0; @@ -201,107 +183,22 @@ void ImageViewer::acidTrippin() { * Analyze the image, get average luminance * Also fill grayscale_absolute_histogramm * - * TODO: Decouple this from the drawing of the histogramm - * (READ: Fuck, reanalyzing my image fucks up tools that work on histogramm data!) - * * @brief ImageViewer::analyzeImage */ void ImageViewer::analyzeImage() { - if(image!=NULL) { - //Zero existing histogramm data first - for(int i=0; i<256; i++) { - grayscale_absolute_histogramm[i] = 0; - grayscale_relative_histogramm[i] = 0; - } - + if(original->getImage() != NULL) { logFile << "Analyzing image ..."; renewLogging(); - for(int x=0; xwidth(); x++) { - for(int y=0; yheight(); y++) { - int r,g,b; - QColor color = QColor::fromRgb(image->pixel(x, y)); - color.getRgb(&r,&g,&b); - int intensity = calcIntensity(r, g, b); - grayscale_absolute_histogramm[intensity] += 1; - } - } - - int pixels = image->width()*image->height(); - for(int i=0; i<256; i++) { - grayscale_relative_histogramm[i] = (((double) grayscale_absolute_histogramm[i])/((double) pixels)); - } - + original->updateStatistics(); + working_copy->updateStatistics(); logFile << "done" << std::endl; renewLogging(); - - QString result = QString("Intensity: Average: %1, Variance: %2").arg(getAverageIntensity()).arg(getIntensityVariance()); + QString result = QString("Intensity: Average: %1, Variance: %2").arg(working_copy->getIntensityAverage()).arg(working_copy->getIntensityVariance()); stats->setText(result); - - updateHistogramm(); + histogramm_label->setPixmap(QPixmap::fromImage(*(working_copy->getHistogrammImage()))); } } -/** - * Use histogramm to retrieve the average intensity. - * @brief ImageViewer::getAverageIntensity - */ -int ImageViewer::getAverageIntensity() { - double sumIntensity = 0; - for(int i=0; i<256;i++) { - sumIntensity += (i*grayscale_relative_histogramm[i]); - } - return (int) qRound(sumIntensity); -} - -/** - * Retrieve the intensity variance from the image. - * @brief ImageViewer::getVarianceIntensity - */ -int ImageViewer::getIntensityVariance() { - int average_intensity = getAverageIntensity(); - int sumDifference = 0; - for(int x=0; xwidth(); x++) { - for(int y=0; yheight(); y++) { - QColor color = QColor::fromRgb(image->pixel(x, y)); - int r,g,b; - color.getRgb(&r,&g,&b); - int intensity = calcIntensity(r, g, b); - int diff = std::abs(intensity - average_intensity); - sumDifference += diff; - } - } - return (int) (sumDifference/(image->width()*image->height())); -} - -/** - * Builds up the image for the histogramm. - * @brief ImageViewer::updateHistogramm - */ -void ImageViewer::updateHistogramm() { - if(histogramm != NULL) { - delete histogramm; - histogramm = NULL; - } - //Find biggest value in histogramm data - double max = 0; - for(int i=0; i<256; i++) { - if(grayscale_relative_histogramm[i] > max) max = grayscale_relative_histogramm[i]; - } - - histogramm = new QImage(256, 100, QImage::Format_RGB32); - histogramm->fill(QColor::fromRgb(200,200,200)); - int black = QColor::fromRgb(0,0,0).rgb(); - for(int x=0; x<256; x++) { - int k_max = (int) qRound((100*grayscale_relative_histogramm[x])/max); - for(int y=0; ysetPixel(x, (100-y)-1, black); - } - } - logFile << "Histogramm done." << std::endl; - renewLogging(); - histogramm_label->setPixmap(QPixmap::fromImage(*histogramm)); -} - /** * Fired by the brightness_slider, this one adjusts the brightness on image. * @brief ImageViewer::adjustBrightness @@ -310,15 +207,15 @@ void ImageViewer::adjustBrightness(int b) { int h, s, old_l; int new_l = 0; int delta = b - 255; - for(int x=0; xwidth(); x++) { - for(int y=0; yheight(); y++) { - QColor color = QColor::fromRgb(original_image->pixel(x, y)); + for(int x=0; xgetImage()->width(); x++) { + for(int y=0; ygetImage()->height(); y++) { + QColor color = QColor::fromRgb(original->getImage()->pixel(x, y)); color.getHsl(&h, &s, &old_l); new_l = old_l + delta; if(new_l > 255) new_l = 255; if(new_l < 0) new_l = 0; color.setHsl(h, s, new_l); - image->setPixel(x, y, color.rgb()); + working_copy->getImage()->setPixel(x, y, color.rgb()); } } updateImageDisplay(); @@ -334,16 +231,16 @@ void ImageViewer::adjustContrast(int c) { int h, s, old_l; int new_l = 0; double alpha = c / 255.0; - int average_intensity = getAverageIntensity(); - for(int x=0; xwidth(); x++) { - for(int y=0; yheight(); y++) { - QColor color = QColor::fromRgb(original_image->pixel(x, y)); + int average_intensity = original->getIntensityAverage(); + for(int x=0; xgetImage()->width(); x++) { + for(int y=0; ygetImage()->height(); y++) { + QColor color = QColor::fromRgb(original->getImage()->pixel(x, y)); color.getHsl(&h, &s, &old_l); new_l = average_intensity + ((int) round((old_l - average_intensity) * alpha)); if(new_l > 255) new_l = 255; if(new_l < 0) new_l = 0; color.setHsl(h, s, new_l); - image->setPixel(x, y, color.rgb()); + working_copy->getImage()->setPixel(x, y, color.rgb()); } } updateImageDisplay(); @@ -366,6 +263,7 @@ void ImageViewer::robustAutomaticContrastAdaption(void) { int upper_border = -1; double limit = percentile / 100.0; double cursor = 0.0; + double* grayscale_relative_histogramm = original->getRelativeIntensityHistogramm(); for(int i=0; i<256; i++) { cursor += grayscale_relative_histogramm[i]; if(cursor >= limit && lower_border == -1) { @@ -383,9 +281,9 @@ void ImageViewer::robustAutomaticContrastAdaption(void) { renewLogging(); int h, s, l; - for(int x=0; xwidth(); x++) { - for(int y=0; yheight(); y++) { - QColor color = QColor::fromRgb(original_image->pixel(x, y)); + for(int x=0; xgetImage()->width(); x++) { + for(int y=0; ygetImage()->height(); y++) { + QColor color = QColor::fromRgb(original->getImage()->pixel(x, y)); color.getHsl(&h, &s, &l); if(l < lower_border) { @@ -397,7 +295,7 @@ void ImageViewer::robustAutomaticContrastAdaption(void) { } color.setHsl(h, s, l); - image->setPixel(x, y, color.rgb()); + working_copy->getImage()->setPixel(x, y, color.rgb()); } } updateImageDisplay(); @@ -512,7 +410,6 @@ void ImageViewer::generateControlPanels() { task_tab_widget3 = new QWidget(); task_tab3 = new QVBoxLayout(); task_tab_widget3->setLayout(task_tab3); - tabWidget->addTab(task_tab_widget3, "Task #3"); @@ -551,7 +448,7 @@ void ImageViewer::renewLogging() } void ImageViewer::updateImageDisplay() { - imageLabel->setPixmap(QPixmap::fromImage(*image)); + imageLabel->setPixmap(QPixmap::fromImage(*(working_copy->getImage()))); } @@ -611,19 +508,19 @@ void ImageViewer::print() { } void ImageViewer::open() { - if(image != NULL) { - delete image; - image = NULL; + if(working_copy != NULL) { + delete working_copy; + working_copy = NULL; } - if(original_image!=NULL) { - delete original_image; - original_image = NULL; + if(original != NULL) { + delete original; + original = NULL; } QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::currentPath()); if(!fileName.isEmpty()) { - image = new QImage(fileName); - original_image = new QImage(fileName); - if(image->isNull()) { + working_copy = new LazyImage(new QImage(fileName)); + original = new LazyImage(new QImage(fileName)); + if(working_copy->getImage()->isNull()) { QMessageBox::information(this, tr("Image Viewer"), tr("Cannot load %1.").arg(fileName)); return; } diff --git a/imageviewer-qt4.h b/imageviewer-qt4.h index dd2a069..f323c15 100644 --- a/imageviewer-qt4.h +++ b/imageviewer-qt4.h @@ -54,6 +54,8 @@ #include "fstream" #include +#include "lazy_image.cpp" + class QAction; class QLabel; class QMenu; @@ -101,10 +103,8 @@ class ImageViewer : public QMainWindow { QVBoxLayout* task_tab3; // "My" space for storing data/results - int grayscale_absolute_histogramm[256]; - double grayscale_relative_histogramm[256]; - QImage* histogramm; - QImage* original_image; + LazyImage* original; + LazyImage* working_copy; private slots: // Custom slots @@ -113,7 +113,6 @@ class ImageViewer : public QMainWindow { void drawDiagonalCross(); void acidTrippin(); void analyzeImage(); - void updateHistogramm(); void adjustBrightness(int b); void adjustContrast(int c); void convertToMonochrome(); @@ -160,7 +159,6 @@ class ImageViewer : public QMainWindow { QLabel* imageLabel; QScrollArea* scrollArea; double scaleFactor; - QImage* image; std::fstream logFile; diff --git a/lazy_image.cpp b/lazy_image.cpp new file mode 100644 index 0000000..1ce0dc8 --- /dev/null +++ b/lazy_image.cpp @@ -0,0 +1,166 @@ +#ifndef LAZY_IMAGE_C +#define LAZY_IMAGE_C + +#include +#include +#include + +#include + +#include + +class LazyImage { + + private: + QImage* img; //Not managed by us, just used. + QImage* histogramm_image; + double histogramm_relative_intensity[256]; + int histogramm_absolute_intensity[256]; + int intensity_average; + int intensity_variance; + + void gatherHistogrammData(void) { + // Zero existing histogramm data first + for(int i=0; i<256; i++) { + histogramm_relative_intensity[i] = 0; + histogramm_absolute_intensity[i] = 0; + } + // Count all the brightness values + for(int x=0; ximg->width(); x++) { + for(int y=0; yimg->height(); y++) { + int r,g,b; + QColor color = QColor::fromRgb(this->img->pixel(x, y)); + color.getRgb(&r,&g,&b); + int intensity = this->calcIntensity(r, g, b); + histogramm_absolute_intensity[intensity] += 1; + } + } + // Calculate relative histogramm + int pixels = this->img->width()*this->img->height(); + for(int i=0; i<256; i++) { + histogramm_relative_intensity[i] = (((double) histogramm_absolute_intensity[i])/((double) pixels)); + } + }; + + void calcIntensityAverage(void) { + double sum = 0; + for(int i=0; i<256;i++) { + sum += (i*histogramm_relative_intensity[i]); + } + this->intensity_average = (int) qRound(sum); + }; + + void calcIntensityVariance(void) { + int intensity_average = this->intensity_average; + int sum_difference = 0; + for(int x=0; ximg->width(); x++) { + for(int y=0; yimg->height(); y++) { + QColor color = QColor::fromRgb(this->img->pixel(x, y)); + int r,g,b; + color.getRgb(&r,&g,&b); + sum_difference += std::abs(this->calcIntensity(r, g, b) - intensity_average);; + } + } + this->intensity_variance = (int) qRound(sum_difference/(this->img->width()*this->img->height())); + }; + + void generateHistogrammImage(void) { + if(this->histogramm_image != NULL) { + delete this->histogramm_image; + this->histogramm_image = NULL; + } + //Find biggest value in histogramm data + double max = 0; + for(int i=0; i<256; i++) { + if(histogramm_relative_intensity[i] > max) max = histogramm_relative_intensity[i]; + } + + this->histogramm_image = new QImage(256, 100, QImage::Format_RGB32); + this->histogramm_image->fill(QColor::fromRgb(200,200,200)); + int black = QColor::fromRgb(0,0,0).rgb(); + for(int x=0; x<256; x++) { + int k_max = (int) qRound((100*histogramm_relative_intensity[x])/max); + for(int y=0; yhistogramm_image->setPixel(x, (100-y)-1, black); + } + } + }; + + + public: + LazyImage(QImage* img) { + this->histogramm_image = NULL; + this->setImage(img); + }; + + ~LazyImage() { + if(img != NULL) { + img = NULL; + } + }; + + void setImage(QImage* img) { + if(img != NULL) { + this->img = img; + this->updateStatistics(); + } + }; + + QImage* getImage(void) { + return this->img; + }; + + void updateStatistics(void) { + this->gatherHistogrammData(); + this->calcIntensityAverage(); + this->calcIntensityVariance(); + this->generateHistogrammImage(); + }; + + QImage* getHistogrammImage(void) { + return this->histogramm_image; + }; + + /** + * Uses simple weights to calculate intensity of a pixel. + * Using qRound() to reduce the error of the int cast. + * + * @brief LazyImage::calcIntensity + */ + int calcIntensity(int r, int g, int b) { + return (int) qRound(0.299*r + 0.587*g + 0.114*b); + }; + + int getIntensityAverage(void) { + return this->intensity_average; + } + + int getIntensityVariance(void) { + return this->intensity_variance; + }; + + int* getAbsoluteIntensityHistogramm(void) { + return this->histogramm_absolute_intensity; + }; + + double* getRelativeIntensityHistogramm(void) { + return this->histogramm_relative_intensity; + }; + + void convertToMonochrome(void) { + for(int x=0; ximg->width(); x++) { + for(int y=0; yimg->height(); y++) { + int r,g,b; + QColor color = QColor::fromRgb(this->img->pixel(x, y)); + color.getRgb(&r,&g,&b); + int intensity = this->calcIntensity(r, g, b); + color = QColor::fromRgb(intensity, intensity, intensity); + this->img->setPixel(x, y, color.rgb()); + } + } + }; + +}; + + +#endif