Automatic Color Enhancement
histeq.c
Go to the documentation of this file.
1 
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include "imageio.h"
25 
26 #define DEFAULT_NUMBINS 256
27 
29 typedef struct
30 {
32  char *input_file;
34  char *output_file;
36  int jpeg_quality;
37 
39  long num_bins;
41 
42 
43 static int parse_params(program_params *param, int argc, char *argv[]);
44 
45 static void print_usage()
46 {
47  puts("Histogram equalization, P. Getreuer 2011\n");
48  puts("Usage: histeq [options] <input file> <output file>\n"
49  "Only " READIMAGE_FORMATS_SUPPORTED " images are supported.\n");
50  puts("Options:\n");
51  puts(" -b <number> number of histogram bins (default 256)");
52 #ifdef USE_LIBJPEG
53  puts(" -q <number> quality for saving JPEG images (0 to 100)\n");
54 #endif
55 }
56 
57 
58 int equalize_image(float *image, int width, int height, int num_bins)
59 {
60  const long num_pixels = ((long)width) * ((long)height);
61  const long num_el = 3 * num_pixels;
62  const int num_bins_minus_one = num_bins - 1;
63  float *histogram1d[3] = {NULL, NULL, NULL};
64  double accum;
65  long i;
66  int n, channel, success = 0;
67 
68  if(!(histogram1d[0] = (float *)Malloc(sizeof(float)*3*num_bins)))
69  goto fail;
70 
71  histogram1d[1] = histogram1d[0] + num_bins;
72  histogram1d[2] = histogram1d[0] + 2*num_bins;
73 
74  for(channel = 0; channel < 3; channel++)
75  for(i = 0; i < num_bins; i++)
76  histogram1d[channel][i] = 0;
77 
78  /* Accumate channel histograms */
79  for(i = 0; i < num_el; i += 3)
80  {
81  histogram1d[0][(int)(image[i + 0]*num_bins_minus_one + 0.5f)]++;
82  histogram1d[1][(int)(image[i + 1]*num_bins_minus_one + 0.5f)]++;
83  histogram1d[2][(int)(image[i + 2]*num_bins_minus_one + 0.5f)]++;
84  }
85 
86  for(channel = 0; channel < 3; channel++)
87  for(i = 0; i < num_bins; i++)
88  histogram1d[channel][i] /= num_pixels;
89 
90  /* Convert histograms to equalization maps */
91  for(channel = 0; channel < 3; channel++)
92  {
93  for(n = 0, accum = 0; n < num_bins; n++)
94  {
95  accum += histogram1d[channel][n];
96  histogram1d[channel][n] = accum - histogram1d[channel][n]/2;
97  }
98 
99  histogram1d[channel][0] = 0;
100  histogram1d[channel][num_bins - 1] = 1;
101  }
102 
103  /* Equalize the image */
104  for(i = 0; i < num_el; i += 3)
105  {
106  image[i + 0] = histogram1d[0][
107  (int)(image[i + 0]*num_bins_minus_one + 0.5f)];
108  image[i + 1] = histogram1d[1][
109  (int)(image[i + 1]*num_bins_minus_one + 0.5f)];
110  image[i + 2] = histogram1d[2][
111  (int)(image[i + 2]*num_bins_minus_one + 0.5f)];
112  }
113 
114  success = 1;
115 fail:
116  Free(histogram1d[0]);
117  return success;
118 }
119 
120 
121 int main(int argc, char **argv)
122 {
123  program_params param;
124  float *image = NULL;
125  unsigned long time_start;
126  int width, height, status = 0;
127 
128  if(!parse_params(&param, argc, argv))
129  return 0;
130 
131  if(!(image = (float *)read_image(&width, &height, param.input_file,
132  IMAGEIO_RGB | IMAGEIO_FLOAT)))
133  goto fail;
134 
135  time_start = Clock();
136 
137  if(!equalize_image(image, width, height, param.num_bins))
138  goto fail;
139 
140  printf("CPU Time: %.3f s\n", 0.001f*(Clock() - time_start));
141 
142  if(!write_image(image, width, height, param.output_file,
143  IMAGEIO_RGB | IMAGEIO_FLOAT, param.jpeg_quality))
144  goto fail;
145 
146  status = 0;
147 fail:
148  if(image)
149  free(image);
150  return status;
151 }
152 
153 
154 static int parse_params(program_params *param, int argc, char *argv[])
155 {
156  static char *default_output_file = (char *)"out.png";
157  char *option_string;
158  char option_char;
159  int i;
160 
161 
162  if(argc < 2)
163  {
164  print_usage();
165  return 0;
166  }
167 
168  /* Set parameter defaults */
169  param->input_file = 0;
170  param->output_file = default_output_file;
171  param->jpeg_quality = 85;
172  param->num_bins = DEFAULT_NUMBINS;
173 
174  for(i = 1; i < argc;)
175  {
176  if(argv[i] && argv[i][0] == '-')
177  {
178  if((option_char = argv[i][1]) == 0)
179  {
180  ErrorMessage("Invalid parameter format.\n");
181  return 0;
182  }
183 
184  if(argv[i][2])
185  option_string = &argv[i][2];
186  else if(++i < argc)
187  option_string = argv[i];
188  else
189  {
190  ErrorMessage("Invalid parameter format.\n");
191  return 0;
192  }
193 
194  switch(option_char)
195  {
196  case 'b':
197  param->num_bins = atoi(option_string);
198 
199  if(param->num_bins <= 1 || param->num_bins > 10000)
200  {
201  ErrorMessage("Number of bins must be between 2 and 10000.\n");
202  return 0;
203  }
204  break;
205 #ifdef LIBJPEG_SUPPORT
206  case 'q':
207  param->jpeg_quality = atoi(option_string);
208 
209  if(param->jpeg_quality <= 0 || param->jpeg_quality > 100)
210  {
211  fprintf(stderr, "JPEG quality must be between 0 and 100.\n");
212  return 0;
213  }
214  break;
215 #endif
216  case '-':
217  print_usage();
218  return 0;
219  default:
220  if(isprint(option_char))
221  ErrorMessage("Unknown option \"-%c\".\n", option_char);
222  else
223  ErrorMessage("Unknown option.\n");
224 
225  return 0;
226  }
227 
228  i++;
229  }
230  else
231  {
232  if(!param->input_file)
233  param->input_file = argv[i];
234  else
235  param->output_file = argv[i];
236 
237  i++;
238  }
239  }
240 
241  if(!param->input_file)
242  {
243  print_usage();
244  return 0;
245  }
246  return 1;
247 }