263 lines
7.6 KiB
C++
263 lines
7.6 KiB
C++
#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_normal_image;
|
|
QImage* histogramm_cumulative_image;
|
|
double histogramm_relative_intensity[256];
|
|
double histogramm_relative_cumulative_intensity[256];
|
|
int histogramm_absolute_intensity[256];
|
|
int histogramm_absolute_cumulative_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;
|
|
histogramm_absolute_cumulative_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 and absolute cumulative histogramm
|
|
int pixels = this->img->width()*this->img->height();
|
|
int sum = 0;
|
|
double relative_sum = 0.0;
|
|
for(int i=0; i<256; i++) {
|
|
histogramm_relative_intensity[i] = (((double) histogramm_absolute_intensity[i])/((double) pixels));
|
|
sum += histogramm_absolute_intensity[i];
|
|
relative_sum += histogramm_relative_intensity[i];
|
|
histogramm_absolute_cumulative_intensity[i] = sum;
|
|
histogramm_relative_cumulative_intensity[i] = relative_sum;
|
|
}
|
|
};
|
|
|
|
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 generateNormalHistogrammImage(void) {
|
|
if(this->histogramm_normal_image != NULL) {
|
|
delete this->histogramm_normal_image;
|
|
this->histogramm_normal_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_normal_image = new QImage(256, 100, QImage::Format_RGB32);
|
|
this->histogramm_normal_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_normal_image->setPixel(x, (100-y)-1, black);
|
|
}
|
|
}
|
|
};
|
|
|
|
void generateCumulativeHistogrammImage(void) {
|
|
if(this->histogramm_cumulative_image != NULL) {
|
|
delete this->histogramm_cumulative_image;
|
|
this->histogramm_cumulative_image = NULL;
|
|
}
|
|
this->histogramm_cumulative_image = new QImage(256, 100, QImage::Format_RGB32);
|
|
this->histogramm_cumulative_image->fill(QColor::fromRgb(200,200,200));
|
|
int black = QColor::fromRgb(0,0,0).rgb();
|
|
double total = 0.0;
|
|
for(int x=0; x<256; x++) {
|
|
total += histogramm_relative_intensity[x];
|
|
int k_max = (int) qRound(100*total);
|
|
for(int y=0; y<k_max; y++) {
|
|
this->histogramm_cumulative_image->setPixel(x, (100-y)-1, black);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
public:
|
|
enum overflowMode {ZERO_PADDING, CONSTANT, MIRRORED, CONTINUOUS};
|
|
|
|
LazyImage(QImage* img) {
|
|
this->histogramm_normal_image = NULL;
|
|
this->histogramm_cumulative_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->generateNormalHistogrammImage();
|
|
this->generateCumulativeHistogrammImage();
|
|
};
|
|
|
|
QImage* getHistogrammNormalImage(void) {
|
|
return this->histogramm_normal_image;
|
|
};
|
|
|
|
QImage* getHistogrammCumulativeImage(void) {
|
|
return this->histogramm_cumulative_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;
|
|
};
|
|
|
|
int* getAbsoluteCumulativeIntensityHistogramm(void) {
|
|
return this->histogramm_absolute_cumulative_intensity;
|
|
};
|
|
|
|
double* getRelativeIntensityHistogramm(void) {
|
|
return this->histogramm_relative_intensity;
|
|
};
|
|
|
|
double* getRelativeCumulativeIntensityHistogramm(void) {
|
|
return this->histogramm_relative_cumulative_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());
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Takes coordinates and a mode about how to handle overflows.
|
|
* Not all modes are 100% bullet proof - it is still possible to
|
|
* get unexpected results out of this for very big overflows.
|
|
*
|
|
* @brief LazyImage::getPixel
|
|
*/
|
|
QRgb getPixel(int x, int y, overflowMode mode) {
|
|
int width = this->img->width();
|
|
int height = this->img->height();
|
|
bool return_result = false;
|
|
QRgb result;
|
|
switch(mode) {
|
|
case ZERO_PADDING: // Return black for all out of bound requests
|
|
if(x < 0 || x >= width || y < 0 || y >= height) {
|
|
result = qRgb(0, 0, 0);
|
|
return_result = true;
|
|
}
|
|
break;
|
|
case CONSTANT: // Simply clamp to the border it is stuck on
|
|
if(x < 0) x = 0;
|
|
else if(x >= width) x = width - 1;
|
|
if(y < 0) y = 0;
|
|
else if(y >= height) y = height - 1;
|
|
break;
|
|
case MIRRORED: // Mirror on overflowed axis
|
|
if(x < 0) x *= -1;
|
|
else if(x >= width) {
|
|
int delta = x - (width-1);
|
|
x = (width-1) - delta;
|
|
}
|
|
if(y < 0) y *= -1;
|
|
else if(y > (height-1)) {
|
|
int delta = y - (height-1);
|
|
y = (height-1) - delta;
|
|
}
|
|
break;
|
|
case CONTINUOUS: // simply start over at the other side again
|
|
x = std::abs(x % width);
|
|
y = std::abs(y % height);
|
|
break;
|
|
default:
|
|
std::cout << "HELP, SOMETHING WENT WRONG! I DON'T KNOW THIS MODE!" << std::endl;
|
|
break; // BOOM!
|
|
}
|
|
if(return_result) {
|
|
return result;
|
|
} else {
|
|
return this->img->pixel(x, y);
|
|
}
|
|
};
|
|
|
|
};
|
|
|
|
|
|
#endif
|