1 /* LCh2CMC
2 *
3 * Modified:
4 * 2/11/09
5 * - gtkdoc
6 * 19/9/12
7 * - redone as a class
8 * 24/9/14
9 * - rechecked against original paper, seems OK
10 */
11
12 /*
13
14 This file is part of VIPS.
15
16 VIPS is free software; you can redistribute it and/or modify
17 it under the terms of the GNU Lesser General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU Lesser General Public License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29 02110-1301 USA
30
31 */
32
33 /*
34
35 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
36
37 */
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif /*HAVE_CONFIG_H*/
42 #include <vips/intl.h>
43
44 #include <stdio.h>
45 #include <math.h>
46
47 #include <vips/vips.h>
48
49 #include "pcolour.h"
50
51 typedef VipsColourTransform VipsLCh2CMC;
52 typedef VipsColourTransformClass VipsLCh2CMCClass;
53
54 G_DEFINE_TYPE( VipsLCh2CMC, vips_LCh2CMC, VIPS_TYPE_COLOUR_TRANSFORM );
55
56 /* I ordered this paper from the library and it took ages. For reference, the
57 * recommended short formula are:
58 *
59 * Lucs
60 * = 1.744 * L, L < 16
61 * = (1/l) * (21.75 * ln(L) + 0.3838 * L - 38.54), otherwise
62 *
63 * Cucs = (l/c) * (0.162 * C + 10.92 * (ln(0.638 + 0.07216 * C)) + 4.907)
64 *
65 * hucs = h + D * f
66 * where
67 * D = k4 + k5 * P * | P | ** k6
68 * P = cos(k7 * h + k8)
69 * f = (C ** 4 / (C ** 4 + 1900)) ** 0.5
70 *
71 * h k4 k5 k6 k7 k8
72 * 0 - 49 133.87 -134.5 -0.924 1.727 340
73 * 49 - 110 11.78 -12.7 -0.218 2.120 333
74 * 110 - 269.5 13.87 10.93 0.140 1.000 -83
75 * 269.5 - 360 0.14 5.23 0.170 1.610 233
76 *
77 * They have a much more complicated but slightly more accurate formula for
78 * hucs. This one is pretty good, simple approximation.
79 */
80
81 /**
82 * vips_col_L2Lcmc:
83 * @L: CIE L*
84 *
85 * Calculate Lcmc from L.
86 *
87 * Returns: Lcmc
88 */
89 float
vips_col_L2Lcmc(float L)90 vips_col_L2Lcmc( float L )
91 {
92 float Lcmc;
93
94 if( L < 16.0 )
95 Lcmc = 1.744 * L;
96 else
97 Lcmc = 21.75 * log( L ) + 0.3838 * L - 38.54;
98
99 return( Lcmc );
100 }
101
102 /**
103 * vips_col_C2Ccmc:
104 * @C: Chroma
105 *
106 * Calculate Ccmc from C.
107 *
108 * Returns: Ccmc.
109 */
110 float
vips_col_C2Ccmc(float C)111 vips_col_C2Ccmc( float C )
112 {
113 float Ccmc;
114
115 Ccmc = 0.162 * C + 10.92 * log( 0.638 + 0.07216 * C ) + 4.907;
116 if( Ccmc < 0 )
117 Ccmc = 0;
118
119 return( Ccmc );
120 }
121
122 /**
123 * vips_col_Ch2hcmc:
124 * @C: Chroma
125 * @h: Hue (degrees)
126 *
127 * Calculate hcmc from C and h.
128 *
129 * Returns: hcmc.
130 */
131 float
vips_col_Ch2hcmc(float C,float h)132 vips_col_Ch2hcmc( float C, float h )
133 {
134 float P, D, f, g;
135 float k4, k5, k6, k7, k8;
136 float hcmc;
137
138 if( h < 49.1 ) {
139 k4 = 133.87;
140 k5 = -134.5;
141 k6 = -.924;
142 k7 = 1.727;
143 k8 = 340.0;
144 }
145 else if( h < 110.1 ) {
146 k4 = 11.78;
147 k5 = -12.7;
148 k6 = -.218;
149 k7 = 2.12;
150 k8 = 333.0;
151 }
152 else if( h < 269.6 ) {
153 k4 = 13.87;
154 k5 = 10.93;
155 k6 = 0.14;
156 k7 = 1.0;
157 k8 = -83.0;
158 }
159 else {
160 k4 = .14;
161 k5 = 5.23;
162 k6 = .17;
163 k7 = 1.61;
164 k8 = 233.0;
165 }
166
167 P = cos( VIPS_RAD( k7 * h + k8 ) );
168 D = k4 + k5 * P * pow( VIPS_FABS( P ), k6 );
169 g = C * C * C * C;
170 f = sqrt( g / (g + 1900.0) );
171 hcmc = h + D * f;
172
173 return( hcmc );
174 }
175
176 static void
vips_LCh2CMC_line(VipsColour * colour,VipsPel * out,VipsPel ** in,int width)177 vips_LCh2CMC_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
178 {
179 float *p = (float *) in[0];
180 float *q = (float *) out;
181
182 int x;
183
184 for( x = 0; x < width; x++ ) {
185 float L = p[0];
186 float C = p[1];
187 float h = p[2];
188
189 p += 3;
190
191 q[0] = vips_col_L2Lcmc( L );
192 q[1] = vips_col_C2Ccmc( C );
193 q[2] = vips_col_Ch2hcmc( C, h );
194
195 q += 3;
196 }
197 }
198
199 static void
vips_LCh2CMC_class_init(VipsLCh2CMCClass * class)200 vips_LCh2CMC_class_init( VipsLCh2CMCClass *class )
201 {
202 VipsObjectClass *object_class = (VipsObjectClass *) class;
203 VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
204
205 object_class->nickname = "LCh2CMC";
206 object_class->description = _( "transform LCh to CMC" );
207
208 colour_class->process_line = vips_LCh2CMC_line;
209 }
210
211 static void
vips_LCh2CMC_init(VipsLCh2CMC * LCh2CMC)212 vips_LCh2CMC_init( VipsLCh2CMC *LCh2CMC )
213 {
214 VipsColour *colour = VIPS_COLOUR( LCh2CMC );
215
216 colour->interpretation = VIPS_INTERPRETATION_CMC;
217 }
218
219 /**
220 * vips_LCh2CMC: (method)
221 * @in: input image
222 * @out: (out): output image
223 * @...: %NULL-terminated list of optional named arguments
224 *
225 * Turn LCh to CMC.
226 *
227 * The CMC colourspace is described in "Uniform Colour Space Based on the
228 * CMC(l:c) Colour-difference Formula", M R Luo and B Rigg, Journal of the
229 * Society of Dyers and Colourists, vol 102, 1986. Distances in this
230 * colourspace approximate, within 10% or so, differences in the CMC(l:c)
231 * colour difference formula.
232 *
233 * This operation generates CMC(1:1). For CMC(2:1), halve Lucs and double
234 * Cucs.
235 *
236 * See also: vips_CMC2LCh().
237 *
238 * Returns: 0 on success, -1 on error
239 */
240 int
vips_LCh2CMC(VipsImage * in,VipsImage ** out,...)241 vips_LCh2CMC( VipsImage *in, VipsImage **out, ... )
242 {
243 va_list ap;
244 int result;
245
246 va_start( ap, out );
247 result = vips_call_split( "LCh2CMC", ap, in, out );
248 va_end( ap );
249
250 return( result );
251 }
252