1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.openimaj.image.analysis.colour;
31
32 import org.openimaj.image.FImage;
33 import org.openimaj.image.MBFImage;
34 import org.openimaj.image.colour.ColourSpace;
35 import org.openimaj.image.combiner.ImageCombiner;
36
37
38
39
40
41
42
43
44 public class CIEDE2000 implements ImageCombiner<MBFImage, MBFImage, FImage> {
45
46
47
48
49
50
51 public static double calculateDeltaE(double [] lab1, double[] lab2) {
52 return calculateDeltaE(lab1[0],lab1[1],lab1[2],lab2[0],lab2[1],lab2[2]);
53 }
54
55
56
57
58
59
60
61 public static float calculateDeltaE(float [] lab1, float[] lab2) {
62 return (float) calculateDeltaE(lab1[0],lab1[1],lab1[2],lab2[0],lab2[1],lab2[2]);
63 }
64
65
66
67
68
69
70
71 public static float calculateDeltaE(Float [] lab1, Float[] lab2) {
72 return (float) calculateDeltaE(lab1[0],lab1[1],lab1[2],lab2[0],lab2[1],lab2[2]);
73 }
74
75
76
77
78
79
80
81
82
83
84
85 public static double calculateDeltaE(double L1, double a1, double b1, double L2, double a2, double b2) {
86 double Lmean = (L1 + L2) / 2.0;
87 double C1 = Math.sqrt(a1*a1 + b1*b1);
88 double C2 = Math.sqrt(a2*a2 + b2*b2);
89 double Cmean = (C1 + C2) / 2.0;
90
91 double G = ( 1 - Math.sqrt( Math.pow(Cmean, 7) / (Math.pow(Cmean, 7) + Math.pow(25, 7)) ) ) / 2;
92 double a1prime = a1 * (1 + G);
93 double a2prime = a2 * (1 + G);
94
95 double C1prime = Math.sqrt(a1prime*a1prime + b1*b1);
96 double C2prime = Math.sqrt(a2prime*a2prime + b2*b2);
97 double Cmeanprime = (C1prime + C2prime) / 2;
98
99 double h1prime = Math.atan2(b1, a1prime) + 2*Math.PI * (Math.atan2(b1, a1prime)<0 ? 1 : 0);
100 double h2prime = Math.atan2(b2, a2prime) + 2*Math.PI * (Math.atan2(b2, a2prime)<0 ? 1 : 0);
101 double Hmeanprime = ((Math.abs(h1prime - h2prime) > Math.PI) ? (h1prime + h2prime + 2*Math.PI) / 2 : (h1prime + h2prime) / 2);
102
103 double T = 1.0 - 0.17 * Math.cos(Hmeanprime - Math.PI/6.0) + 0.24 * Math.cos(2*Hmeanprime) + 0.32 * Math.cos(3*Hmeanprime + Math.PI/30) - 0.2 * Math.cos(4*Hmeanprime - 21*Math.PI/60);
104
105 double deltahprime = ((Math.abs(h1prime - h2prime) <= Math.PI) ? h2prime - h1prime : (h2prime <= h1prime) ? h2prime - h1prime + 2*Math.PI : h2prime - h1prime - 2*Math.PI);
106
107 double deltaLprime = L2 - L1;
108 double deltaCprime = C2prime - C1prime;
109 double deltaHprime = 2.0 * Math.sqrt(C1prime*C2prime) * Math.sin(deltahprime / 2.0);
110 double SL = 1.0 + ( (0.015*(Lmean - 50)*(Lmean - 50)) / (Math.sqrt( 20 + (Lmean - 50)*(Lmean - 50) )) );
111 double SC = 1.0 + 0.045 * Cmeanprime;
112 double SH = 1.0 + 0.015 * Cmeanprime * T;
113
114 double deltaTheta = (30 * Math.PI / 180) * Math.exp(-((180/Math.PI*Hmeanprime-275)/25)*((180/Math.PI*Hmeanprime-275)/25));
115 double RC = (2 * Math.sqrt(Math.pow(Cmeanprime, 7) / (Math.pow(Cmeanprime, 7) + Math.pow(25, 7))));
116 double RT = (-RC * Math.sin(2 * deltaTheta));
117
118 double KL = 1;
119 double KC = 1;
120 double KH = 1;
121
122 double deltaE = Math.sqrt(
123 ((deltaLprime/(KL*SL)) * (deltaLprime/(KL*SL))) +
124 ((deltaCprime/(KC*SC)) * (deltaCprime/(KC*SC))) +
125 ((deltaHprime/(KH*SH)) * (deltaHprime/(KH*SH))) +
126 (RT * (deltaCprime/(KC*SC)) * (deltaHprime/(KH*SH)))
127 );
128
129 return deltaE;
130 }
131
132
133
134
135
136
137
138
139
140 public static FImage makeDisparityMap(MBFImage im1, MBFImage im2) {
141 if (im1.colourSpace != ColourSpace.CIE_Lab) {
142 im1 = ColourSpace.convert(im1, ColourSpace.CIE_Lab);
143 }
144
145 if (im2.colourSpace != ColourSpace.CIE_Lab) {
146 im2 = ColourSpace.convert(im2, ColourSpace.CIE_Lab);
147 }
148
149 FImage disparity = new FImage(im1.getWidth(), im1.getHeight());
150 for (int y=0; y<disparity.height; y++) {
151 for (int x=0; x<disparity.width; x++) {
152 disparity.pixels[y][x] = calculateDeltaE(im1.getPixel(x, y), im2.getPixel(x, y));
153 }
154 }
155
156 return disparity;
157 }
158
159 @Override
160 public FImage combine(MBFImage image1, MBFImage image2) {
161 return makeDisparityMap(image2, image2);
162 }
163 }