Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
colorspace.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
85#ifdef HAVE_CONFIG_H
86#include <config_auto.h>
87#endif /* HAVE_CONFIG_H */
88
89#include <string.h>
90#include <math.h>
91#include "allheaders.h"
92
93#ifndef NO_CONSOLE_IO
94#define DEBUG_HISTO 0
95#define SLOW_CUBE_ROOT 0
96#endif /* ~NO_CONSOLE_IO */
97
98 /* Functions used in xyz <--> lab conversions */
99static l_float32 lab_forward(l_float32 v);
100static l_float32 lab_reverse(l_float32 v);
101
102/*---------------------------------------------------------------------------*
103 * Colorspace conversion between RGB and HSB *
104 *---------------------------------------------------------------------------*/
141PIX *
143 PIX *pixs)
144{
145l_int32 w, h, d, wpl, i, j, rval, gval, bval, hval, sval, vval;
146l_uint32 *line, *data;
147PIXCMAP *cmap;
148
149 if (!pixs)
150 return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
151 if (pixd && pixd != pixs)
152 return (PIX *)ERROR_PTR("pixd defined and not inplace", __func__, pixd);
153
154 d = pixGetDepth(pixs);
155 cmap = pixGetColormap(pixs);
156 if (!cmap && d != 32)
157 return (PIX *)ERROR_PTR("not cmapped or rgb", __func__, pixd);
158
159 if (!pixd)
160 pixd = pixCopy(NULL, pixs);
161
162 cmap = pixGetColormap(pixd);
163 if (cmap) { /* just convert the colormap */
165 return pixd;
166 }
167
168 /* Convert RGB image */
169 pixGetDimensions(pixd, &w, &h, NULL);
170 wpl = pixGetWpl(pixd);
171 data = pixGetData(pixd);
172 for (i = 0; i < h; i++) {
173 line = data + i * wpl;
174 for (j = 0; j < w; j++) {
175 extractRGBValues(line[j], &rval, &gval, &bval);
176 convertRGBToHSV(rval, gval, bval, &hval, &sval, &vval);
177 line[j] = (hval << 24) | (sval << 16) | (vval << 8);
178 }
179 }
180
181 return pixd;
182}
183
184
203PIX *
205 PIX *pixs)
206{
207l_int32 w, h, d, wpl, i, j, rval, gval, bval, hval, sval, vval;
208l_uint32 pixel;
209l_uint32 *line, *data;
210PIXCMAP *cmap;
211
212 if (!pixs)
213 return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
214 if (pixd && pixd != pixs)
215 return (PIX *)ERROR_PTR("pixd defined and not inplace", __func__, pixd);
216
217 d = pixGetDepth(pixs);
218 cmap = pixGetColormap(pixs);
219 if (!cmap && d != 32)
220 return (PIX *)ERROR_PTR("not cmapped or hsv", __func__, pixd);
221
222 if (!pixd)
223 pixd = pixCopy(NULL, pixs);
224
225 cmap = pixGetColormap(pixd);
226 if (cmap) { /* just convert the colormap */
228 return pixd;
229 }
230
231 /* Convert HSV image */
232 pixGetDimensions(pixd, &w, &h, NULL);
233 wpl = pixGetWpl(pixd);
234 data = pixGetData(pixd);
235 for (i = 0; i < h; i++) {
236 line = data + i * wpl;
237 for (j = 0; j < w; j++) {
238 pixel = line[j];
239 hval = pixel >> 24;
240 sval = (pixel >> 16) & 0xff;
241 vval = (pixel >> 8) & 0xff;
242 convertHSVToRGB(hval, sval, vval, &rval, &gval, &bval);
243 composeRGBPixel(rval, gval, bval, line + j);
244 }
245 }
246
247 return pixd;
248}
249
250
276l_ok
277convertRGBToHSV(l_int32 rval,
278 l_int32 gval,
279 l_int32 bval,
280 l_int32 *phval,
281 l_int32 *psval,
282 l_int32 *pvval)
283{
284l_int32 minrg, maxrg, min, max, delta;
285l_float32 h;
286
287 if (phval) *phval = 0;
288 if (psval) *psval = 0;
289 if (pvval) *pvval = 0;
290 if (!phval || !psval || !pvval)
291 return ERROR_INT("&hval, &sval, &vval not all defined", __func__, 1);
292
293 minrg = L_MIN(rval, gval);
294 min = L_MIN(minrg, bval);
295 maxrg = L_MAX(rval, gval);
296 max = L_MAX(maxrg, bval);
297 delta = max - min;
298
299 *pvval = max;
300 if (delta == 0) { /* gray; no chroma */
301 *phval = 0;
302 *psval = 0;
303 } else {
304 *psval = (l_int32)(255. * (l_float32)delta / (l_float32)max + 0.5);
305 if (rval == max) /* between magenta and yellow */
306 h = (l_float32)(gval - bval) / (l_float32)delta;
307 else if (gval == max) /* between yellow and cyan */
308 h = 2. + (l_float32)(bval - rval) / (l_float32)delta;
309 else /* between cyan and magenta */
310 h = 4. + (l_float32)(rval - gval) / (l_float32)delta;
311 h *= 40.0;
312 if (h < 0.0)
313 h += 240.0;
314 if (h >= 239.5)
315 h = 0.0;
316 *phval = (l_int32)(h + 0.5);
317 }
318
319 return 0;
320}
321
322
336l_ok
337convertHSVToRGB(l_int32 hval,
338 l_int32 sval,
339 l_int32 vval,
340 l_int32 *prval,
341 l_int32 *pgval,
342 l_int32 *pbval)
343{
344l_int32 i, x, y, z;
345l_float32 h, f, s;
346
347 if (prval) *prval = 0;
348 if (pgval) *pgval = 0;
349 if (pbval) *pbval = 0;
350 if (!prval || !pgval || !pbval)
351 return ERROR_INT("&rval, &gval, &bval not all defined", __func__, 1);
352
353 if (sval == 0) { /* gray */
354 *prval = vval;
355 *pgval = vval;
356 *pbval = vval;
357 } else {
358 if (hval < 0 || hval > 240)
359 return ERROR_INT("invalid hval", __func__, 1);
360 if (hval == 240)
361 hval = 0;
362 h = (l_float32)hval / 40.;
363 i = (l_int32)h;
364 f = h - i;
365 s = (l_float32)sval / 255.;
366 x = (l_int32)(vval * (1. - s) + 0.5);
367 y = (l_int32)(vval * (1. - s * f) + 0.5);
368 z = (l_int32)(vval * (1. - s * (1. - f)) + 0.5);
369 switch (i)
370 {
371 case 0:
372 *prval = vval;
373 *pgval = z;
374 *pbval = x;
375 break;
376 case 1:
377 *prval = y;
378 *pgval = vval;
379 *pbval = x;
380 break;
381 case 2:
382 *prval = x;
383 *pgval = vval;
384 *pbval = z;
385 break;
386 case 3:
387 *prval = x;
388 *pgval = y;
389 *pbval = vval;
390 break;
391 case 4:
392 *prval = z;
393 *pgval = x;
394 *pbval = vval;
395 break;
396 case 5:
397 *prval = vval;
398 *pgval = x;
399 *pbval = y;
400 break;
401 default: /* none possible */
402 return 1;
403 }
404 }
405
406 return 0;
407}
408
409
423l_ok
425{
426l_int32 i, ncolors, rval, gval, bval, hval, sval, vval;
427
428 if (!cmap)
429 return ERROR_INT("cmap not defined", __func__, 1);
430
431 ncolors = pixcmapGetCount(cmap);
432 for (i = 0; i < ncolors; i++) {
433 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
434 convertRGBToHSV(rval, gval, bval, &hval, &sval, &vval);
435 pixcmapResetColor(cmap, i, hval, sval, vval);
436 }
437 return 0;
438}
439
440
454l_ok
456{
457l_int32 i, ncolors, rval, gval, bval, hval, sval, vval;
458
459 if (!cmap)
460 return ERROR_INT("cmap not defined", __func__, 1);
461
462 ncolors = pixcmapGetCount(cmap);
463 for (i = 0; i < ncolors; i++) {
464 pixcmapGetColor(cmap, i, &hval, &sval, &vval);
465 convertHSVToRGB(hval, sval, vval, &rval, &gval, &bval);
466 pixcmapResetColor(cmap, i, rval, gval, bval);
467 }
468 return 0;
469}
470
471
487PIX *
489{
490l_int32 w, h, d, wplt, wpld;
491l_int32 i, j, rval, gval, bval, hval, minrg, min, maxrg, max, delta;
492l_float32 fh;
493l_uint32 pixel;
494l_uint32 *linet, *lined, *datat, *datad;
495PIX *pixt, *pixd;
496
497 if (!pixs)
498 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
499
500 pixGetDimensions(pixs, &w, &h, &d);
501 if (d != 32 && !pixGetColormap(pixs))
502 return (PIX *)ERROR_PTR("not cmapped or rgb", __func__, NULL);
503 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
504
505 /* Convert RGB image */
506 pixd = pixCreate(w, h, 8);
507 pixCopyResolution(pixd, pixs);
508 wplt = pixGetWpl(pixt);
509 datat = pixGetData(pixt);
510 wpld = pixGetWpl(pixd);
511 datad = pixGetData(pixd);
512 for (i = 0; i < h; i++) {
513 linet = datat + i * wplt;
514 lined = datad + i * wpld;
515 for (j = 0; j < w; j++) {
516 pixel = linet[j];
517 extractRGBValues(pixel, &rval, &gval, &bval);
518 minrg = L_MIN(rval, gval);
519 min = L_MIN(minrg, bval);
520 maxrg = L_MAX(rval, gval);
521 max = L_MAX(maxrg, bval);
522 delta = max - min;
523 if (delta == 0) { /* gray; no chroma */
524 hval = 0;
525 } else {
526 if (rval == max) /* between magenta and yellow */
527 fh = (l_float32)(gval - bval) / (l_float32)delta;
528 else if (gval == max) /* between yellow and cyan */
529 fh = 2. + (l_float32)(bval - rval) / (l_float32)delta;
530 else /* between cyan and magenta */
531 fh = 4. + (l_float32)(rval - gval) / (l_float32)delta;
532 fh *= 40.0;
533 if (fh < 0.0)
534 fh += 240.0;
535 hval = (l_int32)(fh + 0.5);
536 }
537 SET_DATA_BYTE(lined, j, hval);
538 }
539 }
540 pixDestroy(&pixt);
541
542 return pixd;
543}
544
545
546
561PIX *
563{
564l_int32 w, h, d, wplt, wpld;
565l_int32 i, j, rval, gval, bval, sval, minrg, min, maxrg, max, delta;
566l_uint32 pixel;
567l_uint32 *linet, *lined, *datat, *datad;
568PIX *pixt, *pixd;
569
570 if (!pixs)
571 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
572
573 pixGetDimensions(pixs, &w, &h, &d);
574 if (d != 32 && !pixGetColormap(pixs))
575 return (PIX *)ERROR_PTR("not cmapped or rgb", __func__, NULL);
576 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
577
578 /* Convert RGB image */
579 pixd = pixCreate(w, h, 8);
580 pixCopyResolution(pixd, pixs);
581 wplt = pixGetWpl(pixt);
582 datat = pixGetData(pixt);
583 wpld = pixGetWpl(pixd);
584 datad = pixGetData(pixd);
585 for (i = 0; i < h; i++) {
586 linet = datat + i * wplt;
587 lined = datad + i * wpld;
588 for (j = 0; j < w; j++) {
589 pixel = linet[j];
590 extractRGBValues(pixel, &rval, &gval, &bval);
591 minrg = L_MIN(rval, gval);
592 min = L_MIN(minrg, bval);
593 maxrg = L_MAX(rval, gval);
594 max = L_MAX(maxrg, bval);
595 delta = max - min;
596 if (delta == 0) /* gray; no chroma */
597 sval = 0;
598 else
599 sval = (l_int32)(255. *
600 (l_float32)delta / (l_float32)max + 0.5);
601 SET_DATA_BYTE(lined, j, sval);
602 }
603 }
604
605 pixDestroy(&pixt);
606 return pixd;
607}
608
609
624PIX *
626{
627l_int32 w, h, d, wplt, wpld;
628l_int32 i, j, rval, gval, bval, maxrg, max;
629l_uint32 pixel;
630l_uint32 *linet, *lined, *datat, *datad;
631PIX *pixt, *pixd;
632
633 if (!pixs)
634 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
635
636 pixGetDimensions(pixs, &w, &h, &d);
637 if (d != 32 && !pixGetColormap(pixs))
638 return (PIX *)ERROR_PTR("not cmapped or rgb", __func__, NULL);
639 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
640
641 /* Convert RGB image */
642 pixd = pixCreate(w, h, 8);
643 pixCopyResolution(pixd, pixs);
644 wplt = pixGetWpl(pixt);
645 datat = pixGetData(pixt);
646 wpld = pixGetWpl(pixd);
647 datad = pixGetData(pixd);
648 for (i = 0; i < h; i++) {
649 linet = datat + i * wplt;
650 lined = datad + i * wpld;
651 for (j = 0; j < w; j++) {
652 pixel = linet[j];
653 extractRGBValues(pixel, &rval, &gval, &bval);
654 maxrg = L_MAX(rval, gval);
655 max = L_MAX(maxrg, bval);
656 SET_DATA_BYTE(lined, j, max);
657 }
658 }
659
660 pixDestroy(&pixt);
661 return pixd;
662}
663
664
665/*---------------------------------------------------------------------------*
666 * Selection and display of range of colors in HSV space *
667 *---------------------------------------------------------------------------*/
691PIX *
693 l_int32 huecenter,
694 l_int32 huehw,
695 l_int32 satcenter,
696 l_int32 sathw,
697 l_int32 regionflag)
698{
699l_int32 i, j, w, h, wplt, wpld, hstart, hend, sstart, send, hval, sval;
700l_int32 *hlut, *slut;
701l_uint32 pixel;
702l_uint32 *datat, *datad, *linet, *lined;
703PIX *pixt, *pixd;
704
705 if (!pixs || pixGetDepth(pixs) != 32)
706 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
707 if (regionflag != L_INCLUDE_REGION && regionflag != L_EXCLUDE_REGION)
708 return (PIX *)ERROR_PTR("invalid regionflag", __func__, NULL);
709
710 /* Set up LUTs for hue and saturation. These have the value 1
711 * within the specified intervals of hue and saturation. */
712 hlut = (l_int32 *)LEPT_CALLOC(240, sizeof(l_int32));
713 slut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
714 sstart = L_MAX(0, satcenter - sathw);
715 send = L_MIN(255, satcenter + sathw);
716 for (i = sstart; i <= send; i++)
717 slut[i] = 1;
718 hstart = (huecenter - huehw + 240) % 240;
719 hend = (huecenter + huehw + 240) % 240;
720 if (hstart < hend) {
721 for (i = hstart; i <= hend; i++)
722 hlut[i] = 1;
723 } else { /* wrap */
724 for (i = hstart; i < 240; i++)
725 hlut[i] = 1;
726 for (i = 0; i <= hend; i++)
727 hlut[i] = 1;
728 }
729
730 /* Generate the mask */
731 pixt = pixConvertRGBToHSV(NULL, pixs);
732 pixGetDimensions(pixs, &w, &h, NULL);
733 pixd = pixCreate(w, h, 1);
734 if (regionflag == L_INCLUDE_REGION)
735 pixClearAll(pixd);
736 else /* L_EXCLUDE_REGION */
737 pixSetAll(pixd);
738 datat = pixGetData(pixt);
739 datad = pixGetData(pixd);
740 wplt = pixGetWpl(pixt);
741 wpld = pixGetWpl(pixd);
742 for (i = 0; i < h; i++) {
743 linet = datat + i * wplt;
744 lined = datad + i * wpld;
745 for (j = 0; j < w; j++) {
746 pixel = linet[j];
747 hval = (pixel >> L_RED_SHIFT) & 0xff;
748 sval = (pixel >> L_GREEN_SHIFT) & 0xff;
749 if (hlut[hval] == 1 && slut[sval] == 1) {
750 if (regionflag == L_INCLUDE_REGION)
751 SET_DATA_BIT(lined, j);
752 else /* L_EXCLUDE_REGION */
753 CLEAR_DATA_BIT(lined, j);
754 }
755 }
756 }
757
758 LEPT_FREE(hlut);
759 LEPT_FREE(slut);
760 pixDestroy(&pixt);
761 return pixd;
762}
763
764
788PIX *
790 l_int32 huecenter,
791 l_int32 huehw,
792 l_int32 valcenter,
793 l_int32 valhw,
794 l_int32 regionflag)
795{
796l_int32 i, j, w, h, wplt, wpld, hstart, hend, vstart, vend, hval, vval;
797l_int32 *hlut, *vlut;
798l_uint32 pixel;
799l_uint32 *datat, *datad, *linet, *lined;
800PIX *pixt, *pixd;
801
802 if (!pixs || pixGetDepth(pixs) != 32)
803 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
804 if (regionflag != L_INCLUDE_REGION && regionflag != L_EXCLUDE_REGION)
805 return (PIX *)ERROR_PTR("invalid regionflag", __func__, NULL);
806
807 /* Set up LUTs for hue and maximum intensity (val). These have
808 * the value 1 within the specified intervals of hue and value. */
809 hlut = (l_int32 *)LEPT_CALLOC(240, sizeof(l_int32));
810 vlut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
811 vstart = L_MAX(0, valcenter - valhw);
812 vend = L_MIN(255, valcenter + valhw);
813 for (i = vstart; i <= vend; i++)
814 vlut[i] = 1;
815 hstart = (huecenter - huehw + 240) % 240;
816 hend = (huecenter + huehw + 240) % 240;
817 if (hstart < hend) {
818 for (i = hstart; i <= hend; i++)
819 hlut[i] = 1;
820 } else {
821 for (i = hstart; i < 240; i++)
822 hlut[i] = 1;
823 for (i = 0; i <= hend; i++)
824 hlut[i] = 1;
825 }
826
827 /* Generate the mask */
828 pixt = pixConvertRGBToHSV(NULL, pixs);
829 pixGetDimensions(pixs, &w, &h, NULL);
830 pixd = pixCreate(w, h, 1);
831 if (regionflag == L_INCLUDE_REGION)
832 pixClearAll(pixd);
833 else /* L_EXCLUDE_REGION */
834 pixSetAll(pixd);
835 datat = pixGetData(pixt);
836 datad = pixGetData(pixd);
837 wplt = pixGetWpl(pixt);
838 wpld = pixGetWpl(pixd);
839 for (i = 0; i < h; i++) {
840 linet = datat + i * wplt;
841 lined = datad + i * wpld;
842 for (j = 0; j < w; j++) {
843 pixel = linet[j];
844 hval = (pixel >> L_RED_SHIFT) & 0xff;
845 vval = (pixel >> L_BLUE_SHIFT) & 0xff;
846 if (hlut[hval] == 1 && vlut[vval] == 1) {
847 if (regionflag == L_INCLUDE_REGION)
848 SET_DATA_BIT(lined, j);
849 else /* L_EXCLUDE_REGION */
850 CLEAR_DATA_BIT(lined, j);
851 }
852 }
853 }
854
855 LEPT_FREE(hlut);
856 LEPT_FREE(vlut);
857 pixDestroy(&pixt);
858 return pixd;
859}
860
861
884PIX *
886 l_int32 satcenter,
887 l_int32 sathw,
888 l_int32 valcenter,
889 l_int32 valhw,
890 l_int32 regionflag)
891{
892l_int32 i, j, w, h, wplt, wpld, sval, vval, sstart, send, vstart, vend;
893l_int32 *slut, *vlut;
894l_uint32 pixel;
895l_uint32 *datat, *datad, *linet, *lined;
896PIX *pixt, *pixd;
897
898 if (!pixs || pixGetDepth(pixs) != 32)
899 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
900 if (regionflag != L_INCLUDE_REGION && regionflag != L_EXCLUDE_REGION)
901 return (PIX *)ERROR_PTR("invalid regionflag", __func__, NULL);
902
903 /* Set up LUTs for saturation and max intensity (val).
904 * These have the value 1 within the specified intervals of
905 * saturation and max intensity. */
906 slut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
907 vlut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
908 sstart = L_MAX(0, satcenter - sathw);
909 send = L_MIN(255, satcenter + sathw);
910 vstart = L_MAX(0, valcenter - valhw);
911 vend = L_MIN(255, valcenter + valhw);
912 for (i = sstart; i <= send; i++)
913 slut[i] = 1;
914 for (i = vstart; i <= vend; i++)
915 vlut[i] = 1;
916
917 /* Generate the mask */
918 pixt = pixConvertRGBToHSV(NULL, pixs);
919 pixGetDimensions(pixs, &w, &h, NULL);
920 pixd = pixCreate(w, h, 1);
921 if (regionflag == L_INCLUDE_REGION)
922 pixClearAll(pixd);
923 else /* L_EXCLUDE_REGION */
924 pixSetAll(pixd);
925 datat = pixGetData(pixt);
926 datad = pixGetData(pixd);
927 wplt = pixGetWpl(pixt);
928 wpld = pixGetWpl(pixd);
929 for (i = 0; i < h; i++) {
930 linet = datat + i * wplt;
931 lined = datad + i * wpld;
932 for (j = 0; j < w; j++) {
933 pixel = linet[j];
934 sval = (pixel >> L_GREEN_SHIFT) & 0xff;
935 vval = (pixel >> L_BLUE_SHIFT) & 0xff;
936 if (slut[sval] == 1 && vlut[vval] == 1) {
937 if (regionflag == L_INCLUDE_REGION)
938 SET_DATA_BIT(lined, j);
939 else /* L_EXCLUDE_REGION */
940 CLEAR_DATA_BIT(lined, j);
941 }
942 }
943 }
944
945 LEPT_FREE(slut);
946 LEPT_FREE(vlut);
947 pixDestroy(&pixt);
948 return pixd;
949}
950
951
971PIX *
973 l_int32 factor,
974 NUMA **pnahue,
975 NUMA **pnasat)
976{
977l_int32 i, j, w, h, wplt, hval, sval, nd;
978l_uint32 pixel;
979l_uint32 *datat, *linet;
980void **lined32;
981NUMA *nahue = NULL, *nasat = NULL;
982PIX *pixt, *pixd;
983
984 if (pnahue) *pnahue = NULL;
985 if (pnasat) *pnasat = NULL;
986 if (!pixs || pixGetDepth(pixs) != 32)
987 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
988
989 if (pnahue) {
990 nahue = numaCreate(240);
991 numaSetCount(nahue, 240);
992 *pnahue = nahue;
993 }
994 if (pnasat) {
995 nasat = numaCreate(256);
996 numaSetCount(nasat, 256);
997 *pnasat = nasat;
998 }
999
1000 if (factor <= 1)
1001 pixt = pixClone(pixs);
1002 else
1003 pixt = pixScaleBySampling(pixs, 1.0 / (l_float32)factor,
1004 1.0 / (l_float32)factor);
1005
1006 /* Create the hue-saturation histogram */
1007 pixd = pixCreate(256, 240, 32);
1008 lined32 = pixGetLinePtrs(pixd, NULL);
1009 pixGetDimensions(pixt, &w, &h, NULL);
1010 datat = pixGetData(pixt);
1011 wplt = pixGetWpl(pixt);
1012 for (i = 0; i < h; i++) {
1013 linet = datat + i * wplt;
1014 for (j = 0; j < w; j++) {
1015 pixel = linet[j];
1016 hval = (pixel >> L_RED_SHIFT) & 0xff;
1017
1018#if DEBUG_HISTO
1019 if (hval > 239) {
1020 lept_stderr("hval = %d for (%d,%d)\n", hval, i, j);
1021 continue;
1022 }
1023#endif /* DEBUG_HISTO */
1024
1025 sval = (pixel >> L_GREEN_SHIFT) & 0xff;
1026 if (pnahue)
1027 numaShiftValue(nahue, hval, 1.0);
1028 if (pnasat)
1029 numaShiftValue(nasat, sval, 1.0);
1030 nd = GET_DATA_FOUR_BYTES(lined32[hval], sval);
1031 SET_DATA_FOUR_BYTES(lined32[hval], sval, nd + 1);
1032 }
1033 }
1034
1035 LEPT_FREE(lined32);
1036 pixDestroy(&pixt);
1037 return pixd;
1038}
1039
1040
1060PIX *
1062 l_int32 factor,
1063 NUMA **pnahue,
1064 NUMA **pnaval)
1065{
1066l_int32 i, j, w, h, wplt, hval, vval, nd;
1067l_uint32 pixel;
1068l_uint32 *datat, *linet;
1069void **lined32;
1070NUMA *nahue = NULL, *naval = NULL;
1071PIX *pixt, *pixd;
1072
1073 if (pnahue) *pnahue = NULL;
1074 if (pnaval) *pnaval = NULL;
1075 if (!pixs || pixGetDepth(pixs) != 32)
1076 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
1077
1078 if (pnahue) {
1079 nahue = numaCreate(240);
1080 numaSetCount(nahue, 240);
1081 *pnahue = nahue;
1082 }
1083 if (pnaval) {
1084 naval = numaCreate(256);
1085 numaSetCount(naval, 256);
1086 *pnaval = naval;
1087 }
1088
1089 if (factor <= 1)
1090 pixt = pixClone(pixs);
1091 else
1092 pixt = pixScaleBySampling(pixs, 1.0 / (l_float32)factor,
1093 1.0 / (l_float32)factor);
1094
1095 /* Create the hue-value histogram */
1096 pixd = pixCreate(256, 240, 32);
1097 lined32 = pixGetLinePtrs(pixd, NULL);
1098 pixGetDimensions(pixt, &w, &h, NULL);
1099 datat = pixGetData(pixt);
1100 wplt = pixGetWpl(pixt);
1101 for (i = 0; i < h; i++) {
1102 linet = datat + i * wplt;
1103 for (j = 0; j < w; j++) {
1104 pixel = linet[j];
1105 hval = (pixel >> L_RED_SHIFT) & 0xff;
1106 vval = (pixel >> L_BLUE_SHIFT) & 0xff;
1107 if (pnahue)
1108 numaShiftValue(nahue, hval, 1.0);
1109 if (pnaval)
1110 numaShiftValue(naval, vval, 1.0);
1111 nd = GET_DATA_FOUR_BYTES(lined32[hval], vval);
1112 SET_DATA_FOUR_BYTES(lined32[hval], vval, nd + 1);
1113 }
1114 }
1115
1116 LEPT_FREE(lined32);
1117 pixDestroy(&pixt);
1118 return pixd;
1119}
1120
1121
1141PIX *
1143 l_int32 factor,
1144 NUMA **pnasat,
1145 NUMA **pnaval)
1146{
1147l_int32 i, j, w, h, wplt, sval, vval, nd;
1148l_uint32 pixel;
1149l_uint32 *datat, *linet;
1150void **lined32;
1151NUMA *nasat = NULL, *naval = NULL;
1152PIX *pixt, *pixd;
1153
1154 if (pnasat) *pnasat = NULL;
1155 if (pnaval) *pnaval = NULL;
1156 if (!pixs || pixGetDepth(pixs) != 32)
1157 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
1158
1159 if (pnasat) {
1160 nasat = numaCreate(256);
1161 numaSetCount(nasat, 256);
1162 *pnasat = nasat;
1163 }
1164 if (pnaval) {
1165 naval = numaCreate(256);
1166 numaSetCount(naval, 256);
1167 *pnaval = naval;
1168 }
1169
1170 if (factor <= 1)
1171 pixt = pixClone(pixs);
1172 else
1173 pixt = pixScaleBySampling(pixs, 1.0 / (l_float32)factor,
1174 1.0 / (l_float32)factor);
1175
1176 /* Create the hue-value histogram */
1177 pixd = pixCreate(256, 256, 32);
1178 lined32 = pixGetLinePtrs(pixd, NULL);
1179 pixGetDimensions(pixt, &w, &h, NULL);
1180 datat = pixGetData(pixt);
1181 wplt = pixGetWpl(pixt);
1182 for (i = 0; i < h; i++) {
1183 linet = datat + i * wplt;
1184 for (j = 0; j < w; j++) {
1185 pixel = linet[j];
1186 sval = (pixel >> L_GREEN_SHIFT) & 0xff;
1187 vval = (pixel >> L_BLUE_SHIFT) & 0xff;
1188 if (pnasat)
1189 numaShiftValue(nasat, sval, 1.0);
1190 if (pnaval)
1191 numaShiftValue(naval, vval, 1.0);
1192 nd = GET_DATA_FOUR_BYTES(lined32[sval], vval);
1193 SET_DATA_FOUR_BYTES(lined32[sval], vval, nd + 1);
1194 }
1195 }
1196
1197 LEPT_FREE(lined32);
1198 pixDestroy(&pixt);
1199 return pixd;
1200}
1201
1202
1230l_ok
1232 l_int32 type,
1233 l_int32 width,
1234 l_int32 height,
1235 l_int32 npeaks,
1236 l_float32 erasefactor,
1237 PTA **ppta,
1238 NUMA **pnatot,
1239 PIXA **ppixa)
1240{
1241l_int32 i, xmax, ymax, ewidth, eheight;
1242l_uint32 maxval;
1243BOX *box;
1244NUMA *natot;
1245PIX *pixh, *pixw, *pix1, *pix2, *pix3;
1246PTA *pta;
1247
1248 if (ppixa) *ppixa = NULL;
1249 if (ppta) *ppta = NULL;
1250 if (pnatot) *pnatot = NULL;
1251 if (!pixs || pixGetDepth(pixs) != 32)
1252 return ERROR_INT("pixs undefined or not 32 bpp", __func__, 1);
1253 if (!ppta || !pnatot)
1254 return ERROR_INT("&pta and &natot not both defined", __func__, 1);
1255 if (type != L_HS_HISTO && type != L_HV_HISTO && type != L_SV_HISTO)
1256 return ERROR_INT("invalid HSV histo type", __func__, 1);
1257
1258 if ((pta = ptaCreate(npeaks)) == NULL)
1259 return ERROR_INT("pta not made", __func__, 1);
1260 *ppta = pta;
1261 if ((natot = numaCreate(npeaks)) == NULL)
1262 return ERROR_INT("natot not made", __func__, 1);
1263 *pnatot = natot;
1264
1265 *ppta = pta;
1266 if (type == L_SV_HISTO)
1267 pixh = pixAddMirroredBorder(pixs, width + 1, width + 1, height + 1,
1268 height + 1);
1269 else /* type == L_HS_HISTO or type == L_HV_HISTO */
1270 pixh = pixAddMixedBorder(pixs, width + 1, width + 1, height + 1,
1271 height + 1);
1272
1273 /* Get the total count in the sliding window. If the window
1274 * fully covers the peak, this will be the integrated
1275 * volume under the peak. */
1276 pixw = pixWindowedMean(pixh, width, height, 1, 0);
1277 pixDestroy(&pixh);
1278
1279 /* Sequentially identify and erase peaks in the histogram.
1280 * If requested for debugging, save a pixa of the sequence of
1281 * false color histograms. */
1282 if (ppixa)
1283 *ppixa = pixaCreate(0);
1284 for (i = 0; i < npeaks; i++) {
1285 pixGetMaxValueInRect(pixw, NULL, &maxval, &xmax, &ymax);
1286 if (maxval == 0) break;
1287 numaAddNumber(natot, maxval);
1288 ptaAddPt(pta, xmax, ymax);
1289 ewidth = (l_int32)(width * erasefactor);
1290 eheight = (l_int32)(height * erasefactor);
1291 box = boxCreate(xmax - ewidth, ymax - eheight, 2 * ewidth + 1,
1292 2 * eheight + 1);
1293
1294 if (ppixa) {
1295 pix1 = pixMaxDynamicRange(pixw, L_LINEAR_SCALE);
1296 pixaAddPix(*ppixa, pix1, L_INSERT);
1297 pix2 = pixConvertGrayToFalseColor(pix1, 1.0);
1298 pixaAddPix(*ppixa, pix2, L_INSERT);
1299 pix1 = pixMaxDynamicRange(pixw, L_LOG_SCALE);
1300 pix2 = pixConvertGrayToFalseColor(pix1, 1.0);
1301 pixaAddPix(*ppixa, pix2, L_INSERT);
1302 pix3 = pixConvertTo32(pix1);
1303 pixRenderHashBoxArb(pix3, box, 6, 2, L_NEG_SLOPE_LINE,
1304 1, 255, 100, 100);
1305 pixaAddPix(*ppixa, pix3, L_INSERT);
1306 pixDestroy(&pix1);
1307 }
1308
1309 pixClearInRect(pixw, box);
1310 boxDestroy(&box);
1311 if (type == L_HS_HISTO || type == L_HV_HISTO) {
1312 /* clear wraps at bottom and top */
1313 if (ymax - eheight < 0) { /* overlap to bottom */
1314 box = boxCreate(xmax - ewidth, 240 + ymax - eheight,
1315 2 * ewidth + 1, eheight - ymax);
1316 } else if (ymax + eheight > 239) { /* overlap to top */
1317 box = boxCreate(xmax - ewidth, 0, 2 * ewidth + 1,
1318 ymax + eheight - 239);
1319 } else {
1320 box = NULL;
1321 }
1322 if (box) {
1323 pixClearInRect(pixw, box);
1324 boxDestroy(&box);
1325 }
1326 }
1327 }
1328
1329 pixDestroy(&pixw);
1330 return 0;
1331}
1332
1333
1352PIX *
1354 l_int32 sval,
1355 l_int32 vval,
1356 l_int32 huehw,
1357 l_int32 sathw,
1358 l_int32 nsamp,
1359 l_int32 factor)
1360{
1361l_int32 i, j, w, huedelta, satdelta, hue, sat, rval, gval, bval;
1362PIX *pixt, *pixd;
1363
1364 if (hval < 0 || hval > 240)
1365 return (PIX *)ERROR_PTR("invalid hval", __func__, NULL);
1366 if (huehw < 5 || huehw > 120)
1367 return (PIX *)ERROR_PTR("invalid huehw", __func__, NULL);
1368 if (sval - sathw < 0 || sval + sathw > 255)
1369 return (PIX *)ERROR_PTR("invalid sval/sathw", __func__, NULL);
1370 if (nsamp < 1 || factor < 3)
1371 return (PIX *)ERROR_PTR("invalid nsamp or rep. factor", __func__, NULL);
1372 if (vval < 0 || vval > 255)
1373 return (PIX *)ERROR_PTR("invalid vval", __func__, NULL);
1374
1375 w = (2 * nsamp + 1);
1376 huedelta = (l_int32)((l_float32)huehw / (l_float32)nsamp);
1377 satdelta = (l_int32)((l_float32)sathw / (l_float32)nsamp);
1378 pixt = pixCreate(w, w, 32);
1379 for (i = 0; i < w; i++) {
1380 hue = hval + huedelta * (i - nsamp);
1381 if (hue < 0) hue += 240;
1382 if (hue >= 240) hue -= 240;
1383 for (j = 0; j < w; j++) {
1384 sat = sval + satdelta * (j - nsamp);
1385 convertHSVToRGB(hue, sat, vval, &rval, &gval, &bval);
1386 pixSetRGBPixel(pixt, j, i, rval, gval, bval);
1387 }
1388 }
1389
1390 pixd = pixExpandReplicate(pixt, factor);
1391 pixDestroy(&pixt);
1392 return pixd;
1393}
1394
1395
1396/*---------------------------------------------------------------------------*
1397 * Colorspace conversion between RGB and YUV *
1398 *---------------------------------------------------------------------------*/
1426PIX *
1428 PIX *pixs)
1429{
1430l_int32 w, h, d, wpl, i, j, rval, gval, bval, yval, uval, vval;
1431l_uint32 *line, *data;
1432PIXCMAP *cmap;
1433
1434 if (!pixs)
1435 return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1436 if (pixd && pixd != pixs)
1437 return (PIX *)ERROR_PTR("pixd defined and not inplace", __func__, pixd);
1438
1439 d = pixGetDepth(pixs);
1440 cmap = pixGetColormap(pixs);
1441 if (!cmap && d != 32)
1442 return (PIX *)ERROR_PTR("not cmapped or rgb", __func__, pixd);
1443
1444 if (!pixd)
1445 pixd = pixCopy(NULL, pixs);
1446
1447 cmap = pixGetColormap(pixd);
1448 if (cmap) { /* just convert the colormap */
1450 return pixd;
1451 }
1452
1453 /* Convert RGB image */
1454 pixGetDimensions(pixd, &w, &h, NULL);
1455 wpl = pixGetWpl(pixd);
1456 data = pixGetData(pixd);
1457 for (i = 0; i < h; i++) {
1458 line = data + i * wpl;
1459 for (j = 0; j < w; j++) {
1460 extractRGBValues(line[j], &rval, &gval, &bval);
1461 convertRGBToYUV(rval, gval, bval, &yval, &uval, &vval);
1462 line[j] = (yval << 24) | (uval << 16) | (vval << 8);
1463 }
1464 }
1465
1466 return pixd;
1467}
1468
1469
1487PIX *
1489 PIX *pixs)
1490{
1491l_int32 w, h, d, wpl, i, j, rval, gval, bval, yval, uval, vval;
1492l_uint32 pixel;
1493l_uint32 *line, *data;
1494PIXCMAP *cmap;
1495
1496 if (!pixs)
1497 return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1498 if (pixd && pixd != pixs)
1499 return (PIX *)ERROR_PTR("pixd defined and not inplace", __func__, pixd);
1500
1501 d = pixGetDepth(pixs);
1502 cmap = pixGetColormap(pixs);
1503 if (!cmap && d != 32)
1504 return (PIX *)ERROR_PTR("not cmapped or hsv", __func__, pixd);
1505
1506 if (!pixd)
1507 pixd = pixCopy(NULL, pixs);
1508
1509 cmap = pixGetColormap(pixd);
1510 if (cmap) { /* just convert the colormap */
1512 return pixd;
1513 }
1514
1515 /* Convert YUV image */
1516 pixGetDimensions(pixd, &w, &h, NULL);
1517 wpl = pixGetWpl(pixd);
1518 data = pixGetData(pixd);
1519 for (i = 0; i < h; i++) {
1520 line = data + i * wpl;
1521 for (j = 0; j < w; j++) {
1522 pixel = line[j];
1523 yval = pixel >> 24;
1524 uval = (pixel >> 16) & 0xff;
1525 vval = (pixel >> 8) & 0xff;
1526 convertYUVToRGB(yval, uval, vval, &rval, &gval, &bval);
1527 composeRGBPixel(rval, gval, bval, line + j);
1528 }
1529 }
1530
1531 return pixd;
1532}
1533
1534
1550l_ok
1551convertRGBToYUV(l_int32 rval,
1552 l_int32 gval,
1553 l_int32 bval,
1554 l_int32 *pyval,
1555 l_int32 *puval,
1556 l_int32 *pvval)
1557{
1558l_float32 norm;
1559
1560 if (pyval) *pyval = 0;
1561 if (puval) *puval = 0;
1562 if (pvval) *pvval = 0;
1563 if (!pyval || !puval || !pvval)
1564 return ERROR_INT("&yval, &uval, &vval not all defined", __func__, 1);
1565
1566 norm = 1.0 / 256.;
1567 *pyval = (l_int32)(16.0 +
1568 norm * (65.738 * rval + 129.057 * gval + 25.064 * bval) + 0.5);
1569 *puval = (l_int32)(128.0 +
1570 norm * (-37.945 * rval -74.494 * gval + 112.439 * bval) + 0.5);
1571 *pvval = (l_int32)(128.0 +
1572 norm * (112.439 * rval - 94.154 * gval - 18.285 * bval) + 0.5);
1573 return 0;
1574}
1575
1576
1596l_ok
1597convertYUVToRGB(l_int32 yval,
1598 l_int32 uval,
1599 l_int32 vval,
1600 l_int32 *prval,
1601 l_int32 *pgval,
1602 l_int32 *pbval)
1603{
1604l_int32 rval, gval, bval;
1605l_float32 norm, ym, um, vm;
1606
1607 if (prval) *prval = 0;
1608 if (pgval) *pgval = 0;
1609 if (pbval) *pbval = 0;
1610 if (!prval || !pgval || !pbval)
1611 return ERROR_INT("&rval, &gval, &bval not all defined", __func__, 1);
1612
1613 norm = 1.0 / 256.;
1614 ym = yval - 16.0;
1615 um = uval - 128.0;
1616 vm = vval - 128.0;
1617 rval = (l_int32)(norm * (298.082 * ym + 408.583 * vm) + 0.5);
1618 gval = (l_int32)(norm * (298.082 * ym - 100.291 * um - 208.120 * vm) +
1619 0.5);
1620 bval = (l_int32)(norm * (298.082 * ym + 516.411 * um) + 0.5);
1621 *prval = L_MIN(255, L_MAX(0, rval));
1622 *pgval = L_MIN(255, L_MAX(0, gval));
1623 *pbval = L_MIN(255, L_MAX(0, bval));
1624
1625 return 0;
1626}
1627
1628
1642l_ok
1644{
1645l_int32 i, ncolors, rval, gval, bval, yval, uval, vval;
1646
1647 if (!cmap)
1648 return ERROR_INT("cmap not defined", __func__, 1);
1649
1650 ncolors = pixcmapGetCount(cmap);
1651 for (i = 0; i < ncolors; i++) {
1652 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1653 convertRGBToYUV(rval, gval, bval, &yval, &uval, &vval);
1654 pixcmapResetColor(cmap, i, yval, uval, vval);
1655 }
1656 return 0;
1657}
1658
1659
1673l_ok
1675{
1676l_int32 i, ncolors, rval, gval, bval, yval, uval, vval;
1677
1678 if (!cmap)
1679 return ERROR_INT("cmap not defined", __func__, 1);
1680
1681 ncolors = pixcmapGetCount(cmap);
1682 for (i = 0; i < ncolors; i++) {
1683 pixcmapGetColor(cmap, i, &yval, &uval, &vval);
1684 convertYUVToRGB(yval, uval, vval, &rval, &gval, &bval);
1685 pixcmapResetColor(cmap, i, rval, gval, bval);
1686 }
1687 return 0;
1688}
1689
1690
1691/*---------------------------------------------------------------------------*
1692 * Colorspace conversion between RGB and XYZ *
1693 *---------------------------------------------------------------------------*/
1722FPIXA *
1724{
1725l_int32 w, h, wpls, wpld, i, j, rval, gval, bval;
1726l_uint32 *lines, *datas;
1727l_float32 fxval, fyval, fzval;
1728l_float32 *linex, *liney, *linez, *datax, *datay, *dataz;
1729FPIX *fpix;
1730FPIXA *fpixa;
1731
1732 if (!pixs || pixGetDepth(pixs) != 32)
1733 return (FPIXA *)ERROR_PTR("pixs undefined or not rgb", __func__, NULL);
1734
1735 /* Convert RGB image */
1736 pixGetDimensions(pixs, &w, &h, NULL);
1737 fpixa = fpixaCreate(3);
1738 for (i = 0; i < 3; i++) {
1739 fpix = fpixCreate(w, h);
1740 fpixaAddFPix(fpixa, fpix, L_INSERT);
1741 }
1742 wpls = pixGetWpl(pixs);
1743 wpld = fpixGetWpl(fpix);
1744 datas = pixGetData(pixs);
1745 datax = fpixaGetData(fpixa, 0);
1746 datay = fpixaGetData(fpixa, 1);
1747 dataz = fpixaGetData(fpixa, 2);
1748 for (i = 0; i < h; i++) {
1749 lines = datas + i * wpls;
1750 linex = datax + i * wpld;
1751 liney = datay + i * wpld;
1752 linez = dataz + i * wpld;
1753 for (j = 0; j < w; j++) {
1754 extractRGBValues(lines[j], &rval, &gval, &bval);
1755 convertRGBToXYZ(rval, gval, bval, &fxval, &fyval, &fzval);
1756 *(linex + j) = fxval;
1757 *(liney + j) = fyval;
1758 *(linez + j) = fzval;
1759 }
1760 }
1761
1762 return fpixa;
1763}
1764
1765
1779PIX *
1781{
1782l_int32 w, h, wpls, wpld, i, j, rval, gval, bval;
1783l_float32 fxval, fyval, fzval;
1784l_float32 *linex, *liney, *linez, *datax, *datay, *dataz;
1785l_uint32 *lined, *datad;
1786PIX *pixd;
1787FPIX *fpix;
1788
1789 if (!fpixa || fpixaGetCount(fpixa) != 3)
1790 return (PIX *)ERROR_PTR("fpixa undefined or invalid", __func__, NULL);
1791
1792 /* Convert XYZ image */
1793 if (fpixaGetFPixDimensions(fpixa, 0, &w, &h))
1794 return (PIX *)ERROR_PTR("fpixa dimensions not found", __func__, NULL);
1795 pixd = pixCreate(w, h, 32);
1796 wpld = pixGetWpl(pixd);
1797 datad = pixGetData(pixd);
1798 datax = fpixaGetData(fpixa, 0);
1799 datay = fpixaGetData(fpixa, 1);
1800 dataz = fpixaGetData(fpixa, 2);
1801 fpix = fpixaGetFPix(fpixa, 0, L_CLONE);
1802 wpls = fpixGetWpl(fpix);
1803 fpixDestroy(&fpix);
1804 for (i = 0; i < h; i++) {
1805 linex = datax + i * wpls;
1806 liney = datay + i * wpls;
1807 linez = dataz + i * wpls;
1808 lined = datad + i * wpld;
1809 for (j = 0; j < w; j++) {
1810 fxval = linex[j];
1811 fyval = liney[j];
1812 fzval = linez[j];
1813 convertXYZToRGB(fxval, fyval, fzval, 0, &rval, &gval, &bval);
1814 composeRGBPixel(rval, gval, bval, lined + j);
1815 }
1816 }
1817
1818 return pixd;
1819}
1820
1821
1835l_ok
1836convertRGBToXYZ(l_int32 rval,
1837 l_int32 gval,
1838 l_int32 bval,
1839 l_float32 *pfxval,
1840 l_float32 *pfyval,
1841 l_float32 *pfzval)
1842{
1843 if (pfxval) *pfxval = 0.0;
1844 if (pfyval) *pfyval = 0.0;
1845 if (pfzval) *pfzval = 0.0;
1846 if (!pfxval || !pfyval || !pfzval)
1847 return ERROR_INT("&xval, &yval, &zval not all defined", __func__, 1);
1848
1849 *pfxval = 0.4125 * rval + 0.3576 * gval + 0.1804 * bval;
1850 *pfyval = 0.2127 * rval + 0.7152 * gval + 0.0722 * bval;
1851 *pfzval = 0.0193 * rval + 0.1192 * gval + 0.9502 * bval;
1852 return 0;
1853}
1854
1855
1875l_ok
1876convertXYZToRGB(l_float32 fxval,
1877 l_float32 fyval,
1878 l_float32 fzval,
1879 l_int32 blackout,
1880 l_int32 *prval,
1881 l_int32 *pgval,
1882 l_int32 *pbval)
1883{
1884l_int32 rval, gval, bval;
1885
1886 if (prval) *prval = 0;
1887 if (pgval) *pgval = 0;
1888 if (pbval) *pbval = 0;
1889 if (!prval || !pgval ||!pbval)
1890 return ERROR_INT("&rval, &gval, &bval not all defined", __func__, 1);
1891 *prval = *pgval = *pbval = 0;
1892
1893 rval = (l_int32)(3.2405 * fxval - 1.5372 * fyval - 0.4985 * fzval + 0.5);
1894 gval = (l_int32)(-0.9693 * fxval + 1.8760 * fyval + 0.0416 * fzval + 0.5);
1895 bval = (l_int32)(0.0556 * fxval - 0.2040 * fyval + 1.0573 * fzval + 0.5);
1896 if (blackout == 0) { /* the usual situation; use nearest rgb color */
1897 *prval = L_MAX(0, L_MIN(rval, 255));
1898 *pgval = L_MAX(0, L_MIN(gval, 255));
1899 *pbval = L_MAX(0, L_MIN(bval, 255));
1900 } else { /* use black for out of gamut */
1901 if (rval >= 0 && rval < 256 && gval >= 0 && gval < 256 &&
1902 bval >= 0 && bval < 256) { /* in gamut */
1903 *prval = rval;
1904 *pgval = gval;
1905 *pbval = bval;
1906 }
1907 }
1908 return 0;
1909}
1910
1911
1912/*---------------------------------------------------------------------------*
1913 * Colorspace conversion between XYZ and LAB *
1914 *---------------------------------------------------------------------------*/
1934FPIXA *
1936{
1937l_int32 w, h, wpl, i, j;
1938l_float32 fxval, fyval, fzval, flval, faval, fbval;
1939l_float32 *linex, *liney, *linez, *datax, *datay, *dataz;
1940l_float32 *linel, *linea, *lineb, *datal, *dataa, *datab;
1941FPIX *fpix;
1942FPIXA *fpixad;
1943
1944 if (!fpixas || fpixaGetCount(fpixas) != 3)
1945 return (FPIXA *)ERROR_PTR("fpixas undefined/invalid", __func__, NULL);
1946
1947 /* Convert XYZ image */
1948 if (fpixaGetFPixDimensions(fpixas, 0, &w, &h))
1949 return (FPIXA *)ERROR_PTR("fpixas sizes not found", __func__, NULL);
1950 fpixad = fpixaCreate(3);
1951 for (i = 0; i < 3; i++) {
1952 fpix = fpixCreate(w, h);
1953 fpixaAddFPix(fpixad, fpix, L_INSERT);
1954 }
1955 wpl = fpixGetWpl(fpix);
1956 datax = fpixaGetData(fpixas, 0);
1957 datay = fpixaGetData(fpixas, 1);
1958 dataz = fpixaGetData(fpixas, 2);
1959 datal = fpixaGetData(fpixad, 0);
1960 dataa = fpixaGetData(fpixad, 1);
1961 datab = fpixaGetData(fpixad, 2);
1962
1963 /* Convert XYZ image */
1964 for (i = 0; i < h; i++) {
1965 linex = datax + i * wpl;
1966 liney = datay + i * wpl;
1967 linez = dataz + i * wpl;
1968 linel = datal + i * wpl;
1969 linea = dataa + i * wpl;
1970 lineb = datab + i * wpl;
1971 for (j = 0; j < w; j++) {
1972 fxval = *(linex + j);
1973 fyval = *(liney + j);
1974 fzval = *(linez + j);
1975 convertXYZToLAB(fxval, fyval, fzval, &flval, &faval, &fbval);
1976 *(linel + j) = flval;
1977 *(linea + j) = faval;
1978 *(lineb + j) = fbval;
1979 }
1980 }
1981
1982 return fpixad;
1983}
1984
1985
1998FPIXA *
2000{
2001l_int32 w, h, wpl, i, j;
2002l_float32 fxval, fyval, fzval, flval, faval, fbval;
2003l_float32 *linel, *linea, *lineb, *datal, *dataa, *datab;
2004l_float32 *linex, *liney, *linez, *datax, *datay, *dataz;
2005FPIX *fpix;
2006FPIXA *fpixad;
2007
2008 if (!fpixas || fpixaGetCount(fpixas) != 3)
2009 return (FPIXA *)ERROR_PTR("fpixas undefined/invalid", __func__, NULL);
2010
2011 /* Convert LAB image */
2012 if (fpixaGetFPixDimensions(fpixas, 0, &w, &h))
2013 return (FPIXA *)ERROR_PTR("fpixas sizes not found", __func__, NULL);
2014 fpixad = fpixaCreate(3);
2015 for (i = 0; i < 3; i++) {
2016 fpix = fpixCreate(w, h);
2017 fpixaAddFPix(fpixad, fpix, L_INSERT);
2018 }
2019 wpl = fpixGetWpl(fpix);
2020 datal = fpixaGetData(fpixas, 0);
2021 dataa = fpixaGetData(fpixas, 1);
2022 datab = fpixaGetData(fpixas, 2);
2023 datax = fpixaGetData(fpixad, 0);
2024 datay = fpixaGetData(fpixad, 1);
2025 dataz = fpixaGetData(fpixad, 2);
2026
2027 /* Convert XYZ image */
2028 for (i = 0; i < h; i++) {
2029 linel = datal + i * wpl;
2030 linea = dataa + i * wpl;
2031 lineb = datab + i * wpl;
2032 linex = datax + i * wpl;
2033 liney = datay + i * wpl;
2034 linez = dataz + i * wpl;
2035 for (j = 0; j < w; j++) {
2036 flval = *(linel + j);
2037 faval = *(linea + j);
2038 fbval = *(lineb + j);
2039 convertLABToXYZ(flval, faval, fbval, &fxval, &fyval, &fzval);
2040 *(linex + j) = fxval;
2041 *(liney + j) = fyval;
2042 *(linez + j) = fzval;
2043 }
2044 }
2045
2046 return fpixad;
2047}
2048
2049
2057l_ok
2058convertXYZToLAB(l_float32 xval,
2059 l_float32 yval,
2060 l_float32 zval,
2061 l_float32 *plval,
2062 l_float32 *paval,
2063 l_float32 *pbval)
2064{
2065l_float32 xn, yn, zn, fx, fy, fz;
2066
2067 if (plval) *plval = 0.0;
2068 if (paval) *paval = 0.0;
2069 if (pbval) *pbval = 0.0;
2070 if (!plval || !paval || !pbval)
2071 return ERROR_INT("&lval, &aval, &bval not all defined", __func__, 1);
2072
2073 /* First normalize to the corresponding white values */
2074 xn = 0.0041259 * xval;
2075 yn = 0.0039216 * yval;
2076 zn = 0.0036012 * zval;
2077 /* Then apply the lab_forward function */
2078 fx = lab_forward(xn);
2079 fy = lab_forward(yn);
2080 fz = lab_forward(zn);
2081 *plval = 116.0 * fy - 16.0;
2082 *paval = 500.0 * (fx - fy);
2083 *pbval = 200.0 * (fy - fz);
2084 return 0;
2085}
2086
2087
2095l_ok
2096convertLABToXYZ(l_float32 lval,
2097 l_float32 aval,
2098 l_float32 bval,
2099 l_float32 *pxval,
2100 l_float32 *pyval,
2101 l_float32 *pzval)
2102{
2103l_float32 fx, fy, fz;
2104l_float32 xw = 242.37f; /* x component corresponding to rgb white */
2105l_float32 yw = 255.0f; /* y component corresponding to rgb white */
2106l_float32 zw = 277.69f; /* z component corresponding to rgb white */
2107
2108 if (pxval) *pxval = 0.0;
2109 if (pyval) *pyval = 0.0;
2110 if (pzval) *pzval = 0.0;
2111 if (!pxval || !pyval || !pzval)
2112 return ERROR_INT("&xval, &yval, &zval not all defined", __func__, 1);
2113
2114 fy = 0.0086207 * (16.0 + lval);
2115 fx = fy + 0.002 * aval;
2116 fz = fy - 0.005 * bval;
2117 *pxval = xw * lab_reverse(fx);
2118 *pyval = yw * lab_reverse(fy);
2119 *pzval = zw * lab_reverse(fz);
2120 return 0;
2121}
2122
2123
2124/*
2125 * See http://en.wikipedia.org/wiki/Lab_color_space for formulas.
2126 * This is the forward function: from xyz to lab. It includes a rational
2127 * function approximation over [0.008856 ... 1] to the cube root, from
2128 * "Fast Color Space Transformations Using Minimax Approximations",
2129 * M. Celebi et al, http://arxiv.org/pdf/1009.0854v1.pdf.
2130 */
2131static l_float32
2132lab_forward(l_float32 v)
2133{
2134const l_float32 f_thresh = 0.008856f; /* (6/29)^3 */
2135const l_float32 f_factor = 7.787f; /* (1/3) * (29/6)^2) */
2136const l_float32 f_offset = 0.13793f; /* 4/29 */
2137
2138 if (v > f_thresh) {
2139#if SLOW_CUBE_ROOT
2140 return powf(v, 0.333333);
2141#else
2142 l_float32 num, den;
2143 num = 4.37089e-04 + v * (9.52695e-02 + v * (1.25201 + v * 1.30273));
2144 den = 3.91236e-03 + v * (2.95408e-01 + v * (1.71714 + v * 6.34341e-01));
2145 return num / den;
2146#endif
2147 } else {
2148 return f_factor * v + f_offset;
2149 }
2150}
2151
2152
2153/*
2154 * See http://en.wikipedia.org/wiki/Lab_color_space for formulas.
2155 * This is the reverse (inverse) function: from lab to xyz.
2156 */
2157static l_float32
2158lab_reverse(l_float32 v)
2159{
2160const l_float32 r_thresh = 0.20690f; /* 6/29 */
2161const l_float32 r_factor = 0.12842f; /* 3 * (6/29)^2 */
2162const l_float32 r_offset = 0.13793f; /* 4/29 */
2163
2164 if (v > r_thresh) {
2165 return v * v * v;
2166 } else {
2167 return r_factor * (v - r_offset);
2168 }
2169}
2170
2171
2172/*---------------------------------------------------------------------------*
2173 * Colorspace conversion between RGB and LAB *
2174 *---------------------------------------------------------------------------*/
2187FPIXA *
2189{
2190l_int32 w, h, wpls, wpld, i, j, rval, gval, bval;
2191l_uint32 *lines, *datas;
2192l_float32 flval, faval, fbval;
2193l_float32 *linel, *linea, *lineb, *datal, *dataa, *datab;
2194FPIX *fpix;
2195FPIXA *fpixa;
2196
2197 if (!pixs || pixGetDepth(pixs) != 32)
2198 return (FPIXA *)ERROR_PTR("pixs undefined or not rgb", __func__, NULL);
2199
2200 /* Convert RGB image */
2201 pixGetDimensions(pixs, &w, &h, NULL);
2202 fpixa = fpixaCreate(3);
2203 for (i = 0; i < 3; i++) {
2204 fpix = fpixCreate(w, h);
2205 fpixaAddFPix(fpixa, fpix, L_INSERT);
2206 }
2207 wpls = pixGetWpl(pixs);
2208 wpld = fpixGetWpl(fpix);
2209 datas = pixGetData(pixs);
2210 datal = fpixaGetData(fpixa, 0);
2211 dataa = fpixaGetData(fpixa, 1);
2212 datab = fpixaGetData(fpixa, 2);
2213 for (i = 0; i < h; i++) {
2214 lines = datas + i * wpls;
2215 linel = datal + i * wpld;
2216 linea = dataa + i * wpld;
2217 lineb = datab + i * wpld;
2218 for (j = 0; j < w; j++) {
2219 extractRGBValues(lines[j], &rval, &gval, &bval);
2220 convertRGBToLAB(rval, gval, bval, &flval, &faval, &fbval);
2221 *(linel + j) = flval;
2222 *(linea + j) = faval;
2223 *(lineb + j) = fbval;
2224 }
2225 }
2226
2227 return fpixa;
2228}
2229
2230
2242PIX *
2244{
2245l_int32 w, h, wpls, wpld, i, j, rval, gval, bval;
2246l_float32 flval, faval, fbval;
2247l_float32 *linel, *linea, *lineb, *datal, *dataa, *datab;
2248l_uint32 *lined, *datad;
2249PIX *pixd;
2250FPIX *fpix;
2251
2252 if (!fpixa || fpixaGetCount(fpixa) != 3)
2253 return (PIX *)ERROR_PTR("fpixa undefined or invalid", __func__, NULL);
2254
2255 /* Convert LAB image */
2256 if (fpixaGetFPixDimensions(fpixa, 0, &w, &h))
2257 return (PIX *)ERROR_PTR("fpixa dimensions not found", __func__, NULL);
2258 pixd = pixCreate(w, h, 32);
2259 wpld = pixGetWpl(pixd);
2260 datad = pixGetData(pixd);
2261 datal = fpixaGetData(fpixa, 0);
2262 dataa = fpixaGetData(fpixa, 1);
2263 datab = fpixaGetData(fpixa, 2);
2264 fpix = fpixaGetFPix(fpixa, 0, L_CLONE);
2265 wpls = fpixGetWpl(fpix);
2266 fpixDestroy(&fpix);
2267 for (i = 0; i < h; i++) {
2268 linel = datal + i * wpls;
2269 linea = dataa + i * wpls;
2270 lineb = datab + i * wpls;
2271 lined = datad + i * wpld;
2272 for (j = 0; j < w; j++) {
2273 flval = linel[j];
2274 faval = linea[j];
2275 fbval = lineb[j];
2276 convertLABToRGB(flval, faval, fbval, &rval, &gval, &bval);
2277 composeRGBPixel(rval, gval, bval, lined + j);
2278 }
2279 }
2280
2281 return pixd;
2282}
2283
2284
2298l_ok
2299convertRGBToLAB(l_int32 rval,
2300 l_int32 gval,
2301 l_int32 bval,
2302 l_float32 *pflval,
2303 l_float32 *pfaval,
2304 l_float32 *pfbval)
2305{
2306l_float32 fxval, fyval, fzval;
2307
2308 if (pflval) *pflval = 0.0;
2309 if (pfaval) *pfaval = 0.0;
2310 if (pfbval) *pfbval = 0.0;
2311 if (!pflval || !pfaval || !pfbval)
2312 return ERROR_INT("&flval, &faval, &fbval not all defined", __func__, 1);
2313
2314 convertRGBToXYZ(rval, gval, bval, &fxval, &fyval, &fzval);
2315 convertXYZToLAB(fxval, fyval, fzval, pflval, pfaval, pfbval);
2316 return 0;
2317}
2318
2319
2333l_ok
2334convertLABToRGB(l_float32 flval,
2335 l_float32 faval,
2336 l_float32 fbval,
2337 l_int32 *prval,
2338 l_int32 *pgval,
2339 l_int32 *pbval)
2340{
2341l_float32 fxval, fyval, fzval;
2342
2343 if (prval) *prval = 0;
2344 if (pgval) *pgval = 0;
2345 if (pbval) *pbval = 0;
2346 if (!prval || !pgval || !pbval)
2347 return ERROR_INT("&rval, &gval, &bval not all defined", __func__, 1);
2348
2349 convertLABToXYZ(flval, faval, fbval, &fxval, &fyval, &fzval);
2350 convertXYZToRGB(fxval, fyval, fzval, 0, prval, pgval, pbval);
2351 return 0;
2352}
2353
2354
2355/*---------------------------------------------------------------------------*
2356 * Gamut display of RGB color space *
2357 *---------------------------------------------------------------------------*/
2377PIX *
2378pixMakeGamutRGB(l_int32 scale)
2379{
2380l_int32 i, j, k;
2381l_uint32 val32;
2382PIX *pix1, *pix2;
2383PIXA *pixa;
2384
2385 if (scale <= 0) scale = 8; /* default */
2386
2387 pixa = pixaCreate(32);
2388 for (k = 0; k < 32; k++) {
2389 pix1 = pixCreate(32, 32, 32);
2390 for (i = 0; i < 32; i++) {
2391 for (j = 0; j < 32; j++) {
2392 composeRGBPixel(8 * j, 8 * i, 8 * k, &val32);
2393 pixSetPixel(pix1, j, i, val32);
2394 }
2395 }
2396 pixaAddPix(pixa, pix1, L_INSERT);
2397 }
2398 pix2 = pixaDisplayTiledInColumns(pixa, 8, scale, 5, 0);
2399 pixaDestroy(&pixa);
2400 return pix2;
2401}
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_FOUR_BYTES(pdata, n, val)
#define GET_DATA_FOUR_BYTES(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define CLEAR_DATA_BIT(pdata, n)
l_ok pixFindHistoPeaksHSV(PIX *pixs, l_int32 type, l_int32 width, l_int32 height, l_int32 npeaks, l_float32 erasefactor, PTA **ppta, NUMA **pnatot, PIXA **ppixa)
pixFindHistoPeaksHSV()
l_ok convertLABToRGB(l_float32 flval, l_float32 faval, l_float32 fbval, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
convertLABToRGB()
FPIXA * pixConvertRGBToLAB(PIX *pixs)
pixConvertRGBToLAB()
PIX * pixConvertRGBToValue(PIX *pixs)
pixConvertRGBToValue()
Definition colorspace.c:625
PIX * fpixaConvertLABToRGB(FPIXA *fpixa)
fpixaConvertLABToRGB()
l_ok convertXYZToRGB(l_float32 fxval, l_float32 fyval, l_float32 fzval, l_int32 blackout, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
convertXYZToRGB()
PIX * pixMakeGamutRGB(l_int32 scale)
pixMakeGamutRGB()
PIX * fpixaConvertXYZToRGB(FPIXA *fpixa)
fpixaConvertXYZToRGB()
FPIXA * fpixaConvertLABToXYZ(FPIXA *fpixas)
fpixaConvertLABToXYZ()
l_ok convertHSVToRGB(l_int32 hval, l_int32 sval, l_int32 vval, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
convertHSVToRGB()
Definition colorspace.c:337
PIX * pixConvertYUVToRGB(PIX *pixd, PIX *pixs)
pixConvertYUVToRGB()
PIX * pixMakeRangeMaskHV(PIX *pixs, l_int32 huecenter, l_int32 huehw, l_int32 valcenter, l_int32 valhw, l_int32 regionflag)
pixMakeRangeMaskHV()
Definition colorspace.c:789
PIX * pixConvertRGBToSaturation(PIX *pixs)
pixConvertRGBToSaturation()
Definition colorspace.c:562
l_ok convertRGBToHSV(l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *phval, l_int32 *psval, l_int32 *pvval)
convertRGBToHSV()
Definition colorspace.c:277
l_ok pixcmapConvertHSVToRGB(PIXCMAP *cmap)
pixcmapConvertHSVToRGB()
Definition colorspace.c:455
l_ok pixcmapConvertRGBToHSV(PIXCMAP *cmap)
pixcmapConvertRGBToHSV()
Definition colorspace.c:424
PIX * pixMakeRangeMaskHS(PIX *pixs, l_int32 huecenter, l_int32 huehw, l_int32 satcenter, l_int32 sathw, l_int32 regionflag)
pixMakeRangeMaskHS()
Definition colorspace.c:692
l_ok convertRGBToYUV(l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pyval, l_int32 *puval, l_int32 *pvval)
convertRGBToYUV()
l_ok pixcmapConvertRGBToYUV(PIXCMAP *cmap)
pixcmapConvertRGBToYUV()
l_ok convertLABToXYZ(l_float32 lval, l_float32 aval, l_float32 bval, l_float32 *pxval, l_float32 *pyval, l_float32 *pzval)
convertLABToXYZ()
l_ok convertXYZToLAB(l_float32 xval, l_float32 yval, l_float32 zval, l_float32 *plval, l_float32 *paval, l_float32 *pbval)
convertXYZToLAB()
FPIXA * fpixaConvertXYZToLAB(FPIXA *fpixas)
fpixaConvertXYZToLAB()
PIX * pixConvertRGBToYUV(PIX *pixd, PIX *pixs)
pixConvertRGBToYUV()
l_ok convertRGBToLAB(l_int32 rval, l_int32 gval, l_int32 bval, l_float32 *pflval, l_float32 *pfaval, l_float32 *pfbval)
convertRGBToLAB()
PIX * pixMakeHistoSV(PIX *pixs, l_int32 factor, NUMA **pnasat, NUMA **pnaval)
pixMakeHistoSV()
PIX * pixMakeRangeMaskSV(PIX *pixs, l_int32 satcenter, l_int32 sathw, l_int32 valcenter, l_int32 valhw, l_int32 regionflag)
pixMakeRangeMaskSV()
Definition colorspace.c:885
PIX * displayHSVColorRange(l_int32 hval, l_int32 sval, l_int32 vval, l_int32 huehw, l_int32 sathw, l_int32 nsamp, l_int32 factor)
displayHSVColorRange()
PIX * pixConvertHSVToRGB(PIX *pixd, PIX *pixs)
pixConvertHSVToRGB()
Definition colorspace.c:204
l_ok convertYUVToRGB(l_int32 yval, l_int32 uval, l_int32 vval, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
convertYUVToRGB()
l_ok convertRGBToXYZ(l_int32 rval, l_int32 gval, l_int32 bval, l_float32 *pfxval, l_float32 *pfyval, l_float32 *pfzval)
convertRGBToXYZ()
l_ok pixcmapConvertYUVToRGB(PIXCMAP *cmap)
pixcmapConvertYUVToRGB()
FPIXA * pixConvertRGBToXYZ(PIX *pixs)
pixConvertRGBToXYZ()
PIX * pixConvertRGBToHSV(PIX *pixd, PIX *pixs)
pixConvertRGBToHSV()
Definition colorspace.c:142
PIX * pixMakeHistoHS(PIX *pixs, l_int32 factor, NUMA **pnahue, NUMA **pnasat)
pixMakeHistoHS()
Definition colorspace.c:972
PIX * pixConvertRGBToHue(PIX *pixs)
pixConvertRGBToHue()
Definition colorspace.c:488
PIX * pixMakeHistoHV(PIX *pixs, l_int32 factor, NUMA **pnahue, NUMA **pnaval)
pixMakeHistoHV()
@ L_HS_HISTO
Definition pix.h:983
@ L_SV_HISTO
Definition pix.h:985
@ L_HV_HISTO
Definition pix.h:984
@ L_NEG_SLOPE_LINE
Definition pix.h:809
@ REMOVE_CMAP_TO_FULL_COLOR
Definition pix.h:382
@ L_CLONE
Definition pix.h:506
@ L_INSERT
Definition pix.h:504
@ L_EXCLUDE_REGION
Definition pix.h:994
@ L_INCLUDE_REGION
Definition pix.h:993