1
2 /* autopano-sift, Automatic panorama image creation
3 * Copyright (C) 2004 -- Sebastian Nowozin
4 *
5 * This program is free software released under the GNU General Public
6 * License, which is included in this software package (doc/LICENSE).
7 */
8
9 /* AreaFilter.cs
10 *
11 * Area maximizing match filtration using convex hull and polygon-area
12 * maximization.
13 *
14 * (C) Copyright 2004 -- Sebastian Nowozin (nowozin@cs.tu-berlin.de)
15 *
16 * Convex hull code based on Ken Clarksons original C implementation.
17 * Polygon area formula by Paul Bourke.
18 */
19
20 #include "AutoPanoSift.h"
21
22 #ifdef TEST_MAIN
main(int argc,char * argv[])23 int main (int argc, char* argv[])
24 {
25 ArrayList* al = ArrayList_new0 (FilterPoint_delete);
26 Random* rnd = Random_new0 ();
27
28 int n;
29 for (n = 0 ; n < 10 ; ++n) {
30 FilterPoint* p = FilterPoint_new0 ();
31
32 p->x = Random_NextDouble(rnd) * 400.0;
33 p->y = Random_NextDouble(rnd) * 400.0;
34
35 ArrayList_AddItem(al, p);
36 }
37 int i;
38 for(i=0; i<ArrayList_Count(al); i++) {
39 FilterPoint* p = ArrayList_GetItem(al, i);
40 WriteLine ("%f %f # GNUPLOT1", p->x, p->y);
41 }
42
43 AreaFilter* conv = AreaFilter_new0 ();
44 ArrayList* hull = AreaFilter_CreateConvexHull(conv, al);
45
46 WriteLine ("\nhull: %d elements", ArrayList_Count(hull));
47 int j;
48 for(j=0; j<ArrayList_Count(hull); j++) {
49 FilterPoint* p = ArrayList_GetItem(hull, j);
50 WriteLine ("%f %f # GNUPLOT2", p->x, p->y);
51 }
52
53 WriteLine ("\npolygon area: %f", AreaFilter_PolygonArea(conv, hull));
54 ArrayList_delete(al);
55 return 0;
56 }
57
58 #else
59
AreaFilter_new0()60 AreaFilter* AreaFilter_new0()
61 {
62 AreaFilter* self = (AreaFilter*)malloc(sizeof(AreaFilter));
63 return self;
64 }
65
AreaFilter_delete(AreaFilter * self)66 void AreaFilter_delete(AreaFilter* self)
67 {
68 if (self) {
69 free(self);
70 }
71 }
72
73 // Measure the absolute area of a non self-intersecting polygon.
74 // Formula by Paul Bourke
75 // (http://astronomy.swin.edu.au/~pbourke/geometry/polyarea/)
76 //
77 // The input points must be ordered (clock- or counter-clockwise). The
78 // polygon is closed automatically between the first and the last point,
79 // so there should not be two same points in the polygon point set.
AreaFilter_PolygonArea(AreaFilter * self,ArrayList * orderedPoints)80 double AreaFilter_PolygonArea (AreaFilter* self, ArrayList* orderedPoints)
81 {
82 double A = 0.0;
83
84 int n;
85 for (n = 0 ; n < ArrayList_Count(orderedPoints) ; ++n) {
86 FilterPoint* p0 = (FilterPoint*) ArrayList_GetItem(orderedPoints,n);
87 FilterPoint* p1 = (FilterPoint*) ArrayList_GetItem(orderedPoints, (n + 1) % ArrayList_Count(orderedPoints));
88
89 A += p0->x * p1->y - p1->x * p0->y;
90 }
91
92 A *= 0.5;
93
94 return (abs (A));
95 }
96
97 // Create the convex hull of a point set.
AreaFilter_CreateConvexHull(AreaFilter * self,ArrayList * points)98 ArrayList* AreaFilter_CreateConvexHull (AreaFilter* self, ArrayList* points)
99 {
100 int chn = AreaFilter_CreateHull (self, points);
101
102 ArrayList* hull = ArrayList_new0 (NULL);
103 int k;
104 for (k = 0 ; k < chn ; ++k)
105 ArrayList_AddItem(hull, ArrayList_GetItem (points, k));
106
107 return (hull);
108 }
109
AreaFilter_CompareLow(const FilterPoint * p1,const FilterPoint * p2)110 int AreaFilter_CompareLow (const FilterPoint* p1, const FilterPoint* p2)
111 {
112
113 double v = p1->x - p2->x;
114 if (v > 0)
115 return (1);
116 if (v < 0)
117 return (-1);
118
119 v = p2->y - p1->y;
120 if (v > 0)
121 return (1);
122 if (v < 0)
123 return (-1);
124
125 // Equal point
126 return (0);
127 }
128
AreaFilter_CompareHigh(const FilterPoint * p1,const FilterPoint * p2)129 int AreaFilter_CompareHigh (const FilterPoint* p1, const FilterPoint* p2)
130 {
131 return AreaFilter_CompareLow(p2, p1);
132 }
133
134
AreaFilter_ccw(ArrayList * points,int i,int j,int k)135 bool AreaFilter_ccw (ArrayList* points, int i, int j, int k)
136 {
137 double a = ((FilterPoint*)ArrayList_GetItem(points, i))->x - ((FilterPoint*)ArrayList_GetItem(points, j))->x;
138 double b = ((FilterPoint*)ArrayList_GetItem(points, i))->y - ((FilterPoint*)ArrayList_GetItem(points, j))->y;
139 double c = ((FilterPoint*)ArrayList_GetItem(points, k))->x - ((FilterPoint*)ArrayList_GetItem(points, j))->x;
140 double d = ((FilterPoint*)ArrayList_GetItem(points, k))->y - ((FilterPoint*)ArrayList_GetItem(points, j))->y;
141
142 return ((a * d - b * c) <= 0.0);
143 }
144
AreaFilter_MakeChain(AreaFilter * self,ArrayList * points,int (* comp)(const FilterPoint *,const FilterPoint *))145 int AreaFilter_MakeChain (AreaFilter* self, ArrayList* points, int (*comp)(const FilterPoint*, const FilterPoint*))
146 {
147 IComparator comparator;
148 comparator.compareTo = (int ( *)(IComparator *,const void *,const void *)) comp;
149 ArrayList_Sort(points, &comparator);
150
151 int s = 1;
152 int pCount = ArrayList_Count(points);
153 int i;
154 for (i = 2 ; i < pCount ; ++i) {
155 int j;
156 for (j = s ; j >= 1 && AreaFilter_ccw (points, i, j, j - 1) ; --j)
157 ;
158
159 s = j + 1;
160
161 // Swap
162 FilterPoint* t = (FilterPoint*) ArrayList_GetItem(points, s);
163 ArrayList_SetItem(points, s, ArrayList_GetItem(points, i));
164 ArrayList_SetItem(points, i, t);
165 }
166
167 return (s);
168 }
169
AreaFilter_CreateHull(AreaFilter * self,ArrayList * points)170 int AreaFilter_CreateHull (AreaFilter* self, ArrayList* points)
171 {
172 int u = AreaFilter_MakeChain (self, points, AreaFilter_CompareLow);
173
174 if (ArrayList_Count(points) == 0)
175 return (0);
176 /*
177 int k;
178 for (k = 0 ; k < u ; ++k)
179 WriteLine ("point %d: %f %f", k, ((FilterPoint*)ArrayList_GetItem(points, k)[k])->x,
180 ((FilterPoint*)ArrayList_GetItem(points, k)[k])->y);
181 */
182
183 ArrayList* pointsHigh = ArrayList_new(ArrayList_Count(points)+1-u, NULL);
184 //WriteLine ("points.Length = %d, u = %d", ArrayList_Count(points), u);
185
186 ArrayList_Copy (points, u, pointsHigh, 0, ArrayList_Count(points) - u);
187 ArrayList_SetItem(pointsHigh, ArrayList_Count(pointsHigh) - 1, ArrayList_GetItem(points, 0));
188
189 int h = AreaFilter_MakeChain (self, pointsHigh, AreaFilter_CompareHigh);
190
191 int p;
192 for ( p = u ; p < ArrayList_Count(points) ; ++p) {
193 ArrayList_SetItem(points, p, ArrayList_GetItem(pointsHigh, p-u));
194 }
195
196 /*
197 WriteLine ("h = %d, u = %d", h, u);
198 int k;
199 for (k = 0 ; k < (h + u) ; ++k)
200 WriteLine ("point %d: %f %f", k, ((FilterPoint*)ArrayList_GetItem(points, k)[k])->x,
201 ((FilterPoint*)ArrayList_GetItem(points, k)[k])->y);
202 */
203
204 return (h + u);
205 }
206
207 #endif
208
209