Browse code

Implement LUT interpolation

Dario Rodriguez authored on 16/01/2022 16:07:19
Showing 2 changed files
... ...
@@ -1,6 +1,6 @@
1 1
 CC=gcc
2 2
 CFLAGS=-g -Wall
3
-LDFLAGS=-lpng
3
+LDFLAGS=-lm -lpng
4 4
 
5 5
 all: luttool
6 6
 
... ...
@@ -13,13 +13,14 @@
13 13
 #include <stdlib.h>
14 14
 #include <unistd.h>
15 15
 #include <string.h>
16
+#include <math.h>
16 17
 #include <png.h>
17 18
 
18 19
 #define DEFAULT_IDENTITYSIZE 12 /* Same as RawTherapee's HaldCLUTs, 1728x1728 AKA (12*12)*12x12*(12*12), equivalent to a cube with 144px wide sides*/
19 20
 #define DEFAULT_QUALITY 85
20 21
 /* #define JPEG_SUPPORTED */
21 22
 
22
-int luttool_applylut(char *lutfilenamelist,char *infilename, char *outfilename,int quality,int identitysize);
23
+int luttool_applylut(char *lutfilenamelist,char *infilename, char *outfilename,int quality,int identitysize,int flaginterpolatelut);
23 24
 
24 25
 int util_pnginfo(char *filename, int *width, int *height);
25 26
 int util_pngload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height);
... ...
@@ -39,25 +40,36 @@ main(int argc, char *argv[])
39 40
         char *lutlist;
40 41
         int i;
41 42
         int flagseveralinfile;
43
+        int flaginterpolatelut;
42 44
         char bufoutfilename[1024];
43 45
         char *currentoutfilename;
44 46
         if(argc<2 || strcmp(argv[argc-1],"--help")==0) {
45 47
 #ifdef JPEG_SUPPORTED
46
-                printf("Syntax: %s [-q jpegquality] [-n identitylevel] {identity | lutfile[,lutfile[,...]]} { identity | infile1 } [infile2 [...]] -o outfile\n",argv[0]);
48
+                printf("Syntax: %s [-i] [-q jpegquality] [-n identitylevel] {identity | lutfile[,lutfile[,...]]} { identity | infile1 } [infile2 [...]] -o outfile\n",argv[0]);
47 49
                 printf("Example: %s haldclut.png sprite.png -o result.png\n",argv[0]);
50
+                printf("Example: %s -i haldclut.png sprite.png -o result.png\n",argv[0]);
48 51
                 printf("Example: %s -n 16 identity identity -o identity.png\n",argv[0]);
49 52
                 printf("Example: %s -q 85 haldclut.png infile.png -o outfile.jpg\n",argv[0]);
53
+                printf("NOTE: -i makes the program interpolate the LUTs.\n");
50 54
 #else
51 55
                 printf("Syntax: %s [-n identitylevel] {identity | lutfile[,lutfile[,...]]} { identity | infile1 } [infile2 [...]] -o outfile\n",argv[0]);
52 56
                 printf("Example: %s haldclut.png sprite.png -o result.png\n",argv[0]);
57
+                printf("Example: -i %s haldclut.png sprite.png -o result.png\n",argv[0]);
53 58
                 printf("Example: %s -n 16 identity identity -o identity.png\n",argv[0]);
59
+                printf("NOTE: -i makes the program interpolate the LUTs.\n");
54 60
 #endif
55 61
                 return(1);
56 62
         }
57 63
         /* parse arguments */
58 64
         identitysize=DEFAULT_IDENTITYSIZE;
59 65
         quality=DEFAULT_QUALITY;
