1 /*-----------------------------------------------------------------------
2 This file is part of aaphoto.
3
4 aaphoto is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 aaphoto is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ------------------------------------------------------------------------*/
17
18
19
20
21
22 /* --------------------------------------------------- */
23 /* ----------- Auto Adjust RGB ----------------------- */
24 /* ----------- András Horváth (C) 2006-2013 ---------- */
25 /* ----------- Hungary, http://log69.com ------------- */
26 /* --------------------------------------------------- */
27
28 /*
29
30 aaRGB Changelog:
31 ------------------
32 2013/09/30 - aaRGB v0.65 - fix some compile time warnings and uninitalized variables
33 2011/01/26 - aaRGB v0.64 - the contrast seemed strong with the default initial value of the former algorithm,
34 so now constant optimized to the new contrast algorithm introduced in 0.63
35 - add more detailed explanations to the contrast algorithm (in hungarian)
36 2010/12/18 - aaRGB v0.63 - include OpenMP defs in aargb.c too for standalone usage
37 - fix some warning messages during build
38 - make embedded test info image look more readable by changing the colors (--test switch)
39 - change saturation algorithm from linear to exponential
40 - improve contrast algorithm to include a self balance mechanism to avoid overexposure
41 on images with large blank areas that have relatively small details
42 - improve color balance algorithm to make it a bit more aggressive by raising the value
43 of the color difference factor of the white and black point to the 3rd power
44 - speed up process by skipping saturation part if no change is needed
45 - some memory allocation check
46 - some changes in documentation
47 2010/09/14 - aaRGB v0.62 - bugfix: an ugly misconception in my paralleled code caused weird behavior
48 when using more threads
49 - rewrite the code to suffice the ISO C90 ANSI standard C form (GCC -pedantic option)
50 2010/05/02 - aaRGB v0.61 - add OpenMP support for multi processing, all computing cycles paralleled
51 - solve warning issues with some uninitialized variables
52 - some code cleanup
53 2009/10/18 - aaRGB v0.60 - remove gamma handling of the lighter colors from the two-pole gamma computing
54 by setting the gamma_interval_high from 0.9 to 1, it proved to be inefficient
55 2009/04/05 - aaRGB v0.59 - some more code cleanup
56 2009/02/22 - aaRGB v0.58 - code cleanup
57 2007/08/11 - aaRGB v0.57 - improve black and white point analyzing
58 from now they are not scaled to perfect black and white, but to their darkest
59 and brightest color that have maximum saturation to fix overexposure problem
60 - improve saturation algorithm with full floating point computing and HSL conversion
61 to fix over saturated colors
62 - expand image information display with color balance circle for testing (--test switch)
63 - remove text information from test display (--test switch)
64 2007/06/21 - aaRGB v0.56 - expand functionality with "apply only on selection" to process only the selected area
65 2007/04/03 - aaRGB v0.55 - maximize saturation limit with a predefined constant to avoid overexposure in saturation
66 when reconverting the same image
67 2007/04/01 - aaRGB v0.54 - new two-pole gamma computing
68 - new saturation compensation
69 2007/03/29 - aaRGB v0.53 - improve contrast computing to avoid underexposure
70 2007/02/25 - aaRGB v0.52 - improve image information display for testing (--test switch)
71 2007/02/16 - aaRGB v0.51 - improve average RGB color computing for more accurate color balance calibration
72 2007/01/04 - aaRGB v0.49 - stable working version with gamma handling and more clever image analyzing
73 2006/08/29 - aaRGB project begun...
74
75 aaRGB end of Changelog.
76
77 */
78
79
80 /* ---------------------------------------------------------------- */
81 /* -- Automatically adjusts contrast, color balance, gamma level -- */
82 /* -- and saturation of an RGB image ------------------------------ */
83 /* ---------------------------------------------------------------- */
84
85 /*
86 pictures might need some contrast adjustment when their colors don't spread
87 the entire spectrum, usually when their darkest colors aren't dark enough and
88 the lightest colors not bright enough, this causing a veiled effect on them.
89
90 sometime color balance adjustment is also necessary, when the brightest and darkest
91 colors of the image are not black and white enough, but they are shifted towards
92 some other color which may be the effect of the technology used,
93 or simply the environment changes the colors unrealistically.
94
95 the procedure assumes that there must be some detail on the picture that's
96 supposed to be black (dark enough) and also white (bright enough) in real.
97 the automatic contrast and color balance process is built upon this.
98
99 the overall (or average) brilliance of the image can be set by the gamma level.
100 this procedure makes sure that those pictures that seem too dark will be
101 corrected by this factor by changing the middle dark colors while not changing
102 the darkest and brightest colors.
103
104 as the last step, a saturation adjustment takes place to intensify the colors
105 themselves if needed.
106 */
107
108
109
110 #include <math.h>
111 #include <stdlib.h>
112
113
114
115 /* ------------------------- */
116 /* ----- SIGN FUNCTION ----- */
117 /* ------------------------- */
118
sgn(double x)119 int sgn(double x)
120 {
121 if (x < 0) { return -1; }
122 if (x > 0) { return 1; }
123 /* if x is 0 then return 0 */
124 return 0;
125 }
126
127
128
129 /* -------------------------------- */
130 /* ----- RGB - HSL CONVERSION ----- */
131 /* -------------------------------- */
132
RGB_TO_HSL(double R,double G,double B,double * H1,double * S1,double * L1)133 void RGB_TO_HSL(double R, double G, double B, double *H1, double *S1, double *L1)
134 {
135 double H, S, L;
136 double LN, LK, LNX, LKX;
137
138 if (R < 0) { R = 0; } if (R > 1) { R = 1; }
139 if (G < 0) { G = 0; } if (G > 1) { G = 1; }
140 if (B < 0) { B = 0; } if (B > 1) { B = 1; }
141
142 H = 0;
143 S = 0;
144 L = 0;
145
146 L = (R + G + B) / 3;
147
148 /* To calculate the 'S' saturation value, first i determine the
149 maximum amount of how much i can stretch the RGB color elements
150 to their limits while keeping the same 'L' lightness and 'H' hue values */
151
152 LN = R;
153 if (LN < G) { LN = G; }
154 if (LN < B) { LN = B; }
155 LK = R;
156 if (LK > G) { LK = G; }
157 if (LK > B) { LK = B; }
158 if (LN == LK) { S = 0; H = 0; }
159 else {
160 double R2, G2, B2;
161
162 if ((LN < 1) && (LK > 0)) {
163 /* L cannot be either 0 or 1 here */
164 LKX = (L - LK) / L;
165 LNX = (LN - L) / (1 - L);
166 S = LNX;
167 if (LKX >= LNX) { S = LKX; }
168 }
169 else { S = 1; }
170
171 /* To get the 'H' color value, i stretch the RGB elements to their maximum,
172 so it'll be a 6 case outcome. */
173
174 LN = LN - LK;
175 R2 = (R - LK) / LN;
176 G2 = (G - LK) / LN;
177 B2 = (B - LK) / LN;
178
179 if ((R2 == 1) && (G2 < 1) && (G2 >= 0) && (B2 == 0)) { H = ( 0 + G2 * 60) / 360; }
180 if ((G2 == 1) && (R2 <= 1) && (R2 > 0) && (B2 == 0)) { H = ( 60 + (1-R2) * 60) / 360; }
181 if ((G2 == 1) && (B2 < 1) && (B2 >= 0) && (R2 == 0)) { H = (120 + B2 * 60) / 360; }
182 if ((B2 == 1) && (G2 <= 1) && (G2 > 0) && (R2 == 0)) { H = (180 + (1-G2) * 60) / 360; }
183 if ((B2 == 1) && (R2 < 1) && (R2 >= 0) && (G2 == 0)) { H = (240 + R2 * 60) / 360; }
184 if ((R2 == 1) && (B2 <= 1) && (B2 > 0) && (G2 == 0)) { H = (300 + (1-B2) * 60) / 360; }
185
186 if (H == 1) { H = 0; }
187 }
188
189 *H1 = H; *S1 = S; *L1 = L;
190
191 }
192
193
194
HSL_TO_RGB(double H,double S,double L,double * R1,double * G1,double * B1)195 void HSL_TO_RGB(double H, double S, double L, double *R1, double *G1, double *B1)
196 {
197 double R = 0;
198 double G = 0;
199 double B = 0;
200
201 if (H < 0) { H = 0; } if (H > 1) { H = 1; }
202 if (S < 0) { S = 0; } if (S > 1) { S = 1; }
203 if (L < 0) { L = 0; } if (L > 1) { L = 1; }
204
205 if (L == 0) { R = 0; G = 0; B = 0; }
206 else {
207 if (L == 1) { R = 1; G = 1; B = 1; }
208 else {
209 double L2, templ;
210
211 /* set the things here based on 'H' value */
212 int deg;
213 double mul;
214 if (H == 1) { H = 0; }
215 deg = (int)(H * 6);
216 mul = H * 6 - deg;
217
218 switch (deg) {
219 case 0:
220 R = 1; G = mul; B = 0; break;
221 case 1:
222 G = 1; R = 1-mul; B = 0; break;
223 case 2:
224 G = 1; B = mul; R = 0; break;
225 case 3:
226 B = 1; G = 1-mul; R = 0; break;
227 case 4:
228 B = 1; R = mul; G = 0; break;
229 case 5:
230 R = 1; B = 1-mul; G = 0; break;
231 }
232
233 /* scale the things here in the RGB field by the value of 'L' */
234 L2 = (R + G + B) / 3;
235 if (L > L2) {
236 templ = (1-L) / (1-L2);
237 R = 1 - (1-R) * templ;
238 G = 1 - (1-G) * templ;
239 B = 1 - (1-B) * templ;
240 }
241 else {
242 templ = L / L2;
243 R = R * templ;
244 G = G * templ;
245 B = B * templ;
246 }
247
248 /* scale the things here in the RGB field by the value of 'S' */
249 if (R > L) { R = L + (R-L) * S; } else { R = L - (L-R) * S; }
250 if (G > L) { G = L + (G-L) * S; } else { G = L - (L-G) * S; }
251 if (B > L) { B = L + (B-L) * S; } else { B = L - (L-B) * S; }
252 }
253 }
254
255 *R1 = R; *G1 = G; *B1 = B;
256
257 }
258
259
260
261 /* ------------------------------------------------------------------------------ */
262
AARGB_MAIN(unsigned char * image_buffer,int image_width,int image_height,int x1,int y1,int x2,int y2,int format_flag,int apply_on_selection,int test_flag)263 void AARGB_MAIN(
264 unsigned char *image_buffer,
265 int image_width,
266 int image_height,
267 int x1,
268 int y1,
269 int x2,
270 int y2,
271 int format_flag,
272 int apply_on_selection,
273 int test_flag)
274 {
275
276
277 /* ------------------------------------------------------------------------------ */
278 /* ---------- Global variables for the procedure ------------------------------ */
279 /* ------------------------------------------------------------------------------ */
280
281 int max_threads2;
282
283 double cont_max;
284 double gamma_max;
285 double gamma_interval_low;
286 double gamma_interval_high;
287 double satur_max;
288
289 double gamma_weight_low_all;
290 double gamma_weight_high_all;
291 double gamma_weight_low;
292 double gamma_weight_high;
293 double gamma_low;
294 double gamma_high;
295
296 long hist1[256];
297 long hist2[256];
298 long hist3[256];
299 long *hist1n;
300 long *hist2n;
301 long *hist3n;
302 long hist_min;
303 long hist_max;
304 long hist_cut_columns;
305 long hist_cut_weight;
306 double hist_cut_limit;
307 double hist_avg;
308
309 /*
310 long hist_sum;
311 long hist_min_test;
312 long hist_max_test;
313 double hist_avg_test;
314 */
315
316 long hist_satur[256];
317 long *hist_saturn;
318 double hist_satur_avg;
319 double hist_satur_low;
320 double hist_satur_ok;
321
322 double temp1, temp2, temp3;
323 long flag1;
324 long bw, bh;
325 long x, y;
326 long i1, i2, i3;
327
328 long col_r, col_g, col_b;
329 double col_r2, col_g2, col_b2;
330 unsigned long col_r3[256];
331 unsigned long col_g3[256];
332 unsigned long col_b3[256];
333 unsigned long *col_r3n;
334 unsigned long *col_g3n;
335 unsigned long *col_b3n;
336
337 double H, S, L;
338
339 double wp, bp;
340 double wp_end, bp_end;
341 double wp_r, wp_g, wp_b;
342 double bp_r, bp_g, bp_b;
343 double wp_r_end = 0, wp_g_end = 0, wp_b_end = 0;
344 double bp_r_end = 0, bp_g_end = 0, bp_b_end = 0;
345
346 long cc;
347 long addr, addr2;
348 long addr_offset;
349 int N;
350
351
352 long col;
353 long xm, ym;
354 long xma1, xma2;
355 long xmb1, xmb2;
356 long color_black = 0x00000000;
357 long color_green = 0x0000ff00;
358 long color_brown = 0x00707000;
359 long color_blue = 0x000080ff;
360 long color_white = 0x00ffffff;
361 long color_gray = 0x00606060;
362 long color_red = 0x00a00000;
363 long color_yellow = 0x00ffff00;
364 /* long color_green_dark = 0x00008000; */
365
366
367 /* is there openmp support? */
368 max_threads2 = 1;
369 #ifdef __OPENMP__
370 /* get the number of available processors to know maximum number of threads */
371 max_threads2 = omp_get_num_procs();
372 /* set it to minimum 1 */
373 if (max_threads2 < 1){ max_threads2 = 1; }
374 #endif
375
376
377 /* allocate memory for the arrays that help to parallel cycles */
378 /* the allocated memory here is way too small, so i don't print any error message on failure
379 cause i don't want to have stdio.h as a dependency for this procedure,
380 just simply exit */
381
382 hist_saturn = 0;
383
384 hist1n = 0;
385 hist2n = 0;
386 hist3n = 0;
387
388 col_r3n = 0;
389 col_g3n = 0;
390 col_b3n = 0;
391
392 if ((hist_saturn = calloc (256 * max_threads2, sizeof (*hist_saturn))) == 0){ goto exit; }
393
394 if ((hist1n = calloc (256 * max_threads2, sizeof (*hist1n))) == 0){ goto exit; }
395 if ((hist2n = calloc (256 * max_threads2, sizeof (*hist2n))) == 0){ goto exit; }
396 if ((hist3n = calloc (256 * max_threads2, sizeof (*hist3n))) == 0){ goto exit; }
397
398 if ((col_r3n = calloc (256 * max_threads2, sizeof (*col_r3n))) == 0){ goto exit; }
399 if ((col_g3n = calloc (256 * max_threads2, sizeof (*col_g3n))) == 0){ goto exit; }
400 if ((col_b3n = calloc (256 * max_threads2, sizeof (*col_b3n))) == 0){ goto exit; }
401
402
403 /* ------------------------------------------------------------------------------ */
404 /* Initialization and constants for the contrast and gamma (0...1) */
405 /* ------------------------------------------------------------------------------ */
406 /* Kezdõ értékek és konstansok megadása a kontraszt és gamma mûveletekhez */
407
408 /* Kontraszt konstans megadása: megadja, hogy mekkora lehet az automata */
409 /* kontraszt állítás maximum értéke (0...1-ig terjedhet az értéke), */
410 /* alapértelmezett = 0.1 */
411 /* Gamma konstans megadása: megadja, hogy mekkora lehet az automatikus */
412 /* gamma állítás maximum értéke (1...10-ig ajánlott), */
413 /* alapértelmezett = 1.5 */
414
415 /* Gamma állításhoz a maximum elõfordulás értékének megadása (occur_max), */
416 /* amely megadja, hogy a gamma érték számításánál ha ennél kisebb az */
417 /* elõfordulása a nagy mértékben elõforduló színeknek, akkor kihagyjuk õket a */
418 /* számításból, vagyis a nagy mértékben elõforduló színeket azért nem vesszük */
419 /* be a számításba, mert inkább a részletek látszódjanak jól, */
420 /* vagyis a részletekhez legyen inkább kiszámolva a megfelelõ fényerõ */
421
422
423 /* ------------------------------ */
424 /* Konstans értékek beállítása */
425 /* ------------------------------ */
426 /* maximális kontraszt mértéke (0..1) */
427 cont_max = 0.066666;
428
429 /* maximális gamma korrekció mértéke (1..10) */
430 gamma_max = 1.5;
431 gamma_interval_low = 0.333;
432 gamma_interval_high = 1;
433
434 /* maximális színtelítettség limit (0..1) */
435 satur_max = 0.333;
436
437 bw = image_width;
438 bh = image_height;
439
440 /* Kijelölt területhez a koordináták határértékeinek vizsgálata */
441 /* és megfelelõ beállítása */
442 /* A kijelölés célja, hogy egy meghatározott képrészletet szeretnénk jól */
443 /* láthatóvá tenni (nem pedig az egészet arányaiban) */
444
445 /* a szélesség konvertálása abszolút koordinátává, jelenleg nem él */
446 /* x2 = x1 + x2 - 1; */
447 /* y2 = y1 + y2 - 1; */
448
449 if (x1 < 0) { x1 = 0; }
450 if (x2 < 0) { x2 = 0; }
451 if (y1 < 0) { y1 = 0; }
452 if (y2 < 0) { y2 = 0; }
453 if (x1 > bw-1) { x1 = bw-1; }
454 if (x2 > bw-1) { x2 = bw-1; }
455 if (y1 > bh-1) { y1 = bh-1; }
456 if (y2 > bh-1) { y2 = bh-1; }
457 /* A DIB formátum 4-byte-os igazításához az eltolás értékének kiszámítása */
458 /* Normál tömbnél erre nincs szükség, ekkor a format_flag értéke = 0 */
459 /* egyébként a DIB formátumú tömb függõlegesen fordított sorokat tartalmaz, */
460 /* és a sorvégek 4 byte-tal vannak igazítva */
461 addr_offset = 0;
462 /* Format = 0 --> NORMAL 3 byte RGB data in array */
463 /* Format = 1 --> DIB data format in array */
464 /* Format = 2 --> BMP data format in array */
465 if ((format_flag == 1) || (format_flag == 2)){
466 y1 = bh - 1 - y1;
467 y2 = bh - 1 - y2;
468 addr_offset = bw * 3 - 4 * (bw * 3 / 4);
469 if (addr_offset) addr_offset = 4 - addr_offset;
470 }
471 /* Kijelölés koordinátáinak felcserélése, ha nem jó sorrendben adták meg, */
472 /* vagyis a bal felsõ sarok az x1 és y1, a jobb alsó pedig az x2 és y2 */
473 if (x1 > x2) { i1 = x1; x1 = x2; x2 = i1; }
474 if (y1 > y2) { i1 = y1; y1 = y2; y2 = i1; }
475
476
477 /* ------------------------------------------------------------------------------ */
478 /* Create Histogram and average RGB colors for the Image */
479 /* ------------------------------------------------------------------------------ */
480 /* Hisztogram generálása a kép színeibõl, ami a kép feényerõ eloszlását adja meg */
481 /* plusz a színegyensúly beállításához az egy fényerejû színek átlag RGB */
482 /* értékeinek letárolása, megelõlegezve egy késõbbi rutin munkáját */
483
484 /* A kép minden egyes pontjának átlag fényereje (szürkéje) bekerül egy */
485 /* 256 elemû tömbbe, ahol a fényerejük értéke az azonos indexû elem értékét */
486 /* 1-gyel növeli */
487
488 /* Így ez a hisztogram tömb pontos leírást ad a feketétõl a fehérig terjedõ */
489 /* színskálájáról a képnek */
490
491 /* array initialization with zeros */
492 #ifdef __OPENMP__
493 #pragma omp parallel for num_threads(max_threads2)
494 #endif
495 for (i1=0; i1<256; i1++){
496 hist1[i1] = 0;
497 hist2[i1] = 0;
498 hist3[i1] = 0;
499 hist_satur[i1] = 0;
500 col_r3[i1] = 0;
501 col_g3[i1] = 0;
502 col_b3[i1] = 0;
503 }
504
505 #ifdef __OPENMP__
506 #pragma omp parallel for private(x, y, addr, addr2, col_r, col_g, col_b, cc, N) num_threads(max_threads2)
507 #endif
508 for (y=0; y<=bh-1; y++){
509 addr2 = y * bw * 3 + y * addr_offset;
510 for (x=0; x<=bw-1; x++){
511 if (x >= x1 &&
512 x <= x2 &&
513 y >= y1 &&
514 y <= y2) {
515
516 addr = addr2 + x * 3;
517 col_r = image_buffer[addr + 0];
518 col_g = image_buffer[addr + 1];
519 col_b = image_buffer[addr + 2];
520 cc = (col_r + col_g + col_b) / 3;
521 /* multi processing, thread id */
522 #ifdef __OPENMP__
523 N = omp_get_thread_num();
524 #else
525 N = 0;
526 #endif
527 /* szürke hisztogramm */
528 hist1n[cc + N*256]++;
529 /* Átlag RGB értékek letárolása a fekete és fehér pont */
530 /* átlag RGB-jének későbbi megállapításához */
531 col_r3n[cc + N*256] += col_r;
532 col_g3n[cc + N*256] += col_g;
533 col_b3n[cc + N*256] += col_b;
534 }
535 }
536 }
537
538 /* this is a replacement code for arrays for multi processing */
539 #ifdef __OPENMP__
540 #pragma omp parallel for private(i1, i2) num_threads(max_threads2)
541 #endif
542 for (i1=0; i1<256; i1++){
543 for (i2=0; i2<max_threads2; i2++){
544 hist1[i1] += hist1n[i1 + i2*256];
545 col_r3[i1] += col_r3n[i1 + i2*256];
546 col_g3[i1] += col_g3n[i1 + i2*256];
547 col_b3[i1] += col_b3n[i1 + i2*256];
548 }
549 }
550
551
552 /* ------------------------------------------------------------------------------ */
553 /* Start analyzing to find the White and Black points */
554 /* ------------------------------------------------------------------------------ */
555 /* Az automata kontraszt beállításához a Fekete és Fehér pont megállapítása */
556
557 /* A hisztogram bal és jobb oldaláról elkezdem beolvasni a szürke értékek */
558 /* nagyságát és addig olvasom be, amíg az nem nagyobb egy elõre meghatározott */
559 /* értéknél, ekkor megkapom a fekete és fehér pont helyzetét */
560
561 /* Ez az elõre meghatározott érték a kontraszt konstans és a hisztogram */
562 /* összes tömbeleme átlagának a szorzata */
563 /* Az átlag szorzat egyensúlyt teremt a határérték elérésénél, mert egyébként */
564 /* ha ez az érték mondjuk a hisztogram maximum értéke lenne, akkor */
565 /* drasztikus kontraszt túlállítás jellemezné a funkciót */
566
567 /* Vagyis ez az érték azt adja meg, hogy a kép átlag fényerejének hány */
568 /* százaléka az az érték, amely a továbbiakban megadja, hogy az ekkora */
569 /* százalék alatt található feketék és fehérek lesznek kihúzva a határig (le lesznek vágva)*/
570
571 hist_min = bw * bh;
572 hist_max = 0;
573 hist_avg = 0;
574
575 /* Átlag fényerõ kiszámítása: ezt úgy kapom meg, hogy összeadom a histogramm
576 összes oszlopát és osztom 256-al (oszlopok száma), vagyis matematikai átlaga.
577 Ezt még leosztom egy konstanssal (10%-ára alapból) úgy, hogy nullánál kisebbel szorzok,
578 az így kapott értéket nevezem itt limit-nek.
579
580 (a maximum és minimum érték számítása csak tesztelési céllal él)
581 */
582 for (i1=0; i1<256; i1++){
583 temp1 = hist1[i1];
584 if (hist_min > (long)temp1){ hist_min = (long)temp1; }
585 if (hist_max < (long)temp1){ hist_max = (long)temp1; }
586 hist_avg = hist_avg + temp1;
587 }
588 /* histogram teljes összege */
589 /* hist_sum = hist_avg; */
590
591 /* histogram matematikai átlag értéke */
592 hist_avg = hist_avg / 256;
593
594 /*
595 hist_min_test = hist_min;
596 hist_max_test = hist_max;
597 hist_avg_test = hist_avg;
598 */
599
600 /* ez lesz itt a limit */
601 temp1 = hist_avg * cont_max;
602 hist_cut_limit = temp1;
603
604
605
606 /* fehér és feketepont keresése 0 (nulla) maximumig */
607
608 bp = 255;
609 flag1 = 0;
610
611 for (i1=0; i1<256; i1++){
612 if (flag1 == 0){
613 if (hist1[i1] > 0){
614 flag1 = 1;
615 bp = i1;
616 }
617 }
618 }
619
620 wp = 0;
621 flag1 = 0;
622 hist_cut_columns = 0;
623
624 for (i1=255; i1>=0; i1--){
625 if (flag1 == 0){
626 if (hist1[i1] > 0){
627 flag1 = 1;
628 wp = i1;
629 }
630 }
631 }
632
633 if (bp > wp){
634 i1 = (long)(wp);
635 wp = bp;
636 bp = i1;
637 }
638 if (bp == wp){
639 bp = bp - 1;
640 wp = wp + 1;
641 }
642 if (bp < 0){ bp = 0; }
643 if (bp >= 255){ bp = 254; }
644 if (wp > 255){ wp = 255; }
645 if (wp <= 0){ wp = 1; }
646
647
648 /* -----------------------------------------------------------------------------------
649 Az automatikus kontraszt állító algoritmus néha olyan bemenetet is kaphat,
650 ahol a részletek a képen túl kis mennyiségben vannak jelen, és nagy terjedelmű
651 egy színű részek a jellemzőek - ekkor az volt a jelenség, hogy az algoritmus
652 túl nagyot vág le a hisztogram széléből, és az ezen a képen fontosabb kis mennyiségű
653 részlet veszik el.
654
655 Ezért beillesztettem az algoritmusba egy önszabályozó mechanizmust, amelynél ha
656 felmerül a fenti eset, akkor jó esély van rá, hogy a részletek maradnak meg inkább
657 a kontraszt állítás után.
658
659 Ez úgy történik, hogy megnézem, mennyi oszlop esik a limit érték alá, és ennek függvényében
660 tovább csökkentem ezt a limit-et, mivel minél több rész esik az átlag alá (oszlopok száma a hisztogramban),
661 ez azt jelenti hogy annál több a képen az olyan érdekes részlet, amely levágásra kerülne,
662 ezért a sok és meghatározó nagy üres részek kevésbé kellene hogy számítsanak.
663
664 A limit értéket az alábbi módon húzom tovább lefelé: újra fogom kalkulálni az átlagot
665 és ezt a limit értéket is úgy, hogy a kalkuláció során az ez fölé eső oszlop értékek
666 kevésbé számítsanak, ha minél több az előzőkben a limit érték alatti részek oszlopainak száma,
667 és ha ezen oszlopok magasságának összegei is minél kisebbek,
668 mert így tudjuk meg, hogy egyre kisebb területen van az értékes részlet.
669
670 Ez így egy önfékező folyamatot eredményez a nagy üres területek átlaga okozta túl nagy limit értékhez,
671 és ezzel a túl nagy kontraszt levágáshoz, ahol is pont a részlet veszik el.
672
673 Ezek után újra kalkulálom ezt a limit értéket az előző módon,
674 és ezzel lesz tovább kalkulálva a histogram szélek levágása.
675
676 Hogy mennyire számítson a kis kép részlet, azt is analóg módon akarom eldönteni,
677 tehát úgy, hogy az eredeti limit érték módosulása ne szakaszos módon történjen,
678 viszont mivel úgy gondolom, hogy olyan görbére van szükségem, amely a 0-1 intervallumon
679 a feléig nagyon kicsit emelkedik, majd innét drasztikusabban,
680 ezért az 5. hatványt szorozva 3-mal találtam a megfelelőnek.
681
682 f(x) = x^5*3
683 Wolphram Aplha link a szemléltetéshez:
684 http://www.wolframalpha.com/input/?i=x^5+*+3+from+0+to+1
685
686 Ennek mentén, ha a kis és nagy részlet egyensúly felborul, akkor
687 a 0.5 től felfelé kezd a kontraszt számítás egyre kevésbé drasztikusba átmenni,
688 és ezzel érem el, hogy a kisebb értékek lehetőleg minél kevésbé,
689 míg a nagyobb értékek egyre jobban folyásolják be ezt.
690 -------------------------------------------------------------------------------------- */
691
692
693 /* azért csak a fekete és fehér pont közötti szakaszt vizsgálom
694 (ez a hisztogramm megmaradó szélessége a bal és jobb oldali levágás után)
695 mert a tervezett végleges eredményen akarom vizsgálni a részlet mennyiségének arányát
696 a teljes terjedelemhez képest (amennyi maradna belőle).
697 */
698
699 hist_cut_columns = 0;
700 hist_cut_weight = 0;
701 for (i1=bp; i1<wp; i1++){
702 if (hist1[i1] < temp1){
703 hist_cut_columns++;
704 hist_cut_weight += hist1[i1];
705 }
706 }
707
708
709 /* temp1 mutatja az eredeti levágandó limit értéket,
710 hist_cut_columns mutatja a limit alatti oszlopok számát (ezt nevezem limit alatti részletnek),
711 hist_cut_weight mutatja ezen oszlopok értékének összegét (súlyát),
712
713 temp2-t pedig úgy állítom be, hogy minél nagyobb súly oszlik el kevesebb oszlop számon
714 (vagyis minél kevesebb oszlop van a limit alatt és ezeknek a súlya minél nagyobb),
715 úgy ennek is annál nagyobb lesz az értéke - vagyis ha temp2-nek nagyobb az értéke,
716 az azt jelenti hogy annál több értékes részlet van a limit alatt.
717
718 azért nevezem a limit alatti oszlopokat értékesebb részletnek, mert a teljes hisztogramm átlagot
719 elhúzzák felfelé a nagy egyszínű részek, amelyek kevés oszlopok nagy súllyal,
720 vagyis ezek nyilván nagyobb terjedelmű üres részek - tehát ezek maguk a "nem" részletek,
721 míg ezen átlag alattiakat veszem a részletnek.
722
723 mivel a limit alatti oszlopokat nézzük, ezért leosztva magával a limit értékkel, egy
724 0..1 intervallumos arány értéket kapok.
725 */
726 if ((hist_cut_columns == 0) || (temp1 == 0)){ temp2 = 0; }
727 else { temp2 = (double)(hist_cut_weight) / hist_cut_columns / temp1; }
728
729
730 /* itt temp3 értékét úgy határozom meg, hogy az eredeti limit alatti oszlopok számát
731 osztom a histogram középső (levágás utáni) megmaradt szélességével (wp-bp)
732 (de csak a megmaradandó szakaszon, ezért az eredmény 0..1 közötti lesz),
733
734 vagyis minél nagyobb rész esik le bal és jobb oldalt, annál kisebb értékkel osztunk,
735 és ha a limit alatti oszlopok száma egyre több, akkor ezt minél kisebb értékkel osztva
736 annál nagyobb számot kapunk, ezért annál drasztikusabbnak vehetjük az eredetileg alkalmazandó kontrasztot,
737 és ezért ezt az értéket az 5. hatványra emelve és szorozva 3-mal - olyan értéket eredményez,
738 mely 50% fölött egyre nagyobb értéket ad vissza, és itt minél nagyobb az érték,
739 annál jobban csökkentem az eredeti tervezett kontraszt (levágás) mértékét.
740 */
741 temp3 = (double)(hist_cut_columns) / (wp-bp);
742
743 /* itt a lineáris értéket hatványra emeléssel görbítem, hogy a kisebb értékek kevésbé,
744 míg a nagyobb értékek egyre jobban befolyásolják az eredményt */
745 temp3 = temp3 * temp3 * temp3 * temp3 * temp3 * 3;
746 if (temp3 > 1){ temp3 = 1; }
747
748 /* itt temp1 (eredeti limit érték) alatt keletkezett temp2 (új limit érték)
749 limit vonalat visszahúzom felfelé az eredeti temp1 felé a temp3-as görbe alapján.
750
751 vagyis a drasztikus kontrasztot lecsökkentettem, majd vissza engedem a görbe alapján
752 (amelynél kb. 50% után görbül drasztikusan).
753 */
754 temp3 = temp1 - ((temp1 - temp2) * temp3);
755 /* itt nem engedem hogy az új csökkentett limit érték az eredeti 10% alá menjen,
756 ez csupán egy alsó korlát a kontraszt csökkentés mértékéhez */
757 if (temp3 < temp1 * 0.1){ temp1 = temp1 * 0.1; }
758 else{ temp1 = temp3; }
759
760 hist_cut_limit = temp1;
761
762 /* ------------------------------------------------------------ */
763
764
765 bp = 255;
766 flag1 = 0;
767
768 /* histogram jobb oldaláról lépkedek és vágom majd le addig az értékig,
769 amely még kisebb mint az átlag * cont_max (átlag 10 %-a) */
770 for (i1=0; i1<256; i1++){
771 if (flag1 == 0){
772 if (hist1[i1] >= temp1){
773 flag1 = 1;
774 bp = i1;
775 }
776 }
777 }
778
779 wp = 0;
780 flag1 = 0;
781 hist_cut_columns = 0;
782
783 for (i1=255; i1>=0; i1--){
784 if (flag1 == 0){
785 if (hist1[i1] >= temp1){
786 flag1 = 1;
787 wp = i1;
788 }
789 }
790 }
791
792 /* Határértékek beállítása és korrekciója */
793 if (bp > wp){
794 i1 = (long)(wp);
795 wp = bp;
796 bp = i1;
797 }
798 if (bp == wp){
799 bp = bp - 1;
800 wp = wp + 1;
801 }
802 if (bp < 0){ bp = 0; }
803 if (bp >= 255){ bp = 254; }
804 if (wp > 255){ wp = 255; }
805 if (wp <= 0){ wp = 1; }
806
807 bp = bp / 255;
808 wp = wp / 255;
809
810
811
812 /* ------------------------------------------------------------------------------ */
813 /* Get the average RGB values for the White and Black points */
814 /* ------------------------------------------------------------------------------ */
815 /* A színegyensúly beállításához az átlag RGB értékek kiszámítása */
816 /* a fekete és fehér pont értéke alapján */
817
818 /* Itt keletkezik egy átlag RGB érték a fekete és fehér pontokhoz egyaránt */
819 /* Ez az érték azt adja meg, hogy az automatikus kontraszt állításakor */
820 /* minden egyes szín milyen irányba torzul lefelé (fekete pont RGB átlaga) */
821 /* és felfelé (fehér pont RGB átlaga) */
822
823 /* A fehér pont feletti összes szín átlagának RGB-je lesz a viszonyítási pont */
824 /* a fehér írányába való torzításhoz, */
825 /* vagyis ez lesz kihúzva a tökéletes fehérbe */
826
827 /* Ez valóságban a kép színegyensúlyát állítja be megfelelõen úgy, hogy a */
828 /* levágandó mértékû fehérek színátlaga lesz a tökéletes fehér, */
829 /* ezért ha ezek átlaga nem tökéletes fehér, akkor az ettõl eltérõ nagyságot */
830 /* minden színnél arányosan el kell tolni a tökéletes fehér irányába, */
831 /* ugyanez a fekete estében */
832
833 bp_r = 0;
834 bp_g = 0;
835 bp_b = 0;
836 wp_r = 0;
837 wp_g = 0;
838 wp_b = 0;
839
840 i3 = 0;
841 /* fekete pont alatti összes szín RGB átlagának kiszámítása */
842 #ifdef __OPENMP__
843 #pragma omp parallel for reduction(+:bp_r, bp_g, bp_b, i3) num_threads(max_threads2)
844 #endif
845 for (i1=(long)(bp * 255); i1>=0; i1--){
846 bp_r += col_r3[i1];
847 bp_g += col_g3[i1];
848 bp_b += col_b3[i1];
849 i3 += hist1[i1];
850 }
851
852 if (i3 > 0){
853 bp_r = bp_r / i3;
854 bp_g = bp_g / i3;
855 bp_b = bp_b / i3;
856 }
857
858 i3 = 0;
859 /* fehér pont feletti összes szín RGB átlagának kiszámítása */
860 #ifdef __OPENMP__
861 #pragma omp parallel for reduction(+:wp_r, wp_g, wp_b, i3) num_threads(max_threads2)
862 #endif
863 for (i1=(long)(wp * 255); i1<256; i1++){
864 wp_r += col_r3[i1];
865 wp_g += col_g3[i1];
866 wp_b += col_b3[i1];
867 i3 += hist1[i1];
868 }
869 if (i3 > 0){
870 wp_r = wp_r / i3;
871 wp_g = wp_g / i3;
872 wp_b = wp_b / i3;
873 }
874
875 /* skálázás 255-ről a [0..1] intervallumra */
876 bp_r = bp_r / 255;
877 bp_g = bp_g / 255;
878 bp_b = bp_b / 255;
879 wp_r = wp_r / 255;
880 wp_g = wp_g / 255;
881 wp_b = wp_b / 255;
882
883 /* A kapott átlag RGB érték fényerejének visszaállítása a fehér pont szintjére. */
884 /* Mivel ugye nem csak a fehér pont fényerejével azonos színeknek kalkuláltuk ki */
885 /* az átlag színét, hanem az attól világosabb összes színnek, ezért a kapott */
886 /* átlag szín fényereje nagyobb vagy egyenlő lesz, mint a kiindulási fehér pont */
887 /* ezért a korrekcióhoz visszaállítjuk az RGB érték fényerejét */
888 /* de az R, G és B komponensek arányának a megtartásával */
889 /* és ugyanez a fekete pont esetében */
890 RGB_TO_HSL (bp_r, bp_g, bp_b, &H, &S, &L);
891 L = bp;
892 HSL_TO_RGB (H, S, L, &bp_r, &bp_g, &bp_b);
893 RGB_TO_HSL (wp_r, wp_g, wp_b, &H, &S, &L);
894 L = wp;
895 HSL_TO_RGB (H, S, L, &wp_r, &wp_g, &wp_b);
896
897 /* A fekete és fehér pont célpontjának kiszámítása. */
898 /* Ez mutatja meg, hogy a fekete és fehér pont átlag RGB-jét */
899 /* hova kell húzni úgy, hogy az RGB kockában a két csúcsot */
900 /* összekötő 'szürke' egyenessel párhuzamosan tolva a távolsága */
901 /* a 'szürke' egyenestől és a színiránya megmaradjon, */
902 /* de a lehető legsötétebb- vagy legvilágosabb legyen */
903 /* */
904 /* Másképpen fogalmazva eltoljuk a szürke egyenes mentén addig, */
905 /* amíg az RGB kocka falába nem ütközünk (mindkét iránynál) */
906 /* */
907 /* Ez annyiban változtatás az előzőkhöz képest, hogy a fekete pontot */
908 /* most már nem a tökéletes feketébe húzzuk, hanem az annak megfelelő */
909 /* olyan legsötétebb pontba, ahol a maximum a színtelítettség */
910 /* és aminek színe megegyezik a fekete pontéval, */
911 /* ezzel a rossz színegyensúlyt és nem megfelelő kontrasztot küszöbölöm ki. */
912
913 temp3 = bp_r;
914 if (temp3 > bp_g) { temp3 = bp_g; }
915 if (temp3 > bp_b) { temp3 = bp_b; }
916 /*bp_r_end = 1 - (1 - bp_r) / (1 - temp3); */
917 /*bp_g_end = 1 - (1 - bp_g) / (1 - temp3); */
918 /*bp_b_end = 1 - (1 - bp_b) / (1 - temp3); */
919 bp_r_end = bp_r - temp3;
920 bp_g_end = bp_g - temp3;
921 bp_b_end = bp_b - temp3;
922
923 temp3 = wp_r;
924 if (temp3 < wp_g) { temp3 = wp_g; }
925 if (temp3 < wp_b) { temp3 = wp_b; }
926 if (temp3 > 0){
927 wp_r_end = wp_r / temp3;
928 wp_g_end = wp_g / temp3;
929 wp_b_end = wp_b / temp3;
930 }
931
932
933
934 /* ----------------- */
935 /* ---- RGB TÉR ---- */
936 /* ----------------- */
937 /* A teljes RGB teret egy szabályos 3D-s kocka foglalja magába, */
938 /* amelynek 1-1 éle jelenti a R, a G és a B tengelyt */
939 /* és egyik csúcsában található a tökéletes fehér szín, */
940 /* a másik (ezzel szemköti) csúcsában pedig a tökéletes fekete */
941 /* és ezt a két csúcsot összekötő egyenes tartalmazza a */
942 /* feketétől fehérig terjedő teljes szürke skálát. */
943 /* A színeltolás mértéke pedig nem más, mint az adott szín */
944 /* távolsága merőleges írányban szürke skála egyenesétől */
945 /* (amit egy 0 és 1 közötti érték jellemezhet, ahol a 0 */
946 /* azt jelenti, hogy a szín szürke, vagyis az egyenesen található) */
947 /* */
948 /* ------------------------- */
949 /* ---- RGB SZÍN IRÁNYA ---- */
950 /* ------------------------- */
951 /* A fekete és fehér pont átlag eltolási RGB értékét összehasonlítom, */
952 /* hogy megállapítsam, vajon megegyező irányban vannak-e eltolva, */
953 /* mivel ha nem jó a kép színegyensúlya, akkor feltételezem, hogy */
954 /* a kép összes színe a színegyensúly felborulását okozó tényező miatt */
955 /* megegyező irányban tolódik el. Ha nem megegyező irányba mutat */
956 /* az eltolásuk értéke, akkor feltételezem, hogy ez nem azért van, */
957 /* mert a színegyensúly felborult. Ekkor a kontraszt műveletnél nem */
958 /* alkalmazok színegyensúly kiegyenlítést (vagyis a kép színeinek */
959 /* a tökéletes fehér és tökéletes fekete irányába való RGB korrekcióját). */
960 /* */
961 /* Egy adott szín irányán az RGB kockában található pontjából kiinduló */
962 /* merőleges szakasz körülforgási szögét értem a szürke egyenesre nézve. */
963 /* Ennek értéke -180 és 180 fok közé kell hogy essen. */
964 /* Így a fekete és fehér pont átlag RGB színeinek iránya megad két szöget. */
965 /* Ennek különbsége adja meg, hogy milyen mértékkel kell színegyensúly */
966 /* kompenzációt végezni. Minél jobban egyírányba mutatnak, annál erősebb */
967 /* színkompenzáció szükséges. */
968
969
970
971 /* ------------------------------------------------------------------------------------ */
972 /* Get RGB color directions of the White and Black points and change average RGB colors */
973 /* ------------------------------------------------------------------------------------ */
974 /* Megállapítjuk a fekete és fehér pont átlag RGB értékeinek irányát */
975 /* Ez két szöget ad vissza, és ennek a különbségét vizsgáljuk, */
976 /* minél kevésbé eltérő, az átlag RGB értékeket annál jobban lecseréljük */
977 /* a tökéletes fekete és fehér értékre, így a kontraszt állításnál */
978 /* jobban keletkezik színegyensúly korrekció */
979 /* */
980 /* Mivel az irányuk egy 360˚-os szöget zár be, és az eltérő színek 60˚-onként vannak, */
981 /* ezért a 60˚-nál nagyobb eltérést teljesen különbözőnek vesszük. */
982 /* Vagyis a 60˚-nál kisebb eltérésnél toljuk csak el arányosan a fekete és */
983 /* fehér pont célpontját a tökéletes fekete és a tökéletes fehér írányába */
984 /* (vagyis egyező irány esetén teljes színkorrekció lép fel) */
985
986 RGB_TO_HSL (bp_r_end, bp_g_end, bp_b_end, &H, &S, &L);
987 temp1 = H;
988 RGB_TO_HSL (wp_r_end, wp_g_end, wp_b_end, &H, &S, &L);
989 temp2 = H;
990 temp2 = temp2 - temp1;
991
992 /* change value to positive */
993 if (temp2 < 0) { temp2 = 0 - temp2; }
994 /* if angle of direction is larger than 180 degree, then take the smaller section of the circle,
995 it means it'll always be less or equal than 180 deg */
996 if (temp2 > 0.5) { temp2 = 1 - temp2; }
997 /* if the angle is greater then 60 degree, that means the colors are totally different,
998 so i check the amount of difference on this 1/6 intervall only from 0 to 60 degrees. */
999 temp2 = temp2 * 6;
1000 if (temp2 > 1){ temp2 = 1; }
1001
1002 /* raise the value (0..1) of angle difference to 3th power to make color balance a bit more aggressive */
1003 temp2 = temp2 * temp2 * temp2;
1004
1005 /* Ezzel megvan az iránykülönbség értéke egy [0..1] intervallumon, */
1006 /* ahol a 0 a teljes egyezést mutatja */
1007 /* most az egész 'kör' hatod részét vizsgálom csak és */
1008 /* abból alakítok ki egy értéket a [0..1] intervallumon, */
1009 /* hogy majd ezzel szorozni tudjam a fekete pont fényerejét, */
1010 /* vagyis ha egyeznek az írányok, akkor tökéletes feketébe megy el */
1011 /* ugyanez a fehér pont esetében */
1012 if (temp2 < 1) {
1013 RGB_TO_HSL (bp_r_end, bp_g_end, bp_b_end, &H, &S, &L);
1014 L = L * temp2;
1015 HSL_TO_RGB (H, S, L, &bp_r_end, &bp_g_end, &bp_b_end);
1016 RGB_TO_HSL (wp_r_end, wp_g_end, wp_b_end, &H, &S, &L);
1017 L = 1 - (1 - L) * temp2;
1018 HSL_TO_RGB (H, S, L, &wp_r_end, &wp_g_end, &wp_b_end);
1019 }
1020 wp_end = (wp_r_end + wp_g_end + wp_b_end) / 3;
1021 bp_end = (bp_r_end + bp_g_end + bp_b_end) / 3;
1022
1023
1024
1025 /* ------------------------------------------------------------------------------ */
1026 /* Convert original Histogram using White and Black point values */
1027 /* ------------------------------------------------------------------------------ */
1028 /* Eredeti hisztogramból a fekete és fehér pont alapján megváltoztatott */
1029 /* hisztogram létrehozása */
1030
1031 /* Nem az egész kép újraanalizálása, hanem csak az eredeti hisztogramé, */
1032 /* mert így csak 256 értéket kell feldolgozni a kép összes pontjai számának */
1033 /* helyett. Ez a hisztogram az automatikus kontraszt állítás utáni állapotát */
1034 /* mutatja a képnek */
1035
1036 /* Ez a hisztogram lesz felhasználva a gamma súlypont megállapításához */
1037
1038 #ifdef __OPENMP__
1039 #pragma omp parallel for private(temp2, temp3, cc, N) num_threads(max_threads2)
1040 #endif
1041 for (i1=0; i1<256; i1++){
1042
1043 temp2 = (double)(i1) / 255;
1044
1045 /* bp-től és wp-től viszonyított nullára húzással a kontraszt számolás az alábbi */
1046 /*temp2 = bp + ((temp2 - bp) * (1 - bp) / (wp - bp)); */
1047 /*temp2 = 1 - (1 - temp2) * 1 / (1 - bp); */
1048
1049 /* teljes intervallumon számolt húzással a kontraszt számolás az alábbi */
1050 /*temp2 = temp2 * wp_end / wp; */
1051 /* ---> bp = bp * wp_end / wp; */
1052 /* ---> bp_end = bp_end * wp_end / wp; */
1053 /*temp2 = 1 - (1 - temp2) * (1 - bp_end * wp_end / wp) / (1 - bp * wp_end / wp); */
1054
1055 /* bp_end-től és wp_end-től viszonyított bp-ből és wp-ből húzással a kontraszt számolás az alábbi */
1056 if ((temp2 > bp_end) && (wp > bp_end)) {
1057 temp2 = bp_end + (temp2 - bp_end) * (wp_end - bp_end) / (wp - bp_end); }
1058 /* itt a bp fekete pontot is fel kell szorozni a következő számításhoz, */
1059 /* mert a bp_end -től viszonyítva nyújtjuk a skálát jobbra a fehér irányába */
1060 /* és ezért elmászik a bp */
1061 temp3 = 0;
1062 if (wp > bp_end) {
1063 temp3 = bp_end + (bp - bp_end) * (wp_end - bp_end) / (wp - bp_end); }
1064 if ((temp2 < wp_end) && (wp_end != temp3)) {
1065 temp2 = wp_end - (wp_end - temp2) * (wp_end - bp_end) / (wp_end - temp3); }
1066 /*az 'if' utasításoknál mindenhol vizsgálom hogy ne lehessen nullával való osztás */
1067
1068 if (temp2 > 1){ temp2 = 1; }
1069 if (temp2 < 0){ temp2 = 0; }
1070 cc = (long)(temp2 * 255);
1071 #ifdef __OPENMP__
1072 N = omp_get_thread_num();
1073 #else
1074 N = 0;
1075 #endif
1076 hist2n[cc + N*256] += hist1[i1];
1077 }
1078
1079 /* this is a replacement code for arrays for multi processing */
1080 #ifdef __OPENMP__
1081 #pragma omp parallel for private(i1, i2) num_threads(max_threads2)
1082 #endif
1083 for (i1=0; i1<256; i1++){
1084 for (i2=0; i2<max_threads2; i2++){ hist2[i1] += hist2n[i1 + i2*256]; } }
1085
1086
1087
1088 /* ------------------------------------------------------------------------------ */
1089 /* Gamma value calculating */
1090 /* ------------------------------------------------------------------------------ */
1091 /* Gamma súlypont megállapítása a második hisztogram alapján, ami már az */
1092 /* állított kontraszt utáni helyzetet mutatja */
1093 /* A végeredmény azt adja meg, hogy mennyire kell világosítani, vagy éppen */
1094 /* sötétíteni a képet, hogy az össz fényereje a képnek egyensúlyban legyen */
1095
1096 /* A gamma súlypont az az érték, amely a hisztogramban azt mutatja, */
1097 /* hogy tõle balra és jobbra egyaránt egyforma számú képpont található */
1098 /* (vagyis fele a kép összes pontjainak) */
1099
1100 /* Ezt úgy kapjuk meg, hogy elkezdjük olvasni a hisztogram értékeit az */
1101 /* egyik oldalról befelé, és közben össze adjuk a kapott értékeket */
1102 /* Ha ez az érték elérte vagy túllépte a kép összes pontjainak a számának */
1103 /* felét, akkor megállunk és a tömb aktuális indexe adja meg */
1104 /* a gamma súlypont megfelelõ értékét */
1105
1106 /*
1107 gamma_weight_mid_all = 0;
1108 for (i1=0; i1<256; i1++){ gamma_weight_mid_all += hist2[i1]; }
1109 i3 = 0;
1110 flag1 = 0;
1111 gamma_weight_mid = 0;
1112 for (i1=0; i1<256; i1++){
1113 i3 = i3 + hist2[i1];
1114 if (flag1 == 0){
1115 if (i3 > gamma_weight_mid_all / 2){
1116 flag1 = 1;
1117 gamma_weight_mid = i1;
1118 }
1119 }
1120 }
1121 gamma_weight_mid = gamma_weight_low / 255;
1122 gamma_mid = 1;
1123 gamma_mid = log(gamma_interval_mid) / log(gamma_weight_mid);
1124 if (gamma_mid < (1/gamma_max)){ gamma_mid = (1/gamma_max); }
1125 if (gamma_mid > gamma_max){ gamma_mid = gamma_max; }
1126 */
1127 /* Convert CONTRAST Histogram using MID GAMMA VALUE */ /*
1128 for (i1=0; i1<256; i1++){
1129 temp2 = i1;
1130 temp2 = pow(temp2 / 255, gamma_mid) * 255;
1131 i2 = (long)temp2;
1132 if (i2 > 255){ i2 = 255; }
1133 if (i2 < 0){ i2 = 0; }
1134 hist2b[i2] = hist2b[i2] + hist2[i1];
1135 }
1136 */
1137
1138 /* Hisztogramm súlyának megállapítása */
1139 gamma_weight_low_all = 0;
1140 gamma_weight_high_all = 0;
1141
1142 #ifdef __OPENMP__
1143 #pragma omp parallel for reduction(+:gamma_weight_low_all) num_threads(max_threads2)
1144 #endif
1145 for (i1=0; i1<128; i1++){ gamma_weight_low_all += hist2[i1]; }
1146 #ifdef __OPENMP__
1147 #pragma omp parallel for reduction(+:gamma_weight_high_all) num_threads(max_threads2)
1148 #endif
1149 for (i1=128; i1<256; i1++){ gamma_weight_high_all += hist2[i1]; }
1150
1151 /* Hisztogramm súlypont megállapítása */
1152 i3 = 0;
1153 flag1 = 0;
1154 gamma_weight_low = 0;
1155 for (i1=0; i1<128; i1++){
1156 i3 = i3 + hist2[i1];
1157 if (flag1 == 0){
1158 if (i3 > gamma_weight_low_all / 2){
1159 flag1 = 1;
1160 gamma_weight_low = i1;
1161 }
1162 }
1163 }
1164 i3 = 0;
1165 flag1 = 0;
1166 gamma_weight_high = 0;
1167 for (i1=128; i1<256; i1++){
1168 i3 = i3 + hist2[i1];
1169 if (flag1 == 0){
1170 if (i3 > gamma_weight_high_all / 2){
1171 flag1 = 1;
1172 gamma_weight_high = i1;
1173 }
1174 }
1175 }
1176 gamma_weight_low = gamma_weight_low / 255;
1177 gamma_weight_high = gamma_weight_high / 255;
1178
1179 /* Súlypont eltolás szükségességének megállapítása */
1180 gamma_low = 1;
1181 gamma_high = 1;
1182
1183 /* gammát csak egyírányban toljuk el, */
1184 /* vagyis csak világosítunk ha szükséges, de soha sem sötétítünk */
1185 if (gamma_weight_low < gamma_interval_low){
1186 gamma_low = log(gamma_interval_low) / log(gamma_weight_low);
1187 }
1188 if (gamma_weight_high > gamma_interval_high){
1189 gamma_high = log(gamma_interval_high) / log(gamma_weight_high);
1190 }
1191
1192 if (gamma_low < (1/gamma_max)){ gamma_low = (1/gamma_max); }
1193 if (gamma_low > gamma_max){ gamma_low = gamma_max; }
1194 if (gamma_high < (1/gamma_max)){ gamma_high = (1/gamma_max); }
1195 if (gamma_high > gamma_max){ gamma_high = gamma_max; }
1196
1197
1198
1199 /* ------------------------------------------------------------------------------ */
1200 /* Recalculate the RGB values by setting the CONTRAST, COLOR BALANCE and GAMMA */
1201 /* ------------------------------------------------------------------------------ */
1202 /* Kép színeinek újrakalkulálása (kontraszt, színegyensúly és gamma korrekció) */
1203 /* A kép összes pontja újrakalkulálódik és visszaíródik a pufferba */
1204
1205 /* A gamma állításnál a kép színének RGB-jét a gammához mérten nem külön */
1206 /* színcsatornánként, hanem a fényerejükhöz mérten egyben vannnak állítva */
1207 /* A gamma úgy állítódik, hogy a súlypont el van tolva 128-ba */
1208 /* (tehát ha kisebb az értéke akkor növekszik, ha nagyobb, akkor meg csökken) */
1209 /* és ez magával húzza nyújtásos módon arányosan a közép színeket */
1210 /* a 128 irányába */
1211
1212
1213 #ifdef __OPENMP__
1214 #pragma omp parallel for private(x, y, addr, addr2, col_r, col_g, col_b, col_r2, col_g2, col_b2, temp2, temp3, cc, H, S, L, N) num_threads(max_threads2)
1215 #endif
1216 for (y=0; y<=bh-1; y++){
1217 addr2 = y * bw * 3 + y * addr_offset;
1218 for (x=0; x<=bw-1; x++){
1219 addr = addr2 + x * 3;
1220
1221 /* apply changes ONLY on selected area of the image */
1222 if ((apply_on_selection == 0) || ((apply_on_selection) &&
1223 (x >= x1 &&
1224 x <= x2 &&
1225 y >= y1 &&
1226 y <= y2))) {
1227
1228 col_r2 = image_buffer[addr + 0];
1229 col_g2 = image_buffer[addr + 1];
1230 col_b2 = image_buffer[addr + 2];
1231
1232 col_r2 /= 255;
1233 col_g2 /= 255;
1234 col_b2 /= 255;
1235
1236
1237 /* CONTRAST SHIFT AND COLOR BALANCE */
1238 /* bp_end-től és wp_end-től viszonyított bp-ből és wp-ből húzással a kontraszt számolás az alábbi */
1239 if ((col_r2 > bp_r_end) && (wp_r > bp_r_end)) {
1240 col_r2 = bp_r_end + (col_r2 - bp_r_end) * (wp_r_end - bp_r_end) / (wp_r - bp_r_end); }
1241 if ((col_g2 > bp_g_end) && (wp_g > bp_g_end)) {
1242 col_g2 = bp_g_end + (col_g2 - bp_g_end) * (wp_g_end - bp_g_end) / (wp_g - bp_g_end); }
1243 if ((col_b2 > bp_b_end) && (wp_b > bp_b_end)) {
1244 col_b2 = bp_b_end + (col_b2 - bp_b_end) * (wp_b_end - bp_b_end) / (wp_b - bp_b_end); }
1245
1246 /* itt a bp fekete pontot is fel kell szorozni a következő számításhoz, */
1247 /* mert a bp_end -től viszonyítva nyújtjuk a skálát jobbra a fehér irányába */
1248 /* és ezért elmászik a bp */
1249 temp3 = 0;
1250 if (wp_r > bp_r_end) {
1251 temp3 = bp_r_end + (bp_r - bp_r_end) * (wp_r_end - bp_r_end) / (wp_r - bp_r_end); }
1252 if ((col_r2 < wp_r_end) && (wp_r_end != temp3)) {
1253 col_r2 = wp_r_end - (wp_r_end - col_r2) * (wp_r_end - bp_r_end) / (wp_r_end - temp3); }
1254
1255 temp3 = 0;
1256 if (wp_g > bp_g_end) {
1257 temp3 = bp_g_end + (bp_g - bp_g_end) * (wp_g_end - bp_g_end) / (wp_g - bp_g_end); }
1258 if ((col_g2 < wp_g_end) && (wp_g_end != temp3)) {
1259 col_g2 = wp_g_end - (wp_g_end - col_g2) * (wp_g_end - bp_g_end) / (wp_g_end - temp3); }
1260
1261 temp3 = 0;
1262 if (wp_b > bp_b_end) {
1263 temp3 = bp_b_end + (bp_b - bp_b_end) * (wp_b_end - bp_b_end) / (wp_b - bp_b_end); }
1264 if ((col_b2 < wp_b_end) && (wp_b_end != temp3)) {
1265 col_b2 = wp_b_end - (wp_b_end - col_b2) * (wp_b_end - bp_b_end) / (wp_b_end - temp3); }
1266
1267 /* határérték ellenőrzés és visszaírás */
1268 if (col_r2 > 1){ col_r2 = 1; }
1269 if (col_g2 > 1){ col_g2 = 1; }
1270 if (col_b2 > 1){ col_b2 = 1; }
1271 if (col_r2 < 0){ col_r2 = 0; }
1272 if (col_g2 < 0){ col_g2 = 0; }
1273 if (col_b2 < 0){ col_b2 = 0; }
1274
1275
1276 /* GAMMA CORRECTION */
1277 /* megjegyzés: ez a gamma felhúzásos módszer színesebb végeredményt ad */
1278 /* mint amelyiknél külön - külön toljuk a színeket, nem arányosan */
1279 temp2 = (col_r2 + col_g2 + col_b2) / 3;
1280 cc = (long)(temp2 * 255);
1281
1282 /*temp2 = pow(temp2 / 255, gamma_mid) * 255; */
1283 if (temp2 <= 0.5){ temp3 = pow(temp2 * 2, gamma_low) / 2; }
1284 else{ temp3 = pow((temp2 - 0.5) * 2, gamma_high) / 2 + 0.5; }
1285
1286 /*temp3 = pow(temp2 / 255, gamma_exp) * 255; */
1287 if (temp2 < temp3){
1288 if (temp2 < 1){
1289 if (temp2 > 0){
1290 col_r2 = ((1 - (1 - col_r2) * (1 - temp3)
1291 / (1 - temp2)) + (col_r2 * temp3 / temp2)) / 2;
1292 col_g2 = ((1 - (1 - col_g2) * (1 - temp3)
1293 / (1 - temp2)) + (col_g2 * temp3 / temp2)) / 2;
1294 col_b2 = ((1 - (1 - col_b2) * (1 - temp3)
1295 / (1 - temp2)) + (col_b2 * temp3 / temp2)) / 2;
1296 }
1297 }
1298 }
1299 else{
1300 if (temp2 > 0){
1301 col_r2 = col_r2 * temp3 / temp2;
1302 col_g2 = col_g2 * temp3 / temp2;
1303 col_b2 = col_b2 * temp3 / temp2;
1304 }
1305 }
1306
1307 /* határérték ellenőrzés és visszaírás */
1308 if (col_r2 > 1){ col_r2 = 1; }
1309 if (col_g2 > 1){ col_g2 = 1; }
1310 if (col_b2 > 1){ col_b2 = 1; }
1311 if (col_r2 < 0){ col_r2 = 0; }
1312 if (col_g2 < 0){ col_g2 = 0; }
1313 if (col_b2 < 0){ col_b2 = 0; }
1314
1315
1316 col_r = (long)(col_r2 * 255);
1317 col_g = (long)(col_g2 * 255);
1318 col_b = (long)(col_b2 * 255);
1319 image_buffer[addr + 0] = col_r & 0xff;
1320 image_buffer[addr + 1] = col_g & 0xff;
1321 image_buffer[addr + 2] = col_b & 0xff;
1322
1323 /* Build up Histogram for SATURATION */
1324 if (x >= x1 &&
1325 x <= x2 &&
1326 y >= y1 &&
1327 y <= y2) {
1328 double H, S, L;
1329 RGB_TO_HSL (col_r2, col_g2, col_b2, &H, &S, &L);
1330 /* Az 'S' értékét a szürke egyenes közepétől távolodva kisebbnek veszem itt, */
1331 /* mert az optikailag egyre kevésbé tűnik színesnek, */
1332 /* és ennél a résznél optikailag vizsgálok */
1333 if (L > 0.5) { L = 1 - L; }
1334 S = S * L * 2;
1335 /* Ha S = 0, vagyis szürke a szín, akkor nem adom hozzá */
1336 /* a színtelítettség hisztogramjához értelemszerűen */
1337 if (S > 0) {
1338
1339 cc = (long)(S * 255);
1340 #ifdef __OPENMP__
1341 N = omp_get_thread_num();
1342 #else
1343 N = 0;
1344 #endif
1345 hist_saturn[cc + N*256]++;
1346 }
1347 }
1348
1349 }
1350 }
1351 }
1352
1353 /* this is a replacement code for arrays for multi processing */
1354 #ifdef __OPENMP__
1355 #pragma omp parallel for private(i1, i2) num_threads(max_threads2)
1356 #endif
1357 for (i1=0; i1<256; i1++){
1358 for (i2=0; i2<max_threads2; i2++){ hist_satur[i1] += hist_saturn[i1 + i2*256]; } }
1359
1360
1361 /* ------------------------------------------------------------------------------ */
1362 /* Recalculate the RGB values by setting the SATURAION */
1363 /* ------------------------------------------------------------------------------ */
1364
1365 /* Hisztogram átlag értékének megállapítása */
1366 hist_satur_avg = 0;
1367
1368 #ifdef __OPENMP__
1369 #pragma omp parallel for reduction(+:hist_satur_avg) num_threads(max_threads2)
1370 #endif
1371 for (i1=255; i1>=0; i1--){
1372 hist_satur_avg += hist_satur[i1];
1373 }
1374 hist_satur_avg = hist_satur_avg / 255;
1375 /* levágási limit megállapítása, ez az átlag 10%-a bevált a kontrasztnál is,
1376 ezzel az értékkel megfelelően állítja be önmagát a hisztogram,
1377 és a megfelelő nagyságú szélek esnek le */
1378 temp1 = hist_satur_avg * 0.1;
1379
1380 /* Hisztogram szélének keresése a színek felhúzásához */
1381 i3 = 0;
1382 flag1 = 0;
1383 for (i1=255; i1>=0; i1--){
1384 if (flag1 == 0){
1385 if (hist_satur[i1] >= temp1){
1386 flag1 = 1;
1387 i3 = i1;
1388 }
1389 }
1390 }
1391 hist_satur_low = (double)(i3) / 255;
1392
1393 /* Határérték ellenőrzés */
1394 hist_satur_ok = 1;
1395 if (hist_satur_low > satur_max){ hist_satur_low = satur_max; }
1396 if (hist_satur_low > 0){ hist_satur_ok = log(satur_max) / log(hist_satur_low); }
1397
1398 /* run saturation recalculation only if necessary */
1399 if (hist_satur_ok != 1){
1400
1401 #ifdef __OPENMP__
1402 #pragma omp parallel for private(x, y, addr, addr2, col_r, col_g, col_b, col_r2, col_g2, col_b2, H, S, L, cc, N) num_threads(max_threads2)
1403 #endif
1404 for (y=0; y<=bh-1; y++){
1405 addr2 = y * bw * 3 + y * addr_offset;
1406 for (x=0; x<=bw-1; x++){
1407 double S_new;
1408 double S_diff;
1409
1410 addr = addr2 + x * 3;
1411
1412 /* apply changes ONLY on selected area of the image */
1413 if ((apply_on_selection == 0) || ((apply_on_selection) &&
1414 (x >= x1 &&
1415 x <= x2 &&
1416 y >= y1 &&
1417 y <= y2))) {
1418
1419 col_r2 = image_buffer[addr + 0];
1420 col_g2 = image_buffer[addr + 1];
1421 col_b2 = image_buffer[addr + 2];
1422
1423 col_r2 = col_r2 / 255;
1424 col_g2 = col_g2 / 255;
1425 col_b2 = col_b2 / 255;
1426
1427 RGB_TO_HSL (col_r2, col_g2, col_b2, &H, &S, &L);
1428
1429 /* szín telítettségének hatványos emelése a gammához hasonlóan,
1430 vagyis hatványra emelem az eredeti színtelítettség értékét,
1431 és beszorzom a 0.5-től való távolságának kétszeresével,
1432 hogy a 0.5 pontban lévők maximálisan nővekedjenek, míg az ettől
1433 távolabbra lévők egyre kevesebb mértékben, a 0 és 1 helyen lévők pedig semennyire,
1434
1435 másképpen fogalmazva, exponenciálisan állítom, de úgy, hogy a közepéhez
1436 közelebb lévők jobban állítódjanak, míg az ettől egyre távolabb esők kevésbé -
1437 erre azért van így szükség, mert a sima hatványra emelésnél túl drasztikus
1438 a görbe és az alsóbb részei a hisztogramnak is túl nagyot ugranak,
1439 így viszont megfelelő lesz a változás, mindegy mekkora az.
1440 */
1441
1442 if (hist_satur_ok != 1){
1443 S_new = pow(S, hist_satur_ok);
1444 S_diff = 1 - (fabs(0.5 - S) * 2);
1445 S = (S_new - S) * S_diff + S;
1446 }
1447
1448 HSL_TO_RGB (H, S, L, &col_r2, &col_g2, &col_b2);
1449
1450 col_r = (long)(col_r2 * 255);
1451 col_g = (long)(col_g2 * 255);
1452 col_b = (long)(col_b2 * 255);
1453 image_buffer[addr + 0] = col_r & 0xff;
1454 image_buffer[addr + 1] = col_g & 0xff;
1455 image_buffer[addr + 2] = col_b & 0xff;
1456
1457 /*Mellékesen a legvégső Hisztogram létrehozása is */
1458 cc = (long)((double)(col_r + col_g + col_b) / 3);
1459
1460 /*hist3[cc]++; */
1461 /* this is a replacement code for arrays for multi processing */
1462 #ifdef __OPENMP__
1463 N = omp_get_thread_num();
1464 #else
1465 N = 0;
1466 #endif
1467 hist3n[cc + N*256]++;
1468
1469 }
1470 }
1471 }
1472
1473 /* this is a replacement code for arrays for multi processing */
1474 #ifdef __OPENMP__
1475 #pragma omp parallel for private(i1, i2) num_threads(max_threads2)
1476 #endif
1477 for (i1=0; i1<256; i1++){
1478 for (i2=0; i2<max_threads2; i2++){ hist3[i1] += hist3n[i1 + i2*256]; } }
1479
1480 }
1481 /* just copy the former histogram with no change because there was no saturation processing */
1482 else {
1483 for (i1=0; i1<256; i1++){ hist3[i1] = hist2[i1]; }
1484 }
1485
1486
1487 /* a test rész csak akkor működik, ha van math library, mert itt használok szögfüggvényeket */
1488
1489 /* ------------------------------------------------------------------------------ */
1490 /* TEST: Show Histograms by Drawing them on Image */
1491 /* ------------------------------------------------------------------------------ */
1492 /* */
1493 /* csak normál RGB tömbnél élhet a tesztelés */
1494 if ((format_flag == 0) && (test_flag == 1)) {
1495 /* a max érték kezdõértéke 1, hogy 0-val való osztás ne fordulhasson elõ */
1496 long hist1_max = 1;
1497 long hist2_max = 1;
1498 long hist3_max = 1;
1499 long histS_max = 1;
1500
1501 /* Figyelem! Többszöri lefuttatása a rutinnak ugyanazon a képen */
1502 /* nem várt eredményt produkál ha a hisztogrammok is ki vannak rajzolva, */
1503 /* mert akkor már a teszt képet is beleveszi a számításba */
1504 for (i1=0; i1<256; i1++){ if (hist1_max < hist1[i1]) { hist1_max = hist1[i1]; } }
1505 for (i1=0; i1<256; i1++){ if (hist2_max < hist2[i1]) { hist2_max = hist2[i1]; } }
1506 for (i1=0; i1<256; i1++){ if (hist3_max < hist3[i1]) { hist3_max = hist3[i1]; } }
1507 for (i1=0; i1<256; i1++){ if (histS_max < hist_satur[i1]) { histS_max = hist_satur[i1]; } }
1508
1509 for (y=0; y<=bh-1; y++){
1510 addr2 = y * bw * 3 + y * addr_offset;
1511 for (x=0; x<=bw-1; x++){
1512 addr = addr2 + x * 3;
1513 xm = x;
1514 ym = y;
1515 if (format_flag == 1) { ym = bh - 1 - ym; }
1516 if (format_flag == 2) { ym = bh - 1 - ym; }
1517
1518 /* Keret rajzolása a hisztogrammok köré 1 pixel szélességben */
1519 if (((xm == 256) && (ym <= 601)) || ((ym == 601) && (xm <= 256))) {
1520 col = color_black;
1521 image_buffer[addr + 2] = (col >> 0) & 0xff;
1522 image_buffer[addr + 1] = (col >> 8) & 0xff;
1523 image_buffer[addr + 0] = (col >> 16) & 0xff;
1524 }
1525
1526 /* Hisztogrammok kirajzolása */
1527 if ((xm >= 0) && (xm <= 255)) {
1528 double rad, outline, pi;
1529
1530 /* 1. hisztogramm: EREDETI KÉP ÁLLAPOTA KONTRASZT ÁLLÍTÁSSAL*/
1531 if (ym <= 99) {
1532 i2 = hist1[xm] * 99 / hist1_max;
1533 xma1 = (long)(bp * 255);
1534 xmb1 = (long)(wp * 255);
1535 xma2 = (long)(bp_end * 255);
1536 xmb2 = (long)(wp_end * 255);
1537 /* show the average limit with a horizontal line */
1538 if (y == (99 - (long)(hist_cut_limit) * 99 / hist_max)){
1539 col = color_yellow;
1540 }
1541 else{
1542 if (99 - ym >= i2) {
1543 if (((xm > xma2) && (xm < xma1)) || ((xm < xmb2) && (xm > xmb1))) {
1544 col = color_brown;
1545 }
1546 else {
1547 col = color_black;
1548 }
1549 }
1550 else {
1551 col = color_green;
1552 }
1553 }
1554 if (xm == xma1) { col = color_white; }
1555 if (xm == xmb1) { col = color_white; }
1556 image_buffer[addr + 2] = (col >> 0) & 0xff;
1557 image_buffer[addr + 1] = (col >> 8) & 0xff;
1558 image_buffer[addr + 0] = (col >> 16) & 0xff;
1559 }
1560
1561 /* 2. hisztogramm: KONTRASZT UTÁN GAMMA ÁLLÍTÁSSAL */
1562 if ((ym >= 100) && (ym <= 199)) {
1563 i2 = hist2[xm] * 99 / hist2_max;
1564 xma1 = (long)(gamma_weight_low * 255);
1565 xmb1 = (long)(gamma_weight_high * 255);
1566 xma2 = (long)(gamma_interval_low * 255);
1567 xmb2 = (long)(gamma_interval_high * 255);
1568 if (199 - ym >= i2) {
1569 if ((xm < xma2) && (xm > xma1))
1570 {
1571 col = color_brown;
1572 }
1573 else{
1574 /* vörössel jelölöm barna helyett, hogy ez vissza irányú gamma állítás lenne,
1575 ez viszont nem kerül számításra */
1576 if ((xm > xma2) && (xm < xma1))
1577 {
1578 col = color_red;
1579 }
1580 else{
1581 col = color_black;
1582 }
1583 }
1584 }
1585 else {
1586 col = color_green;
1587 }
1588 /* Gamma alsó súlypont */
1589 if (xm == xma1) {
1590 col = color_white;
1591 }
1592 /* Gamma felső súlypont */
1593 /* if (xm == (long)(gamma_weight_high * 255)) {
1594 col = color_white;
1595 }*/
1596 image_buffer[addr + 2] = (col >> 0) & 0xff;
1597 image_buffer[addr + 1] = (col >> 8) & 0xff;
1598 image_buffer[addr + 0] = (col >> 16) & 0xff;
1599 }
1600
1601 /* 3. hisztogramm SZÍNTELÍTETTSÉG ÁLLÍTÁSSAL */
1602 if ((ym >= 200) && (ym <= 299)) {
1603 i2 = hist_satur[xm] * 99 / histS_max;
1604 xma1 = (long)((hist_satur_low)* 255);
1605 xma2 = (long)(satur_max * 255);
1606 if (299 - ym >= i2) {
1607 if (((xm < xma2) && (xm > xma1)) || ((xm > xma2) && (xm < xma1)))
1608 {
1609 col = color_brown;
1610 }
1611 else{
1612 col = color_black;
1613 }
1614 }
1615 else {
1616 col = color_blue;
1617 }
1618 if (xm == xma1) { col = color_white; }
1619 image_buffer[addr + 2] = (col >> 0) & 0xff;
1620 image_buffer[addr + 1] = (col >> 8) & 0xff;
1621 image_buffer[addr + 0] = (col >> 16) & 0xff;
1622 }
1623
1624 /* 4. hisztogramm: KONTRASZT, GAMMA és SZÍNTELÍTETTSÉG UTÁN (VÉGSŐ) */
1625 if ((ym >= 300) && (ym <= 399)) {
1626 i2 = hist3[xm] * 99 / hist3_max;
1627 if (399 - ym >= i2) {
1628 col = color_black;
1629 }
1630 else {
1631 col = color_green;
1632 }
1633 image_buffer[addr + 2] = (col >> 0) & 0xff;
1634 image_buffer[addr + 1] = (col >> 8) & 0xff;
1635 image_buffer[addr + 0] = (col >> 16) & 0xff;
1636 }
1637
1638 /* 5. Fekete és fehér pont színirányának kirajzolása egy körbe */
1639 /* konstans a kör sugarához */
1640 rad = 100;
1641 /* konstans a körvonal vastagságához */
1642 outline = 10;
1643 /* pi értéke */
1644 pi = 3.1415926535897932;
1645 if ((ym >= 400) && (ym <= 400+rad*2)) {
1646 double rr, rx, ry;
1647
1648 rx = xm - rad;
1649 ry = ym - 400 - rad;
1650 rr = sqrt(rx*rx + ry*ry);
1651
1652 /* KÖRÍV MEGRAJZOLÁSA */
1653 if ((rr <= rad) && (rr >= rad-outline)) {
1654 H = 0;
1655 if ((rx >= 0) && (ry < 0)) { H = asin( rx / rr) / pi / 2 + 0.00; }
1656 if ((rx >= 0) && (ry >= 0)) { H = asin( ry / rr) / pi / 2 + 0.25; }
1657 if ((rx < 0) && (ry >= 0)) { H = asin(-rx / rr) / pi / 2 + 0.50; }
1658 if ((rx < 0) && (ry < 0)) { H = asin(-ry / rr) / pi / 2 + 0.75; }
1659 S = 1;
1660 L = 0.5;
1661 L = rad - rr;
1662 if (L > outline / 2) { L = outline - L; }
1663 L = L / outline;
1664 HSL_TO_RGB (H, S, L, &col_r2, &col_g2, &col_b2);
1665 col_r = (long)(col_r2 * 255);
1666 col_g = (long)(col_g2 * 255);
1667 col_b = (long)(col_b2 * 255);
1668 image_buffer[addr + 0] = col_r & 0xff;
1669 image_buffer[addr + 1] = col_g & 0xff;
1670 image_buffer[addr + 2] = col_b & 0xff;
1671 }
1672 else {
1673 double px, py, lx, ly, d;
1674
1675 col = color_black;
1676 px = 0; py = 0;
1677 lx = 0; ly = 0;
1678
1679 /* FEKETE PONT SZÍNIRÁNYA EGYENESÉNEK MEGHÚZÁSA */
1680 /* Szürke pontnál nem jelenik meg egyenes a körben */
1681 RGB_TO_HSL (bp_r, bp_g, bp_b, &H, &S, &L);
1682
1683 if ((H >= 0.00) && (H < 0.25)) { lx = sin((H - 0.00) * 2 * pi) * rr; ly = cos((H - 0.00) * 2 * pi) * rr; }
1684 if ((H >= 0.25) && (H < 0.50)) { lx = cos((H - 0.25) * 2 * pi) * rr; ly = -sin((H - 0.25) * 2 * pi) * rr; }
1685 if ((H >= 0.50) && (H < 0.75)) { lx = -sin((H - 0.50) * 2 * pi) * rr; ly = -cos((H - 0.50) * 2 * pi) * rr; }
1686 if ((H >= 0.75) && (H < 1.00)) { lx = -cos((H - 0.75) * 2 * pi) * rr; ly = sin((H - 0.75) * 2 * pi) * rr; }
1687 px = lx * S;
1688 py = ly * S;
1689
1690 d = ly * rx + lx * ry;
1691 d = d / sqrt(lx * lx + ly * ly);
1692 if (d < 0) { d = 0 - d; }
1693
1694 if ((d < 1) && (rr < rad) && (sgn(rx) == sgn(px)) && (sgn(ry) == -sgn(py))) {
1695 if (rr < rad * S) { col = color_white; }
1696 else { col = color_gray; }
1697 }
1698
1699 /* FEHÉR PONT SZÍNIRÁNYA EGYENESÉNEK MEGHÚZÁSA */
1700 RGB_TO_HSL (wp_r, wp_g, wp_b, &H, &S, &L);
1701
1702 if ((H >= 0.00) && (H < 0.25)) { lx = sin((H - 0.00) * 2 * pi) * rr; ly = cos((H - 0.00) * 2 * pi) * rr; }
1703 if ((H >= 0.25) && (H < 0.50)) { lx = cos((H - 0.25) * 2 * pi) * rr; ly = -sin((H - 0.25) * 2 * pi) * rr; }
1704 if ((H >= 0.50) && (H < 0.75)) { lx = -sin((H - 0.50) * 2 * pi) * rr; ly = -cos((H - 0.50) * 2 * pi) * rr; }
1705 if ((H >= 0.75) && (H < 1.00)) { lx = -cos((H - 0.75) * 2 * pi) * rr; ly = sin((H - 0.75) * 2 * pi) * rr; }
1706 px = lx * S;
1707 py = ly * S;
1708
1709 d = ly * rx + lx * ry;
1710 d = d / sqrt(lx * lx + ly * ly);
1711 if (d < 0) { d = 0 - d; }
1712
1713 if ((d < 1) && (rr < rad) && (sgn(rx) == sgn(px)) && (sgn(ry) == -sgn(py))) {
1714 if (rr < rad * S) { col = color_white; }
1715 else { col = color_gray; }
1716 }
1717
1718 image_buffer[addr + 2] = (col >> 0) & 0xff;
1719 image_buffer[addr + 1] = (col >> 8) & 0xff;
1720 image_buffer[addr + 0] = (col >> 16) & 0xff;
1721
1722 }
1723 }
1724 }
1725 }
1726 }
1727 }
1728
1729
1730 exit:
1731
1732 if (hist_saturn){ free (hist_saturn); }
1733 if (hist1n) { free (hist1n); }
1734 if (hist2n) { free (hist2n); }
1735 if (hist3n) { free (hist3n); }
1736 if (col_r3n) { free (col_r3n); }
1737 if (col_g3n) { free (col_g3n); }
1738 if (col_b3n) { free (col_b3n); }
1739
1740 }
1741
1742
1743
1744 /* ------------------------------ */
1745 /* ----- MAIN AARGB ENTRIES ----- */
1746 /* ------------------------------ */
1747
AARGB_NORMAL(unsigned char * image_buffer,int image_width,int image_height)1748 void AARGB_NORMAL(
1749 unsigned char *image_buffer,
1750 int image_width,
1751 int image_height)
1752 {
1753 AARGB_MAIN(
1754 image_buffer,
1755 image_width,
1756 image_height,
1757 0,
1758 0,
1759 image_width-1,
1760 image_height-1,
1761 0,
1762 0,
1763 0);
1764 }
1765
AARGB_NORMAL_SEL(unsigned char * image_buffer,int image_width,int image_height,int x1,int y1,int x2,int y2,int apply_on_selection)1766 void AARGB_NORMAL_SEL(
1767 unsigned char *image_buffer,
1768 int image_width,
1769 int image_height,
1770 int x1,
1771 int y1,
1772 int x2,
1773 int y2,
1774 int apply_on_selection)
1775 {
1776 AARGB_MAIN(
1777 image_buffer,
1778 image_width,
1779 image_height,
1780 x1,
1781 y1,
1782 x2,
1783 y2,
1784 0,
1785 apply_on_selection,
1786 0);
1787 }
1788
AARGB_DIB(unsigned char * image_buffer,int image_width,int image_height)1789 void AARGB_DIB(
1790 unsigned char *image_buffer,
1791 int image_width,
1792 int image_height)
1793 {
1794 AARGB_MAIN(
1795 image_buffer,
1796 image_width,
1797 image_height,
1798 0,
1799 0,
1800 image_width-1,
1801 image_height-1,
1802 1,
1803 0,
1804 0);
1805 }
1806
AARGB_DIB_SEL(unsigned char * image_buffer,int image_width,int image_height,int x1,int y1,int x2,int y2,int apply_on_selection)1807 void AARGB_DIB_SEL(
1808 unsigned char *image_buffer,
1809 int image_width,
1810 int image_height,
1811 int x1,
1812 int y1,
1813 int x2,
1814 int y2,
1815 int apply_on_selection)
1816 {
1817 AARGB_MAIN(
1818 image_buffer,
1819 image_width,
1820 image_height,
1821 x1,
1822 y1,
1823 x2,
1824 y2,
1825 1,
1826 apply_on_selection,
1827 0);
1828 }
1829
AARGB_BMP(unsigned char * image_buffer)1830 void AARGB_BMP(
1831 unsigned char *image_buffer)
1832 {
1833 long f_bm;
1834 long f_bitcount;
1835 long f_compressed;
1836 long f_offs;
1837 long f_width;
1838 long f_height;
1839
1840 f_bm = 0;
1841 f_bm += image_buffer[0] << 0;
1842 f_bm += image_buffer[1] << 8;
1843
1844 f_bitcount = 0;
1845 f_bitcount += image_buffer[28] << 0;
1846 f_bitcount += image_buffer[29] << 8;
1847
1848 f_compressed = 0;
1849 f_compressed += image_buffer[30] << 0;
1850 f_compressed += image_buffer[31] << 8;
1851 f_compressed += image_buffer[32] << 16;
1852 f_compressed += image_buffer[33] << 24;
1853
1854 if ((f_bm == 0x00004d42) && (f_bitcount == 24) && (f_compressed == 0)) {
1855
1856 f_offs = 0;
1857 f_offs += image_buffer[10] << 0;
1858 f_offs += image_buffer[11] << 8;
1859 f_offs += image_buffer[12] << 16;
1860 f_offs += image_buffer[13] << 24;
1861
1862 f_width = 0;
1863 f_width += image_buffer[18] << 0;
1864 f_width += image_buffer[19] << 8;
1865 f_width += image_buffer[20] << 16;
1866 f_width += image_buffer[21] << 24;
1867
1868 f_height = 0;
1869 f_height += image_buffer[22] << 0;
1870 f_height += image_buffer[23] << 8;
1871 f_height += image_buffer[24] << 16;
1872 f_height += image_buffer[25] << 24;
1873
1874 AARGB_MAIN(
1875 image_buffer + f_offs,
1876 f_width,
1877 f_height,
1878 0,
1879 0,
1880 f_width-1,
1881 f_height-1,
1882 2,
1883 0,
1884 0);
1885 }
1886 }
1887
AARGB_BMP_SEL(unsigned char * image_buffer,int x1,int y1,int x2,int y2,int apply_on_selection)1888 void AARGB_BMP_SEL(
1889 unsigned char *image_buffer,
1890 int x1,
1891 int y1,
1892 int x2,
1893 int y2,
1894 int apply_on_selection)
1895 {
1896 long f_bm;
1897 long f_bitcount;
1898 long f_compressed;
1899 long f_offs;
1900 long f_width;
1901 long f_height;
1902
1903 f_bm = 0;
1904 f_bm += image_buffer[0] << 0;
1905 f_bm += image_buffer[1] << 8;
1906
1907 f_bitcount = 0;
1908 f_bitcount += image_buffer[28] << 0;
1909 f_bitcount += image_buffer[29] << 8;
1910
1911 f_compressed = 0;
1912 f_compressed += image_buffer[30] << 0;
1913 f_compressed += image_buffer[31] << 8;
1914 f_compressed += image_buffer[32] << 16;
1915 f_compressed += image_buffer[33] << 24;
1916
1917 if ((f_bm == 0x00004d42) && (f_bitcount == 24) && (f_compressed == 0)) {
1918
1919 f_offs = 0;
1920 f_offs += image_buffer[10] << 0;
1921 f_offs += image_buffer[11] << 8;
1922 f_offs += image_buffer[12] << 16;
1923 f_offs += image_buffer[13] << 24;
1924
1925 f_width = 0;
1926 f_width += image_buffer[18] << 0;
1927 f_width += image_buffer[19] << 8;
1928 f_width += image_buffer[20] << 16;
1929 f_width += image_buffer[21] << 24;
1930
1931 f_height = 0;
1932 f_height += image_buffer[22] << 0;
1933 f_height += image_buffer[23] << 8;
1934 f_height += image_buffer[24] << 16;
1935 f_height += image_buffer[25] << 24;
1936
1937 AARGB_MAIN(
1938 image_buffer + f_offs,
1939 f_width,
1940 f_height,
1941 x1,
1942 y1,
1943 x2,
1944 y2,
1945 2,
1946 apply_on_selection,
1947 0);
1948 }
1949 }
1950
1951
1952
1953
1954 /*
1955 int main (){
1956 return 0;
1957 }
1958 */
1959