#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_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; 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 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; 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 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; yhistogramm_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; yhistogramm_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; 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()); } } }; /** * 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