[TASK] Move most basic logic into lazy_image.cpp.

This commit is contained in:
Jan Philipp Timme 2015-11-13 14:38:15 +01:00
parent ef298dc322
commit 884c8ee7ae
3 changed files with 223 additions and 162 deletions

View File

@ -45,9 +45,8 @@
* @brief ImageViewer::ImageViewer * @brief ImageViewer::ImageViewer
*/ */
ImageViewer::ImageViewer() { ImageViewer::ImageViewer() {
original_image = NULL; original = NULL;
image = NULL; working_copy = NULL;
histogramm = NULL;
startLogging(); startLogging();
generateMainGui(); generateMainGui();
renewLogging(); renewLogging();
@ -66,44 +65,27 @@ ImageViewer::ImageViewer() {
* @brief ImageViewer::initializeImage * @brief ImageViewer::initializeImage
*/ */
void ImageViewer::initializeImage() { void ImageViewer::initializeImage() {
if(image==NULL) { if(original->getImage() == NULL) {
std::cout << "Error! No image provided!" << std::endl; std::cout << "Error! No image provided!" << std::endl;
return; return;
} }
analyzeImage(); 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. * 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 * @brief ImageViewer::convertToMonochrome
*/ */
void ImageViewer::convertToMonochrome() { void ImageViewer::convertToMonochrome() {
if(image!=NULL) { if(original->getImage() != NULL) {
logFile << "Converting image to monochrome..."; logFile << "Converting image to monochrome...";
renewLogging(); renewLogging();
for(int x=0; x<image->width(); x++) {
for(int y=0; y<image->height(); y++) { original->convertToMonochrome();
int r,g,b; working_copy->convertToMonochrome();
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());
}
}
updateImageDisplay(); updateImageDisplay();
logFile << "done." << std::endl; logFile << "done." << std::endl;
renewLogging(); renewLogging();
@ -115,9 +97,9 @@ void ImageViewer::convertToMonochrome() {
* @brief ImageViewer::drawBlackLine * @brief ImageViewer::drawBlackLine
*/ */
void ImageViewer::drawBlackLine() { void ImageViewer::drawBlackLine() {
if(image!=NULL) { if(original->getImage() != NULL) {
for(int i=0;i<std::min(image->width(),image->height());i++) { for(int i=0;i<std::min(working_copy->getImage()->width(),working_copy->getImage()->height());i++) {
image->setPixel(i,i,0); working_copy->getImage()->setPixel(i,i,0);
} }
updateImageDisplay(); updateImageDisplay();
logFile << "Black line drawn." << std::endl; logFile << "Black line drawn." << std::endl;
@ -130,13 +112,13 @@ void ImageViewer::drawBlackLine() {
* @brief ImageViewer::drawDiagonalCross * @brief ImageViewer::drawDiagonalCross
*/ */
void ImageViewer::drawDiagonalCross() { void ImageViewer::drawDiagonalCross() {
if(image!=NULL) { if(original->getImage() != NULL) {
int color = QColor::fromHsl(120,255,125).rgb(); int color = QColor::fromHsl(120,255,125).rgb();
int width = image->width(); int width = working_copy->getImage()->width();
int height = image->height(); int height = working_copy->getImage()->height();
for(int y=0; y<image->height(); y++) { for(int y=0; y<working_copy->getImage()->height(); y++) {
image->setPixel((1.0*y/height)*width,y,color); working_copy->getImage()->setPixel((1.0*y/height)*width,y,color);
image->setPixel((1.0-(1.0*y/height))*width,y,color); working_copy->getImage()->setPixel((1.0-(1.0*y/height))*width,y,color);
} }
} }
updateImageDisplay(); updateImageDisplay();
@ -160,17 +142,17 @@ void ImageViewer::drawRainbowCross() {
* @param initialHue * @param initialHue
*/ */
void ImageViewer::drawRainbowCross(int initialHue=0) { void ImageViewer::drawRainbowCross(int initialHue=0) {
if(image!=NULL) { if(original->getImage() != NULL) {
int h = initialHue; int h = initialHue;
QColor myColor = QColor::fromHsl(h, 255, 125); 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(); int range = line_slider->value();
if(range > image->width()-2) range = image->width()-2; if(range > working_copy->getImage()->width()-2) range = working_copy->getImage()->width()-2;
for(int i=0;i<std::min(image->width(),image->height());i++) { for(int i=0;i<std::min(working_copy->getImage()->width(),working_copy->getImage()->height());i++) {
int color = myColor.rgb(); int color = myColor.rgb();
for(int r=0; r<range; r++) { for(int r=0; r<range; r++) {
image->setPixel(i+r,i,color); working_copy->getImage()->setPixel(i+r,i,color);
image->setPixel((image_width-i)-r,i,color); working_copy->getImage()->setPixel((image_width-i)-r,i,color);
} }
h++; h++;
if(h > 359) h = 0; if(h > 359) h = 0;
@ -201,107 +183,22 @@ void ImageViewer::acidTrippin() {
* Analyze the image, get average luminance * Analyze the image, get average luminance
* Also fill grayscale_absolute_histogramm * 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 * @brief ImageViewer::analyzeImage
*/ */
void ImageViewer::analyzeImage() { void ImageViewer::analyzeImage() {
if(image!=NULL) { if(original->getImage() != NULL) {
//Zero existing histogramm data first
for(int i=0; i<256; i++) {
grayscale_absolute_histogramm[i] = 0;
grayscale_relative_histogramm[i] = 0;
}
logFile << "Analyzing image ..."; logFile << "Analyzing image ...";
renewLogging(); renewLogging();
for(int x=0; x<image->width(); x++) { original->updateStatistics();
for(int y=0; y<image->height(); y++) { working_copy->updateStatistics();
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));
}
logFile << "done" << std::endl; logFile << "done" << std::endl;
renewLogging(); renewLogging();
QString result = QString("Intensity: Average: %1, Variance: %2").arg(working_copy->getIntensityAverage()).arg(working_copy->getIntensityVariance());
QString result = QString("Intensity: Average: %1, Variance: %2").arg(getAverageIntensity()).arg(getIntensityVariance());
stats->setText(result); stats->setText(result);
histogramm_label->setPixmap(QPixmap::fromImage(*(working_copy->getHistogrammImage())));
updateHistogramm();
} }
} }
/**
* 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; x<image->width(); x++) {
for(int y=0; y<image->height(); 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; y<k_max; y++) {
histogramm->setPixel(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. * Fired by the brightness_slider, this one adjusts the brightness on image.
* @brief ImageViewer::adjustBrightness * @brief ImageViewer::adjustBrightness
@ -310,15 +207,15 @@ void ImageViewer::adjustBrightness(int b) {
int h, s, old_l; int h, s, old_l;
int new_l = 0; int new_l = 0;
int delta = b - 255; int delta = b - 255;
for(int x=0; x<image->width(); x++) { for(int x=0; x<working_copy->getImage()->width(); x++) {
for(int y=0; y<image->height(); y++) { for(int y=0; y<working_copy->getImage()->height(); y++) {
QColor color = QColor::fromRgb(original_image->pixel(x, y)); QColor color = QColor::fromRgb(original->getImage()->pixel(x, y));
color.getHsl(&h, &s, &old_l); color.getHsl(&h, &s, &old_l);
new_l = old_l + delta; new_l = old_l + delta;
if(new_l > 255) new_l = 255; if(new_l > 255) new_l = 255;
if(new_l < 0) new_l = 0; if(new_l < 0) new_l = 0;
color.setHsl(h, s, new_l); color.setHsl(h, s, new_l);
image->setPixel(x, y, color.rgb()); working_copy->getImage()->setPixel(x, y, color.rgb());
} }
} }
updateImageDisplay(); updateImageDisplay();
@ -334,16 +231,16 @@ void ImageViewer::adjustContrast(int c) {
int h, s, old_l; int h, s, old_l;
int new_l = 0; int new_l = 0;
double alpha = c / 255.0; double alpha = c / 255.0;
int average_intensity = getAverageIntensity(); int average_intensity = original->getIntensityAverage();
for(int x=0; x<image->width(); x++) { for(int x=0; x<working_copy->getImage()->width(); x++) {
for(int y=0; y<image->height(); y++) { for(int y=0; y<working_copy->getImage()->height(); y++) {
QColor color = QColor::fromRgb(original_image->pixel(x, y)); QColor color = QColor::fromRgb(original->getImage()->pixel(x, y));
color.getHsl(&h, &s, &old_l); color.getHsl(&h, &s, &old_l);
new_l = average_intensity + ((int) round((old_l - average_intensity) * alpha)); new_l = average_intensity + ((int) round((old_l - average_intensity) * alpha));
if(new_l > 255) new_l = 255; if(new_l > 255) new_l = 255;
if(new_l < 0) new_l = 0; if(new_l < 0) new_l = 0;
color.setHsl(h, s, new_l); color.setHsl(h, s, new_l);
image->setPixel(x, y, color.rgb()); working_copy->getImage()->setPixel(x, y, color.rgb());
} }
} }
updateImageDisplay(); updateImageDisplay();
@ -366,6 +263,7 @@ void ImageViewer::robustAutomaticContrastAdaption(void) {
int upper_border = -1; int upper_border = -1;
double limit = percentile / 100.0; double limit = percentile / 100.0;
double cursor = 0.0; double cursor = 0.0;
double* grayscale_relative_histogramm = original->getRelativeIntensityHistogramm();
for(int i=0; i<256; i++) { for(int i=0; i<256; i++) {
cursor += grayscale_relative_histogramm[i]; cursor += grayscale_relative_histogramm[i];
if(cursor >= limit && lower_border == -1) { if(cursor >= limit && lower_border == -1) {
@ -383,9 +281,9 @@ void ImageViewer::robustAutomaticContrastAdaption(void) {
renewLogging(); renewLogging();
int h, s, l; int h, s, l;
for(int x=0; x<image->width(); x++) { for(int x=0; x<working_copy->getImage()->width(); x++) {
for(int y=0; y<image->height(); y++) { for(int y=0; y<working_copy->getImage()->height(); y++) {
QColor color = QColor::fromRgb(original_image->pixel(x, y)); QColor color = QColor::fromRgb(original->getImage()->pixel(x, y));
color.getHsl(&h, &s, &l); color.getHsl(&h, &s, &l);
if(l < lower_border) { if(l < lower_border) {
@ -397,7 +295,7 @@ void ImageViewer::robustAutomaticContrastAdaption(void) {
} }
color.setHsl(h, s, l); color.setHsl(h, s, l);
image->setPixel(x, y, color.rgb()); working_copy->getImage()->setPixel(x, y, color.rgb());
} }
} }
updateImageDisplay(); updateImageDisplay();
@ -513,7 +411,6 @@ void ImageViewer::generateControlPanels() {
task_tab3 = new QVBoxLayout(); task_tab3 = new QVBoxLayout();
task_tab_widget3->setLayout(task_tab3); task_tab_widget3->setLayout(task_tab3);
tabWidget->addTab(task_tab_widget3, "Task #3"); tabWidget->addTab(task_tab_widget3, "Task #3");
//Show it //Show it
@ -551,7 +448,7 @@ void ImageViewer::renewLogging()
} }
void ImageViewer::updateImageDisplay() { 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() { void ImageViewer::open() {
if(image != NULL) { if(working_copy != NULL) {
delete image; delete working_copy;
image = NULL; working_copy = NULL;
} }
if(original_image!=NULL) { if(original != NULL) {
delete original_image; delete original;
original_image = NULL; original = NULL;
} }
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::currentPath()); QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::currentPath());
if(!fileName.isEmpty()) { if(!fileName.isEmpty()) {
image = new QImage(fileName); working_copy = new LazyImage(new QImage(fileName));
original_image = new QImage(fileName); original = new LazyImage(new QImage(fileName));
if(image->isNull()) { if(working_copy->getImage()->isNull()) {
QMessageBox::information(this, tr("Image Viewer"), tr("Cannot load %1.").arg(fileName)); QMessageBox::information(this, tr("Image Viewer"), tr("Cannot load %1.").arg(fileName));
return; return;
} }

View File

@ -54,6 +54,8 @@
#include "fstream" #include "fstream"
#include <iostream> #include <iostream>
#include "lazy_image.cpp"
class QAction; class QAction;
class QLabel; class QLabel;
class QMenu; class QMenu;
@ -101,10 +103,8 @@ class ImageViewer : public QMainWindow {
QVBoxLayout* task_tab3; QVBoxLayout* task_tab3;
// "My" space for storing data/results // "My" space for storing data/results
int grayscale_absolute_histogramm[256]; LazyImage* original;
double grayscale_relative_histogramm[256]; LazyImage* working_copy;
QImage* histogramm;
QImage* original_image;
private slots: private slots:
// Custom slots // Custom slots
@ -113,7 +113,6 @@ class ImageViewer : public QMainWindow {
void drawDiagonalCross(); void drawDiagonalCross();
void acidTrippin(); void acidTrippin();
void analyzeImage(); void analyzeImage();
void updateHistogramm();
void adjustBrightness(int b); void adjustBrightness(int b);
void adjustContrast(int c); void adjustContrast(int c);
void convertToMonochrome(); void convertToMonochrome();
@ -160,7 +159,6 @@ class ImageViewer : public QMainWindow {
QLabel* imageLabel; QLabel* imageLabel;
QScrollArea* scrollArea; QScrollArea* scrollArea;
double scaleFactor; double scaleFactor;
QImage* image;
std::fstream logFile; std::fstream logFile;

166
lazy_image.cpp Normal file
View File

@ -0,0 +1,166 @@
#ifndef LAZY_IMAGE_C
#define LAZY_IMAGE_C
#include <QtGlobal>
#include <QMainWindow>
#include <QColor>
#include <iostream>
#include <math.h>
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; x<this->img->width(); x++) {
for(int y=0; y<this->img->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; x<this->img->width(); x++) {
for(int y=0; y<this->img->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; y<k_max; y++) {
this->histogramm_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; x<this->img->width(); x++) {
for(int y=0; y<this->img->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