swh:1:snp:206991563b219d18cdfc998d0e35716ba142c12e
Tip revision: baabf12542cd6df80af9594de8922b5281f07272 authored by Software Heritage on 14 November 2018, 00:00:00 UTC
ipol: Deposit 595 in collection ipol
ipol: Deposit 595 in collection ipol
Tip revision: baabf12
mlhe.cpp
/*----------------------------------------------------------------------------
Copyright (c) 2018 J.L. Lisani (joseluis.lisani@uib.es)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "library/io_png/io_png.h"
#include "library/io_RGB.h"
#include "library/libmlhe.h"
#include "library/parser.h"
//Read input data
unsigned char *getImageData(const char *name,
unsigned char **R,
unsigned char **G,
unsigned char **B,
unsigned char **I,
int &w, int &h)
{
size_t ww, hh;
unsigned char *img = io_png_read_u8_rgb(name, &ww, &hh);
w=(int) ww;
h=(int) hh;
input2RGB(img, R, G, B, w*h);
RGBtoI(*R, *G, *B, I, w*h);
return img;
}
//Save processed result
void saveImageData(const char *name,
unsigned char *R,
unsigned char *G,
unsigned char *B,
unsigned char *imgIn,
int w, int h)
{
unsigned char *img = imgIn;
if (!imgIn) img=new unsigned char[3*w*h];
RGB2output(R, G, B, img, w*h);
io_png_write_u8(name, img, w, h, 3); //3 channels
if (!imgIn) free(img);
}
//Algorithm 6:
//use original and processed intensities to compute
//the colors of the ouput image
void colorprocess(unsigned char *R, unsigned char *G, unsigned char *B,
unsigned char *I, unsigned char *Iout, int w, int h)
{
float scale;
int size=w*h;
unsigned char *Rout=R;
unsigned char *Gout=G;
unsigned char *Bout=B;
for (int n=0; n < size; n++) {
if (I[n] != 0) {
scale=(float) Iout[n]/ (float) I[n];
float rr= (float) R[n] *scale;
float gg= (float) G[n] *scale;
float bb= (float) B[n] *scale;
float outmax=(rr > gg)?((rr > bb)?(rr):(bb)):((gg > bb)?(gg):(bb));
//assume 8-bits images
if (outmax > 255) { //out of range: rescale but keeping
//the R/G/B ratio
rr*=255.0f/outmax;
gg*=255.0f/outmax;
bb*=255.0f/outmax;
}
Rout[n]=(int) (rr+0.5f);
Gout[n]=(int) (gg+0.5f);
Bout[n]=(int) (bb+0.5f);
} else {
Rout[n]=0;
Gout[n]=0;
Bout[n]=0;
}
}
}
//Main function (Algorithm 1):
// - read names of input and output images and parameters
// - read input image
// - apply MLHE to intensity component
// - modify color of input image using processed and original intensities
// - save result
int main(int argc, char **argv)
{
std::vector<ParStruct *> parameters;
ParStruct pInput = {(char *) "input", NULL, (char *) "input image"};
parameters.push_back(&pInput);
ParStruct pOutput = {(char *) "output", NULL, (char *) "output image"};
parameters.push_back(&pOutput);
std::vector <OptStruct *> options;
OptStruct oO = {(char *) "o:", 0, (char *) "1", NULL, (char *) "Histogram Processing Option \n \
1: Classical Histogram Equalization\n \
2: Piecewise Affine Histogram Equalization\n \
3: CLAHE"};
options.push_back(&oO);
OptStruct oA = {(char *) "a:", 0, (char *) "20", NULL, (char *) "Minimum area of processed connected components"};
options.push_back(&oA);
OptStruct oL = {(char *) "l:", 0, (char *) "7", NULL, (char *) "Maximum recursion depth (maximum=7)"};
options.push_back(&oL);
OptStruct oR = {(char *) "r:", 0, (char *) "3.0", NULL, (char *) "Maximum allowed ratio between ranges of values of connected components before and after processing"};
options.push_back(&oR);
OptStruct oM = {(char *) "m:", 0, (char *) "0.8", NULL, (char *) "Minimum allowed ratio between ranges of values of connected components before and after processing"};
options.push_back(&oM);
OptStruct oN = {(char *) "n:", 0, (char *) "5", NULL, (char *) "Number of segments in Piecewise Affine Histogram Equalization"};
options.push_back(&oN);
OptStruct oS = {(char *) "s:", 0, (char *) "3.0", NULL, (char *) "Maximum slope in Piecewise Affine Histogram Equalization"};
options.push_back(&oS);
OptStruct oT = {(char *) "t:", 0, (char *) "1.0", NULL, (char *) "Minimum slope in Piecewise Affine Histogram Equalization"};
options.push_back(&oT);
OptStruct oC = {(char *) "c:", 0, (char *) "0.01", NULL, (char *) "Clip factor for CLAHE"};
options.push_back(&oC);
if (!parsecmdline((char *) "mlhe", (char *) "Morpho Local Histogram Equalization", \
argc, argv, options, parameters))
return EXIT_FAILURE;
const char *namein = pInput.value;
const char *nameout = pOutput.value;
int HE_option = atoi(oO.value);
if ((HE_option != 1) && (HE_option != 2) && (HE_option != 3)) {
fprintf(stderr, "Invalid Histogram Processing option\n");
return EXIT_FAILURE;
}
//Parameters of the method
int Amin = atoi(oA.value);
int Lmax = atoi(oL.value);
float rmax = atof(oR.value);
float rmin = atof(oM.value);
int PAE_N = atoi(oN.value);
float PAE_smax = atof(oS.value);
float PAE_smin = atof(oT.value);
float CLAHE_clip = atof(oC.value);
//define variables
unsigned char *R, *G, *B, *I, *Iout, *img;
int w, h;
//read input image
img = getImageData(namein, &R, &G, &B, &I, w, h);
//apply algorithm
mlhe a(I, w, h);
a.apply_algorithm(Lmax, Amin, rmax, rmin, HE_option, PAE_N, \
PAE_smin, PAE_smax, CLAHE_clip);
Iout = a.get_result();
//apply changes to color channels
colorprocess(R, G, B, I, Iout, w, h);
//save result
saveImageData(nameout, R, G, B, img, w, h);
//clean up
delete[] R;
delete[] G;
delete[] B;
delete[] I;
free(img);
delete[] Iout;
return EXIT_SUCCESS;
}