1 /* Copyright (C) <2010> Douglas Bagnall <douglas@halo.gen.nz>
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Library General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
13 * You should have received a copy of the GNU Library General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 02111-1307, USA.
21 #include "gstsparrow.h"
29 /* draw the line (in sparrow->colour) */
31 draw_line(GstSparrow
* sparrow
, sparrow_line_t
*line
, guint8
*out
){
32 guint32
*p
= (guint32
*)out
;
34 if (line
->dir
== SPARROW_HORIZONTAL
){
35 p
+= line
->offset
* sparrow
->out
.width
;
36 for (i
= 0; i
< sparrow
->out
.width
; i
++){
37 p
[i
] = sparrow
->colour
;
41 guint32
*p
= (guint32
*)out
;
43 for(i
= 0; i
< sparrow
->out
.height
; i
++){
45 p
+= sparrow
->out
.width
;
55 /*3 pixels manhatten distance makes you an outlier */
56 #define OUTLIER_THRESHOLD 3 << (SPARROW_FIXED_POINT)
57 #define OUTLIER_PENALTY 8
59 #define SIGNAL(c)((c).signal[SPARROW_HORIZONTAL] + (c).signal[SPARROW_VERTICAL])
62 find_corners(GstSparrow
*sparrow
, guint8
*in
, sparrow_find_lines_t
*fl
){
64 sparrow_cluster_t
*clusters
= malloc_or_die(fl
->n_hlines
* fl
->n_vlines
* sizeof(sparrow_cluster_t
));
67 for (y
= 0; y
< sparrow
->in
.height
; y
++){
68 for (x
= 0; x
< sparrow
->in
.width
; x
++){
69 sparrow_intersect_t
*p
= &fl
->map
[y
* sparrow
->in
.width
+ x
];
70 /*remembering that 0 is valid as a line no, but not as a signal */
71 if (! p
->signal
[SPARROW_HORIZONTAL
] ||
72 ! p
->signal
[SPARROW_VERTICAL
]){
75 /*This one is lobbying for the position of the corner.*/
77 /*XXX what to do in the case that there is no intersection? often cases
78 this will happen in the dark bits and be OK. But if it happens in the
80 /*linearise the xy coordinates*/
81 int vline
= p
->lines
[SPARROW_VERTICAL
];
82 int hline
= p
->lines
[SPARROW_HORIZONTAL
];
83 sparrow_cluster_t
*cluster
= &clusters
[vline
* fl
->n_hlines
+ hline
];
86 cluster
->voters
[n
].x
= x
<< SPARROW_FIXED_POINT
;
87 cluster
->voters
[n
].y
= y
<< SPARROW_FIXED_POINT
;
88 cluster
->voters
[n
].signal
= (SIG_WEIGHT
+ p
->signal
[SPARROW_HORIZONTAL
]) *
89 (SIG_WEIGHT
+ p
->signal
[SPARROW_VERTICAL
]);
93 GST_DEBUG("more than 8 pixels at cluster for corner %d, %d\n",
95 /*if this message ever turns up, replace the weakest signals or add
101 for (i
= 0; i
< fl
->n_hlines
* fl
->n_vlines
; i
++){
103 1. centre of gravity (x,y, weighted average)
104 2. discard outliers? look for connectedness? but if 2 are outliers?
106 sparrow_cluster_t
*cluster
= clusters
+ i
;
110 while(votes
) { /* don't diminish signal altogether */
115 for (j
= 0; j
< cluster
->n
; j
++){
116 votes
+= cluster
->voters
[j
].signal
;
117 ysum
+= cluster
->voters
[j
].y
* cluster
->voters
[j
].signal
;
118 xsum
+= cluster
->voters
[j
].x
* cluster
->voters
[j
].signal
;
120 xmean
= xsum
/ votes
;
121 ymean
= ysum
/ votes
;
125 for (j
= 0; j
< cluster
->n
; j
++){
126 int xdiff
= abs(cluster
->voters
[j
].x
- xmean
);
127 int ydiff
= abs(cluster
->voters
[j
].y
- ymean
);
128 devsum
+= xdiff
+ ydiff
;
129 if (xdiff
+ ydiff
> worst
){
130 worst
= xdiff
+ ydiff
;
134 /*a bad outlier has significantly greater than average deviation
135 (but how much is bad? median deviation would be more useful)*/
136 if (worst
> 3 * devsum
/ cluster
->n
){
137 /* reduce the worst ones weight. it is a silly aberration. */
138 cluster
->voters
[worstn
].signal
/= OUTLIER_PENALTY
;
139 GST_DEBUG("dropping outlier at %s,%s (mean %s,%s)\n",
140 cluster
->voters
[worstn
].x
, cluster
->voters
[worstn
].y
, xmean
, ymean
);
145 GST_DEBUG("found corner at (%3f, %3f)\n", xmean
/ 256.0, ymean
/ 256.0);
148 1. calculate deltas toward adjacent corners.
149 2. record the corners in sparrow object
156 /* With no line drawn (in our colour) look at the background noise. Any real
157 signal has to be stringer than this.
159 XXX looking for simple maximum -- maybe heap or histogram might be better,
160 so as to be less susceptible to wierd outliers (e.g., bad pixels). */
162 look_for_threshold(GstSparrow
*sparrow
, guint8
*in
, sparrow_find_lines_t
*fl
){
166 guint32
*in32
= (guint32
*)in
;
168 for (i
= 0; i
< (int)sparrow
->in
.size
; i
++){
169 colour
= in32
[i
] & sparrow
->colour
;
170 signal
= ((colour
>> fl
->shift1
) +
171 (colour
>> fl
->shift2
)) & 0x1ff;
172 if (signal
> highest
){
176 fl
->threshold
= highest
+ 10;
177 GST_DEBUG("found maximum noise of %s, using threshold %s\n", highest
, fl
->threshold
);
182 look_for_line(GstSparrow
*sparrow
, guint8
*in
, sparrow_find_lines_t
*fl
,
183 sparrow_line_t
*line
){
187 guint32
*in32
= (guint32
*)in
;
188 for (i
= 0; i
< sparrow
->in
.size
; i
++){
189 colour
= in32
[i
] & sparrow
->colour
;
190 signal
= ((colour
>> fl
->shift1
) +
191 (colour
>> fl
->shift2
)) & 0x1ff;
192 if (signal
> fl
->threshold
){
193 if (fl
->map
[i
].lines
[line
->dir
]){
194 GST_DEBUG("HEY, expected point %d to be in line %d (dir %d)"
195 "and thus empty, but it is also in line %d\n",
196 i
, line
->index
, line
->dir
, fl
->map
[i
].lines
[line
->dir
]);
198 fl
->map
[i
].lines
[line
->dir
] = line
->index
;
199 fl
->map
[i
].signal
[line
->dir
] = signal
;
205 /* show each line for 2 frames, then wait sparrow->lag frames, leaving line on
209 INVISIBLE sparrow_state
210 mode_find_edges(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
){
211 sparrow_find_lines_t
*fl
= (sparrow_find_lines_t
*)&sparrow
->helper_struct
;
212 sparrow_line_t
*line
= fl
->shuffled_lines
[fl
->current
];
213 sparrow
->countdown
--;
214 memset(out
, 0, sparrow
->out
.size
);
215 if (sparrow
->countdown
){
216 /* show the line except on the first round, when we find a threshold*/
218 draw_line(sparrow
, line
, out
);
222 /*show nothing, look for result */
224 if (fl
->current
== fl
->n_lines
){
227 look_for_line(sparrow
, in
, fl
, line
);
231 look_for_threshold(sparrow
, in
, fl
);
233 sparrow
->countdown
= sparrow
->lag
+ 2;
235 return SPARROW_STATUS_QUO
;
237 /*match up lines and find corners */
238 find_corners(sparrow
, in
, fl
);
241 /*free stuff!, including fl, and reset pointer to NULL*/
243 return SPARROW_NEXT_STATE
;
248 setup_colour_shifts(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
249 switch (sparrow
->colour
){
252 fl
->shift1
= sparrow
->in
.gshift
;
253 fl
->shift2
= sparrow
->in
.gshift
;
255 case SPARROW_MAGENTA
:
256 fl
->shift1
= sparrow
->in
.rshift
;
257 fl
->shift2
= sparrow
->in
.bshift
;
263 init_find_edges(GstSparrow
*sparrow
){
264 gint32 w
= sparrow
->out
.width
;
265 gint32 h
= sparrow
->out
.height
;
267 sparrow_find_lines_t
*fl
= zalloc_aligned_or_die(sizeof(sparrow_find_lines_t
));
268 sparrow
->helper_struct
= (void *)fl
;
270 gint h_lines
= (h
+ LINE_PERIOD
- 1) / LINE_PERIOD
;
271 gint v_lines
= (w
+ LINE_PERIOD
- 1) / LINE_PERIOD
;
272 gint n_lines
= (h_lines
+ v_lines
);
273 fl
->n_hlines
= h_lines
;
274 fl
->n_vlines
= v_lines
;
275 fl
->n_lines
= n_lines
;
277 fl
->h_lines
= malloc_aligned_or_die(sizeof(sparrow_line_t
) * n_lines
);
278 fl
->shuffled_lines
= malloc_aligned_or_die(sizeof(sparrow_line_t
*) * n_lines
);
279 fl
->map
= zalloc_aligned_or_die(sizeof(sparrow_intersect_t
) * sparrow
->in
.pixcount
);
281 sparrow_line_t
*line
= fl
->h_lines
;
282 sparrow_line_t
**sline
= fl
->shuffled_lines
;
283 int offset
= LINE_PERIOD
/ 2;
285 for (i
= 0, offset
= LINE_PERIOD
/ 2; offset
< h
;
286 i
++, offset
+= LINE_PERIOD
){
287 line
->offset
= offset
;
288 line
->dir
= SPARROW_HORIZONTAL
;
295 /*now add the vertical lines */
297 for (i
= 0, offset
= LINE_PERIOD
/ 2; offset
< w
;
298 i
++, offset
+= LINE_PERIOD
){
299 line
->offset
= offset
;
300 line
->dir
= SPARROW_VERTICAL
;
307 GST_DEBUG("allocated %s lines, used %s\n", n_lines
, line
- fl
->h_lines
);
309 /*now shuffle (triangluar, to no particular advantage) */
310 for (i
= 0; i
< n_lines
- 1; i
++){
311 int j
= RANDINT(sparrow
, i
+ 1, n_lines
);
312 sparrow_line_t
*tmp
= fl
->shuffled_lines
[j
];
313 fl
->shuffled_lines
[j
] = fl
->shuffled_lines
[i
];
314 fl
->shuffled_lines
[i
] = tmp
;
317 setup_colour_shifts(sparrow
, fl
);
318 sparrow
->countdown
= sparrow
->lag
+ 2;
320 sparrow
->mesh
= malloc_aligned_or_die(sizeof(sparrow_corner_t
) * h_lines
* v_lines
);