blind-set-luma.c (3592B)
1 /* See LICENSE file for copyright and license details. */ 2 #ifndef TYPE 3 #include "common.h" 4 5 USAGE("luma-stream") 6 7 #define FILE "blind-set-luma.c" 8 #include "define-functions.h" 9 10 int 11 main(int argc, char *argv[]) 12 { 13 struct stream colour, luma; 14 void (*process)(struct stream *colour, struct stream *luma, size_t n); 15 16 UNOFLAGS(argc != 1); 17 18 eopen_stream(&colour, NULL); 19 eopen_stream(&luma, argv[0]); 20 21 SELECT_PROCESS_FUNCTION(&colour); 22 CHECK_CHANS(&colour, == 3, == 1); 23 CHECK_COLOUR_SPACE(&colour, CIEXYZ); 24 25 fprint_stream_head(stdout, &colour); 26 efflush(stdout, "<stdout>"); 27 process_two_streams(&colour, &luma, STDOUT_FILENO, "<stdout>", process); 28 return 0; 29 } 30 31 #else 32 33 static void 34 PROCESS(struct stream *colour, struct stream *luma, size_t n) 35 {\ 36 size_t i; 37 TYPE a, y; 38 for (i = 0; i < n; i += colour->pixel_size) { 39 a = ((TYPE *)(luma->buf + i))[1]; 40 a *= ((TYPE *)(luma->buf + i))[3]; 41 y = ((TYPE *)(colour->buf + i))[1]; 42 ((TYPE *)(colour->buf + i))[0] += y * a - y; 43 ((TYPE *)(colour->buf + i))[1] = y * a; 44 ((TYPE *)(colour->buf + i))[2] += y * a - y; 45 /* 46 * Note, this changes the luma only, not the saturation, 47 * so the result may look a bit weird. To change both 48 * you can use `blind-arithm mul`. 49 * 50 * Explaination of algorithm: 51 * 52 * Y is the luma, but (X, Z) is not the chroma, 53 * but in CIELAB, L* is the luma and (a*, *b) is 54 * the chroma. Multiplying 55 * 56 * ⎛0 1 0⎞ 57 * ⎜1 −1 0⎟ 58 * ⎝0 1 −1⎠ 59 * 60 * (X Y Z)' gives a colour model similar to 61 * CIE L*a*b*: a model where each parameter is 62 * a linear transformation of the corresponding 63 * parameter in CIE L*a*b*. The inverse of that 64 * matrix is 65 * 66 * ⎛1 1 0⎞ 67 * ⎜1 0 0⎟ 68 * ⎝0 0 −1⎠ 69 * 70 * and 71 * 72 * ⎛1 1 0⎞⎛a 0 0⎞⎛0 1 0⎞ ⎛1 a−1 0⎞ 73 * ⎜1 0 0⎟⎜0 1 0⎟⎜1 −1 0⎟ = ⎜0 a 0⎟. 74 * ⎝0 0 −1⎠⎝0 0 1⎠⎝0 1 −1⎠ ⎝0 a−1 1⎠ 75 * 76 * Explanation of why changing only the luma looks weird: 77 * 78 * Consider when you are workings with colours, 79 * when you want to change the brightness of a 80 * colour, you multiply all parameters: red, green, 81 * and blue, with the same value (this is however 82 * only an approximation in most cases, since you 83 * are usually usally working with colours that 84 * have the sRGB transfer function applied to their 85 * parameters). This action is the same in all 86 * colour models and colour spaces that are a 87 * linear transformation of the sRGB colour spaces 88 * (sans transfer function); this is simply because 89 * of the properties of linear transformations. 90 * 91 * The reason you change brightness this way can 92 * be explained by how objects reflect colour. 93 * Objects can only reject colours that are present 94 * in the light source. A ideal white object will look 95 * pure red if the light sources is ideal red, and a 96 * a ideal blue object will pure black in the same 97 * light source. An object can also not reflect 98 * colours brighter than the source. When the brightness 99 * of a light source is changed, the intensity of all 100 * colours (by wavelength) it emits is multiplied by 101 * one value. Therefore, when changing the brightness 102 * it looks most natural when all primaries (red, green, 103 * and blue) are multiplied by one value, or all 104 * parameters of the used colour spaces is a linear 105 * transformation of sRGB, such as CIE XYZ. 106 */ 107 } 108 } 109 110 #endif