60
-        for(firstarg=1;firstarg<(argc-1) && (strcmp(argv[firstarg],"-n")==0 || (strcmp(argv[firstarg],"-q")==0));) {
66
+        flaginterpolatelut=0;
67
+        for(firstarg=1
68
+          ;firstarg<(argc-1)
69
+          && (strcmp(argv[firstarg],"-n")==0
70
+          || strcmp(argv[firstarg],"-q")==0
71
+          || strcmp(argv[firstarg],"-i")==0)
72
+          ;) {
61 73
                 if(strcmp(argv[firstarg],"-n")==0) {
62 74
                         identitysize=atoi(argv[firstarg+1]);
63 75
                         if(identitysize<2 || identitysize>16) {
... ...
@@ -70,6 +82,9 @@ main(int argc, char *argv[])
70 82
                                 fprintf(stderr,"%s: ERROR: the parameter to -q must be between 1 and 100 (default: %i)\n",argv[0],DEFAULT_QUALITY);
71 83
                                 return(1);
72 84
                         }
85
+                } else if(strcmp(argv[firstarg],"-i")==0) {
86
+                        flaginterpolatelut=1;
87
+                        firstarg--; /* doesn't have param. */
73 88
                 }
74 89
                 firstarg+=2;
75 90
         }
... ...
@@ -107,7 +122,7 @@ main(int argc, char *argv[])
107 122
                         bufoutfilename[sizeof(bufoutfilename)-1]='\0';
108 123
                         currentoutfilename=bufoutfilename;
109 124
                 }
110
-                if(luttool_applylut(lutlist,argv[i],currentoutfilename,quality,identitysize)!=0) {
125
+                if(luttool_applylut(lutlist,argv[i],currentoutfilename,quality,identitysize,flaginterpolatelut)!=0) {
111 126
                         fprintf(stderr,"%s: ERROR: couldn't apply LUTs \"%s\" to \"%s\" or couldn't write \"%s\"\n",argv[0],lutlist,argv[i],currentoutfilename);
112 127
                         return(1);
113 128
                 }
... ...
@@ -116,7 +131,7 @@ main(int argc, char *argv[])
116 131
 }
117 132
 
118 133
 int
119
-luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,int identitysize)
134
+luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,int identitysize,int flaginterpolatelut)
120 135
 {
121 136
         char *curlut,*next;
122 137
         char filename[1024];
... ...
@@ -126,6 +141,7 @@ luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,i
126 141
         int sizelutbuf,lutwidth,lutheight;
127 142
         int sizeimgbuf,imgwidth,imgheight;
128 143
         int sizergblutbuf;
144
+        int res;
129 145
         lutbuf=imgbuf=rgblutbuf=NULL;
130 146
         sizelutbuf=sizeimgbuf=sizergblutbuf=0;
131 147
         lutwidth=lutheight=imgwidth=imgheight=0;
... ...
@@ -159,7 +175,12 @@ luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,i
159 175
                                 break; /* couldn't load lut */
160 176
                         }
161 177
                 }
