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.feature.global;
31
32 import java.util.List;
33
34 import org.openimaj.citation.annotation.Reference;
35 import org.openimaj.citation.annotation.ReferenceType;
36 import org.openimaj.feature.DoubleFV;
37 import org.openimaj.feature.FeatureVectorProvider;
38 import org.openimaj.image.MBFImage;
39 import org.openimaj.image.analyser.ImageAnalyser;
40 import org.openimaj.image.analysis.colour.CIEDE2000;
41 import org.openimaj.image.colour.ColourSpace;
42 import org.openimaj.image.pixel.ConnectedComponent;
43 import org.openimaj.image.pixel.Pixel;
44 import org.openimaj.image.pixel.PixelSet;
45 import org.openimaj.image.segmentation.FelzenszwalbHuttenlocherSegmenter;
46
47
48
49
50
51
52
53
54
55 @Reference(
56 type = ReferenceType.Inproceedings,
57 author = { "Che-Hua Yeh", "Yuan-Chen Ho", "Brian A. Barsky", "Ming Ouhyoung" },
58 title = "Personalized Photograph Ranking and Selection System",
59 year = "2010",
60 booktitle = "Proceedings of ACM Multimedia",
61 pages = { "211", "220" },
62 month = "October",
63 customData = { "location", "Florence, Italy" })
64 public class ColourContrast implements ImageAnalyser<MBFImage>, FeatureVectorProvider<DoubleFV> {
65 FelzenszwalbHuttenlocherSegmenter<MBFImage> segmenter;
66 double contrast;
67
68
69
70
71
72 public ColourContrast() {
73 segmenter = new FelzenszwalbHuttenlocherSegmenter<MBFImage>();
74 }
75
76
77
78
79
80
81
82
83
84
85
86
87 public ColourContrast(float sigma, float k, int minSize) {
88 segmenter = new FelzenszwalbHuttenlocherSegmenter<MBFImage>(sigma, k, minSize);
89 }
90
91 @Override
92 public DoubleFV getFeatureVector() {
93 return new DoubleFV(new double[] { contrast });
94 }
95
96
97
98
99
100
101
102
103 @Override
104 public void analyseImage(MBFImage image) {
105 final List<ConnectedComponent> ccs = segmenter.segment(image);
106 final MBFImage labImage = ColourSpace.convert(image, ColourSpace.CIE_Lab);
107 final float[][] avgs = new float[ccs.size()][3];
108 final int w = image.getWidth();
109 final int h = image.getHeight();
110
111
112 for (int i = 0; i < avgs.length; i++) {
113 for (final Pixel p : ccs.get(i).pixels) {
114 final Float[] v = labImage.getPixel(p);
115
116 avgs[i][0] += v[0];
117 avgs[i][0] += v[1];
118 avgs[i][0] += v[2];
119 }
120 final int sz = ccs.get(i).pixels.size();
121 avgs[i][0] /= sz;
122 avgs[i][1] /= sz;
123 avgs[i][2] /= sz;
124 }
125
126 for (int i = 0; i < avgs.length; i++) {
127 for (int j = i + 1; j < avgs.length; j++) {
128 final PixelSet ci = ccs.get(i);
129 final PixelSet cj = ccs.get(i);
130 final float C = CIEDE2000.calculateDeltaE(avgs[i], avgs[j]);
131
132 contrast += (1 - distance(ci, cj, w, h)) * (C / (ci.calculateArea() * cj.calculateArea()));
133 }
134 }
135 }
136
137 float distance(PixelSet c1, PixelSet c2, int w, int h) {
138 final double[] cen1 = c1.calculateCentroid();
139 final double[] cen2 = c2.calculateCentroid();
140
141 final double dx = (cen1[0] - cen2[0]) / w;
142 final double dy = (cen1[1] - cen2[1]) / h;
143
144 return (float) (Math.sqrt(dx * dx + dy * dy) / Math.sqrt(2));
145 }
146 }