[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
*/
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; x<image->width(); x++) {
for(int y=0; y<image->height(); 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;i<std::min(image->width(),image->height());i++) {
image->setPixel(i,i,0);
if(original->getImage() != NULL) {
for(int i=0;i<std::min(working_copy->getImage()->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; y<image->height(); 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; y<working_copy->getImage()->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;i<std::min(image->width(),image->height());i++) {
if(range > working_copy->getImage()->width()-2) range = working_copy->getImage()->width()-2;
for(int i=0;i<std::min(working_copy->getImage()->width(),working_copy->getImage()->height());i++) {
int color = myColor.rgb();
for(int r=0; r<range; r++) {
image->setPixel(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; x<image->width(); x++) {
for(int y=0; y<image->height(); 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; 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.
* @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; x<image->width(); x++) {
for(int y=0; y<image->height(); y++) {
QColor color = QColor::fromRgb(original_image->pixel(x, y));
for(int x=0; x<working_copy->getImage()->width(); x++) {
for(int y=0; y<working_copy->getImage()->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; x<image->width(); x++) {
for(int y=0; y<image->height(); y++) {
QColor color = QColor::fromRgb(original_image->pixel(x, y));
int average_intensity = original->getIntensityAverage();
for(int x=0; x<working_copy->getImage()->width(); x++) {
for(int y=0; y<working_copy->getImage()->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; x<image->width(); x++) {
for(int y=0; y<image->height(); y++) {
QColor color = QColor::fromRgb(original_image->pixel(x, y));
for(int x=0; x<working_copy->getImage()->width(); x++) {
for(int y=0; y<working_copy->getImage()->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;
}

View File

@ -54,6 +54,8 @@
#include "fstream"
#include <iostream>
#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;

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