162
-                if(luttool_rgba2lut4096(lutbuf, lutwidth, lutheight, &rgblutbuf, &sizergblutbuf)!=0) {
178
+                res=0;
179
+                if(flaginterpolatelut==0)
180
+                        res=luttool_rgba2lut4096(lutbuf, lutwidth, lutheight, &rgblutbuf, &sizergblutbuf);
181
+                else
182
+                        res=luttool_rgba2lut4096_interpolated(lutbuf, lutwidth, lutheight, &rgblutbuf, &sizergblutbuf);
183
+                if(res!=0) {
163 184
                         in_error=1;
164 185
                         break; /* couldn't process lut */
165 186
                 }
... ...
@@ -387,6 +408,92 @@ luttool_rgba2lut4096(char *rgba, int width, int height, char **lut4096, int *siz
387 408
         return(0);
388 409
 }
389 410
 
411
+int
412
+luttool_rgba2lut4096_interpolated(char *rgba, int width, int height, char **lut4096, int *sizelut4096)
413
+{
414
+        int n;
415
+        int reqsize;
416
+        float fr,fg,fb;
417
+        int ir,ig,ib;
418
+        int incr,incg,incb;
419
+        int posr,posg,posb;
420
+        int myrgb[3];
421
+        int x,y;
422
+        int r,g,b;
423
+        int i;
424
+        int isize,isizesq,isizesqminusone;
425
+        int osize,osizesq,osizesqminusone;
426
+        unsigned char *orig,*dest;
427
+        if(rgba==NULL || width!=height || lut4096==NULL || sizelut4096==NULL)
428
+                return(-1); /* sanity check error */
429
+        /* check if size is a supported size */
430
+        for(n=2;n<=16 && width!=(n*n*n);n++)
431
+                ;
432
+        if(n>16)
433
+                return(-1); /* invalid size */
434
+        /* expand lut4096 as necessary */
435
+        reqsize=4096*4096*3;
436
+        if(*sizelut4096<reqsize) {
437
+                char *newlut4096;
438
+                if((newlut4096=realloc(*lut4096,reqsize))==NULL)
439
+                      return(-1); /* insuf. mem. for resulting lut */
440
+                *lut4096=newlut4096;
441
+                *sizelut4096=reqsize;
442
+        }
443
+        /* do the conversion */
444
+        isize=n;
445
+        isizesq=n*n;
446
+        isizesqminusone=isizesq-1;
447
+        osize=16;
448
+        osizesq=osize*osize;
449
+        osizesqminusone=osizesq-1;
450
+        for(r=0;r<osizesq;r++) {
451
+                for(g=0;g<osizesq;g++) {
452
+                        for(b=0;b<osizesq;b++) {
453
+                                fr=((isizesqminusone*((float)r))/osizesqminusone);
454
+                                fg=((isizesqminusone*((float)g))/osizesqminusone);
455
+                                fb=((isizesqminusone*((float)b))/osizesqminusone);
456
+                                ir=floorf(fr);
457
+                                ig=floorf(fg);
458
+                                ib=floorf(fb);
459
+                                fr=fr-ir;
460
+                                fg=fg-ig;
461
+                                fb=fb-ib;
462
+                                myrgb[0]=myrgb[1]=myrgb[2]=0;
463
+                                for(i=0;i<2*2*2;i++) {
464
+                                        incr=(i>>2)&1;
465
+                                        incg=(i>>1)&1;
466
+                                        incb=i&1;
467
+                                        posr=ir+incr;
468
+                                        posr=(posr<0)?0:(posr>=isizesq)?isizesqminusone:posr;
469
+                                        posg=ig+incg;
470
+                                        posg=(posg<0)?0:(posg>=isizesq)?isizesqminusone:posg;
471
+                                        posb=ib+incb;
472
+                                        posb=(posb<0)?0:(posb>=isizesq)?isizesqminusone:posb;
473
+                                        x=posr+(posg%isize)*isizesq;
474
+                                        y=posb*isize+(posg/isize);
475
+                                        orig=(unsigned char *) (rgba+((y*width+x)<<2));
476
+                                        myrgb[0]+=orig[0]*((incr!=0)?fr:(1-fr));
477
+                                        myrgb[1]+=orig[1]*((incg!=0)?fg:(1-fg));
478
+                                        myrgb[2]+=orig[2]*((incb!=0)?fb:(1-fb));
479
+                                }
480
+                                myrgb[0]/=(i/2);
481
+                                myrgb[0]=(myrgb[0]<0)?0:(myrgb[0]>255)?255:myrgb[0];
482
+                                myrgb[1]/=(i/2);
483
+                                myrgb[1]=(myrgb[1]<0)?0:(myrgb[1]>255)?255:myrgb[1];
484
+                                myrgb[2]/=(i/2);
485
+                                myrgb[2]=(myrgb[2]<0)?0:(myrgb[2]>255)?255:myrgb[2];
486
+                                dest=(unsigned char *) ((*lut4096)+((r<<16)+(g<<8)+b)*3);
487
+                                dest[0]=myrgb[0];
488
+                                dest[1]=myrgb[1];
489
+                                dest[2]=myrgb[2];
490
+                        }
491
+                }
492
+        }
493
+        return(0);
494
+}
495
+
496
+
390 497
 int
391 498
 luttool_applylut4096(char *lut4096,char *imgbuf,int imgwidth,int imgheight)
392 499
 {