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"
30 static void dump_edges_info(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
, const char *filename
){
31 GST_DEBUG("about to save to %s\n", filename
);
32 FILE *f
= fopen(filename
, "w");
33 /* simply write fl, map, clusters and mesh in sequence */
34 GST_DEBUG("fl is %p, file is %p\n", fl
, f
);
35 GST_DEBUG("fl: %d x %d\n", sizeof(sparrow_find_lines_t
), 1);
36 fwrite(fl
, sizeof(sparrow_find_lines_t
), 1, f
);
37 GST_DEBUG("fl->map %d x %d\n", sizeof(sparrow_intersect_t
), sparrow
->in
.pixcount
);
38 fwrite(fl
->map
, sizeof(sparrow_intersect_t
), sparrow
->in
.pixcount
, f
);
39 GST_DEBUG("fl->clusters %d x %d\n", sizeof(sparrow_cluster_t
), fl
->n_hlines
* fl
->n_vlines
);
40 fwrite(fl
->clusters
, sizeof(sparrow_cluster_t
), fl
->n_hlines
* fl
->n_vlines
, f
);
41 GST_DEBUG("fl->mesh %d x %d\n", sizeof(sparrow_corner_t
), fl
->n_hlines
* fl
->n_vlines
);
42 fwrite(fl
->mesh
, sizeof(sparrow_corner_t
), fl
->n_hlines
* fl
->n_vlines
, f
);
46 static void read_edges_info(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
, const char *filename
){
47 FILE *f
= fopen(filename
, "r");
48 sparrow_find_lines_t fl2
;
49 size_t read
= fread(&fl2
, sizeof(sparrow_find_lines_t
), 1, f
);
50 assert(fl2
.n_hlines
== fl
->n_hlines
);
51 assert(fl2
.n_vlines
== fl
->n_vlines
);
53 guint n_corners
= fl
->n_hlines
* fl
->n_vlines
;
54 read
+= fread(fl
->map
, sizeof(sparrow_intersect_t
), sparrow
->in
.pixcount
, f
);
55 read
+= fread(fl
->clusters
, sizeof(sparrow_cluster_t
), n_corners
, f
);
56 read
+= fread(fl
->mesh
, sizeof(sparrow_corner_t
), n_corners
, f
);
61 static inline int sort_median(int *a
, guint n
)
64 /*stupid sort, but n is very small*/
65 for (i
= 0; i
< n
; i
++){
66 for (j
= i
+ 1; j
< n
; j
++){
75 int answer
= a
[middle
];
78 answer
+= a
[middle
- 1];
85 debug_lut(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
88 #define OFFSET(x, y, w)((((y) * (w)) >> SPARROW_FIXED_POINT) + ((x) >> SPARROW_FIXED_POINT))
90 static void corners_to_lut(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
91 //DEBUG_FIND_LINES(fl);
92 sparrow_map_t
*map
= &sparrow
->map
; /*rows in sparrow->out */
93 guint8
*mask
= sparrow
->screenmask
; /*mask in sparrow->in */
94 sparrow_corner_t
*mesh
= fl
->mesh
; /*maps regular points in ->out to points in ->in */
96 int mesh_w
= fl
->n_vlines
;
97 int mesh_h
= fl
->n_hlines
;
98 int in_w
= sparrow
->in
.width
;
99 int mcy
, mmy
, mcx
; /*Mesh Corner|Modulus X|Y*/
102 sparrow_map_row_t
*row
= map
->rows
;
103 sparrow_map_point_t
*p
= map
->point_mem
;
104 sparrow_corner_t
*mesh_row
= mesh
;
105 for(mcy
= 0; mcy
< mesh_h
; mcy
++){
106 for (mmy
= 0; mmy
< LINE_PERIOD
; mmy
++){
107 sparrow_corner_t
*mesh_square
= mesh_row
;
111 for(mcx
= 0; mcx
< mesh_w
; mcx
++){
112 if (mesh_square
->status
!= CORNER_UNUSED
){
113 int iy
= mesh_square
->in_y
+ mmy
* mesh_square
->dyd
;
114 int ix
= mesh_square
->in_x
+ mmy
* mesh_square
->dxd
;
115 int ii
= OFFSET(ix
, iy
, in_w
);
116 int ii_end
= OFFSET(ix
+ (LINE_PERIOD
- 1) * mesh_square
->dxr
,
117 iy
+ (LINE_PERIOD
- 1) * mesh_square
->dyr
, in_w
);
118 int start_on
= mask
[ii
];
119 int end_on
= mask
[ii_end
];
120 GST_DEBUG("start %d end %d row s %d e %d", start_on
, end_on
, row
->start
, row
->end
);
121 if(start_on
&& end_on
){
122 /*add the point, maybe switch on */
123 if (row
->start
== row
->end
){/* if both are 0 */
124 row
->start
= mcx
* LINE_PERIOD
;
128 p
->dx
= mesh_square
->dxr
;
129 p
->dy
= mesh_square
->dyr
;
133 /*add the point, switch off somewhere in the middle*/
134 for (x
= 1; x
< LINE_PERIOD
; x
++){
135 iy
+= mesh_square
->dyr
;
136 ix
+= mesh_square
->dxr
;
137 ii
= OFFSET(ix
, iy
, in_w
);
139 /*point is not in the same column with the others,
140 but sparrow knows this because the row->start says so */
141 row
->start
= mcx
+ x
;
144 p
->dx
= mesh_square
->dxr
;
145 p
->dy
= mesh_square
->dyr
;
152 /* add some, switch off */
153 for (x
= 1; x
< LINE_PERIOD
; x
++){
154 iy
+= mesh_square
->dyr
;
155 ix
+= mesh_square
->dxr
;
156 ii
= OFFSET(ix
, iy
, in_w
);
165 start > end: this is first off pixel.
166 start == end: row hasn't started (both 0)
167 start < end: both are set -- row is done
169 if (row
->start
> row
->end
){
170 row
->end
= mcx
* LINE_PERIOD
;
172 else if (row
->start
< row
->end
){
183 debug_lut(sparrow
, fl
);
187 corners_to_full_lut(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
188 //DEBUG_FIND_LINES(fl);
189 sparrow_corner_t
*mesh
= fl
->mesh
; /*maps regular points in ->out to points in ->in */
190 sparrow_map_lut_t
*map_lut
= sparrow
->map_lut
;
191 int mesh_w
= fl
->n_vlines
;
192 int mesh_h
= fl
->n_hlines
;
193 int mcy
, mmy
, mcx
, mmx
; /*Mesh Corner|Modulus X|Y*/
195 sparrow_corner_t
*mesh_row
= mesh
;
196 for(mcy
= 0; mcy
< mesh_h
; mcy
++){
197 for (mmy
= 0; mmy
< LINE_PERIOD
; mmy
++){
198 sparrow_corner_t
*mesh_square
= mesh_row
;
199 for(mcx
= 0; mcx
< mesh_w
; mcx
++){
200 int iy
= mesh_square
->in_y
+ mmy
* mesh_square
->dyd
;
201 int ix
= mesh_square
->in_x
+ mmy
* mesh_square
->dxd
;
202 for (mmx
= 0; mmx
< LINE_PERIOD
; mmx
++, i
++){
203 map_lut
[i
].x
= ix
>> SPARROW_FP_2_LUT
;
204 map_lut
[i
].y
= iy
>> SPARROW_FP_2_LUT
;
205 ix
+= mesh_square
->dxr
;
206 iy
+= mesh_square
->dyr
;
213 sparrow
->map_lut
= map_lut
;
216 #define DIV ((double)(1 << SPARROW_FIXED_POINT))
217 #define INTXY(x)((x) / (1 << SPARROW_FIXED_POINT))
218 #define FLOATXY(x)(((double)(x)) / (1 << SPARROW_FIXED_POINT))
220 debug_corners_image(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
221 sparrow_corner_t
*mesh
= fl
->mesh
;
222 guint32
*data
= (guint32
*)fl
->debug
->imageData
;
223 guint w
= fl
->debug
->width
;
224 memset(data
, 0, sparrow
->in
.size
);
225 guint32 colours
[4] = {0xff0000ff, 0x00ff0000, 0x0000ff00, 0xcccccccc};
226 for (int i
= 0; i
< fl
->n_vlines
* fl
->n_hlines
; i
++){
227 sparrow_corner_t
*c
= &mesh
[i
];
230 GST_DEBUG("i %d status %d x: %f, y: %f dxr %f dyr %f dxd %f dyd %f\n"
231 "int x, y %d,%d (raw %d,%d) data %p\n",
232 i
, c
->status
, FLOATXY(x
), FLOATXY(y
),
233 FLOATXY(c
->dxr
), FLOATXY(c
->dyr
), FLOATXY(c
->dxd
), FLOATXY(c
->dyd
),
234 INTXY(x
), INTXY(y
), x
, y
, data
);
239 for (int j
= 1; j
< LINE_PERIOD
; j
++){
244 data
[INTXY(tyr
) * w
+ INTXY(txr
)] = 0x000088;
245 data
[INTXY(tyd
) * w
+ INTXY(txd
)] = 0x663300;
248 #define LP8 (LINE_PERIOD / 8)
249 #define LP4 (LINE_PERIOD / 4)
250 #define LP2 (LINE_PERIOD / 2)
251 data
[INTXY(y
+ c
->dyr
* LP8
) * w
+ INTXY(x
+ c
->dxr
* LP8
)] = 0xbbbbbbbb;
252 data
[INTXY(y
+ c
->dyr
* LP4
) * w
+ INTXY(x
+ c
->dxr
* LP4
)] = 0xaaaaaaaa;
253 data
[INTXY(y
+ c
->dyr
* LP2
) * w
+ INTXY(x
+ c
->dxr
* LP2
)] = 0x99999999;
254 data
[INTXY(y
+ c
->dyd
* LP8
) * w
+ INTXY(x
+ c
->dxd
* LP8
)] = 0xbb6666bb;
255 data
[INTXY(y
+ c
->dyd
* LP4
) * w
+ INTXY(x
+ c
->dxd
* LP4
)] = 0xaa5555aa;
256 data
[INTXY(y
+ c
->dyd
* LP2
) * w
+ INTXY(x
+ c
->dxd
* LP2
)] = 0x99444499;
258 data
[INTXY(y
) * w
+ INTXY(x
)] = colours
[c
->status
];
260 MAYBE_DEBUG_IPL(fl
->debug
);
265 debug_clusters(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
266 guint32
*data
= (guint32
*)fl
->debug
->imageData
;
267 memset(data
, 0, sparrow
->in
.size
);
268 int width
= fl
->n_vlines
;
269 int height
= fl
->n_hlines
;
270 sparrow_cluster_t
*clusters
= fl
->clusters
;
273 guint32 colours
[4] = {0xff0000ff, 0x0000ff00, 0x00ff0000,
275 for (i
= 0; i
< width
* height
; i
++){
276 colour
= colours
[i
% 5];
277 sparrow_voter_t
*v
= clusters
[i
].voters
;
278 for (j
= 0; j
< clusters
[i
].n
; j
++){
279 data
[(v
[j
].y
>> SPARROW_FIXED_POINT
) * sparrow
->in
.width
+
280 (v
[j
].x
>> SPARROW_FIXED_POINT
)] = (colour
* (v
[j
].signal
/ 2)) / 256;
283 MAYBE_DEBUG_IPL(fl
->debug
);
286 /*signal product is close to 18 bits. reduce to 4 */
287 #define SIGNAL_QUANT (1 << 14)
289 /*maximum number of pixels in a cluster */
290 #define CLUSTER_SIZE 8
295 make_clusters(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
296 sparrow_cluster_t
*clusters
= fl
->clusters
;
298 /*special case: spurious values collect up at 0,0 */
299 fl
->map
[0].signal
[SPARROW_VERTICAL
] = 0;
300 fl
->map
[0].signal
[SPARROW_HORIZONTAL
] = 0;
301 /*each point in fl->map is in a vertical line, a horizontal line, both, or
302 neither. Only the "both" case matters. */
303 for (y
= 0; y
< sparrow
->in
.height
; y
++){
304 for (x
= 0; x
< sparrow
->in
.width
; x
++){
305 sparrow_intersect_t
*p
= &fl
->map
[y
* sparrow
->in
.width
+ x
];
306 guint vsig
= p
->signal
[SPARROW_VERTICAL
];
307 guint hsig
= p
->signal
[SPARROW_HORIZONTAL
];
308 /*remembering that 0 is valid as a line number, but not as a signal */
309 if (! (vsig
&& hsig
)){
312 /*This one is lobbying for the position of a corner.*/
313 int vline
= p
->lines
[SPARROW_VERTICAL
];
314 int hline
= p
->lines
[SPARROW_HORIZONTAL
];
316 sparrow_cluster_t
*cluster
= &clusters
[hline
* fl
->n_vlines
+ vline
];
317 sparrow_voter_t
*voters
= cluster
->voters
;
319 guint signal
= (vsig
* hsig
) / SIGNAL_QUANT
;
320 GST_DEBUG("signal at %p (%d, %d): %dv %dh, product %u, lines: %dv %dh\n"
321 "cluster is %p, n is %d\n", p
, x
, y
,
322 vsig
, hsig
, signal
, vline
, hline
, cluster
, n
);
324 GST_WARNING("signal at %p (%d, %d) is %d following quantisation!\n",
328 if (n
< CLUSTER_SIZE
){
331 voters
[n
].signal
= signal
;
335 /*duplicate x, y, signal, so they aren't mucked up */
339 /*replaced one ends up here */
343 for (int j
= 0; j
< CLUSTER_SIZE
; j
++){
344 if (voters
[j
].signal
< ts
){
345 ts2
= voters
[j
].signal
;
348 voters
[j
].signal
= ts
;
356 GST_DEBUG("more than %d pixels at cluster for corner %d, %d."
357 "Dropped %u for %u\n",
358 CLUSTER_SIZE
, vline
, hline
, ts2
, signal
);
363 debug_clusters(sparrow
, fl
);
367 /* look for connected group. if there is more than one connected group,
371 drop_cluster_voter(sparrow_cluster_t
*cluster
, int n
)
374 for (int i
= n
; i
< cluster
->n
- 1; i
++){
375 cluster
->voters
[i
] = cluster
->voters
[i
+ 1];
382 median_discard_cluster_outliers(sparrow_cluster_t
*cluster
)
384 int xvals
[CLUSTER_SIZE
];
385 int yvals
[CLUSTER_SIZE
];
387 for (i
= 0; i
< cluster
->n
; i
++){
388 /*XXX could sort here*/
389 xvals
[i
] = cluster
->voters
[i
].x
;
390 yvals
[i
] = cluster
->voters
[i
].y
;
392 const int xmed
= sort_median(xvals
, cluster
->n
);
393 const int ymed
= sort_median(yvals
, cluster
->n
);
395 for (i
= 0; i
< cluster
->n
; i
++){
396 int dx
= cluster
->voters
[i
].x
- xmed
;
397 int dy
= cluster
->voters
[i
].y
- ymed
;
398 if (dx
*dx
+ dy
* dy
> OUTLIER_THRESHOLD
){
399 drop_cluster_voter(cluster
, i
);
406 make_corners(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
407 //DEBUG_FIND_LINES(fl);
408 int width
= fl
->n_vlines
;
409 int height
= fl
->n_hlines
;
410 sparrow_cluster_t
*clusters
= fl
->clusters
;
411 sparrow_corner_t
*mesh
= fl
->mesh
;
415 for (y
= 0; y
< height
; y
++){
416 for (x
= 0; x
< width
; x
++, i
++){
417 sparrow_cluster_t
*cluster
= clusters
+ i
;
418 if (cluster
->n
== 0){
422 /*the good points should all be adjacent; distant ones are spurious, so
424 median_discard_cluster_outliers(cluster
);
426 /* now find a weighted average position */
434 for (j
= 0; j
< cluster
->n
; j
++){
435 votes
+= cluster
->voters
[j
].signal
;
436 ysum
+= cluster
->voters
[j
].y
* cluster
->voters
[j
].signal
;
437 xsum
+= cluster
->voters
[j
].x
* cluster
->voters
[j
].signal
;
440 xmean
= (xsum
<< SPARROW_FIXED_POINT
) / votes
;
441 ymean
= (ysum
<< SPARROW_FIXED_POINT
) / votes
;
444 GST_WARNING("corner %d, %d voters, sum %d,%d, somehow has no votes\n",
445 i
, cluster
->n
, xsum
, ysum
);
448 GST_DEBUG("corner %d: %d voters, %d votes, sum %d,%d, mean %d,%d\n",
449 i
, cluster
->n
, votes
, xsum
, ysum
, xmean
, ymean
);
451 mesh
[i
].in_x
= xmean
;
452 mesh
[i
].in_y
= ymean
;
453 mesh
[i
].status
= CORNER_EXACT
;
454 GST_DEBUG("found corner %d at (%3f, %3f)\n",
455 i
, FLOATXY(xmean
), FLOATXY(ymean
));
460 #define LINE_PERIOD_TMP 1
463 make_map(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
465 int width
= fl
->n_vlines
;
466 int height
= fl
->n_hlines
;
467 sparrow_corner_t
*mesh
= fl
->mesh
;
470 //DEBUG_FIND_LINES(fl);
471 /* calculate deltas toward adjacent corners */
472 /* try to extrapolate left and up, if possible, so need to go backwards. */
473 i
= width
* height
- 1;
474 for (y
= height
- 1; y
>= 0; y
--){
475 for (x
= width
- 1; x
>= 0; x
--, i
--){
476 sparrow_corner_t
*corner
= &mesh
[i
];
477 /* calculate the delta to next corner. If this corner is on edge, delta is
478 0 and next is this.*/
479 sparrow_corner_t
*right
= (x
>= width
- 1) ? corner
: corner
+ 1;
480 sparrow_corner_t
*down
= (y
>= height
- 1) ? corner
: corner
+ width
;
481 GST_DEBUG("i %d xy %d,%d width %d. in_xy %d,%d; down in_xy %d,%d; right in_xy %d,%d\n",
482 i
, x
, y
, width
, corner
->in_x
, corner
->in_y
, down
->in_x
,
483 down
->in_y
, right
->in_x
, right
->in_y
);
484 if (corner
->status
!= CORNER_UNUSED
){
485 corner
->dxr
= (right
->in_x
- corner
->in_x
) / LINE_PERIOD_TMP
;
486 corner
->dyr
= (right
->in_y
- corner
->in_y
) / LINE_PERIOD_TMP
;
487 corner
->dxd
= (down
->in_x
- corner
->in_x
) / LINE_PERIOD_TMP
;
488 corner
->dyd
= (down
->in_y
- corner
->in_y
) / LINE_PERIOD_TMP
;
491 /*copy from both right and down, if they both exist. */
497 } dividends
= {0, 0, 0, 0};
503 if (right
!= corner
){
504 if (right
->dxr
|| right
->dyr
){
505 dividends
.dxr
+= right
->dxr
;
506 dividends
.dyr
+= right
->dyr
;
509 if (right
->dxd
|| right
->dyd
){
510 dividends
.dxd
+= right
->dxd
;
511 dividends
.dyd
+= right
->dyd
;
516 if (down
->dxr
|| down
->dyr
){
517 dividends
.dxr
+= down
->dxr
;
518 dividends
.dyr
+= down
->dyr
;
521 if (down
->dxd
|| down
->dyd
){
522 dividends
.dxd
+= down
->dxd
;
523 dividends
.dyd
+= down
->dyd
;
527 corner
->dxr
= divisors
.r
? dividends
.dxr
/ divisors
.r
: 0;
528 corner
->dyr
= divisors
.r
? dividends
.dyr
/ divisors
.r
: 0;
529 corner
->dxd
= divisors
.d
? dividends
.dxd
/ divisors
.d
: 0;
530 corner
->dyd
= divisors
.d
? dividends
.dyd
/ divisors
.d
: 0;
532 /*now extrapolate position, preferably from both left and right */
533 if (right
== corner
){
534 if (down
!= corner
){ /*use down only */
535 corner
->in_x
= down
->in_x
- corner
->dxd
* LINE_PERIOD_TMP
;
536 corner
->in_y
= down
->in_y
- corner
->dyd
* LINE_PERIOD_TMP
;
539 GST_DEBUG("can't reconstruct corner %d, %d: no useable neighbours\n", x
, y
);
540 /*it would be easy enough to look further, but hopefully of no
544 else if (down
== corner
){ /*use right only */
545 corner
->in_x
= right
->in_x
- corner
->dxr
* LINE_PERIOD_TMP
;
546 corner
->in_y
= right
->in_y
- corner
->dyr
* LINE_PERIOD_TMP
;
548 else { /* use both */
549 corner
->in_x
= right
->in_x
- corner
->dxr
* LINE_PERIOD_TMP
;
550 corner
->in_y
= right
->in_y
- corner
->dyr
* LINE_PERIOD_TMP
;
551 corner
->in_x
+= down
->in_x
- corner
->dxd
* LINE_PERIOD_TMP
;
552 corner
->in_y
+= down
->in_y
- corner
->dyd
* LINE_PERIOD_TMP
;
556 corner
->status
= CORNER_PROJECTED
;
561 DEBUG_FIND_LINES(fl
);
562 debug_corners_image(sparrow
, fl
);
569 look_for_line(GstSparrow
*sparrow
, guint8
*in
, sparrow_find_lines_t
*fl
,
570 sparrow_line_t
*line
){
573 guint32 cmask
= sparrow
->out
.colours
[sparrow
->colour
];
576 /* subtract background noise */
577 fl
->input
->imageData
= (char *)in
;
578 cvSub(fl
->input
, fl
->threshold
, fl
->working
, NULL
);
579 guint32
*in32
= (guint32
*)fl
->working
->imageData
;
581 for (i
= 0; i
< sparrow
->in
.pixcount
; i
++){
582 colour
= in32
[i
] & cmask
;
583 signal
= ((colour
>> fl
->shift1
) +
584 (colour
>> fl
->shift2
)) & 0x1ff;
586 if (fl
->map
[i
].lines
[line
->dir
]){
587 GST_DEBUG("HEY, expected point %d to be in line %d (dir %d)"
588 "and thus empty, but it is also in line %d\n",
589 "old signal %d, new signal %d, ignoring weakest\n",
590 i
, line
->index
, line
->dir
, fl
->map
[i
].lines
[line
->dir
],
591 fl
->map
[i
].signal
[line
->dir
], signal
);
592 if (signal
< fl
->map
[i
].signal
[line
->dir
]){
596 fl
->map
[i
].lines
[line
->dir
] = line
->index
;
597 fl
->map
[i
].signal
[line
->dir
] = signal
;
603 debug_map_image(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
604 guint32
*data
= (guint32
*)fl
->debug
->imageData
;
605 memset(data
, 0, sparrow
->in
.size
);
606 for (guint i
= 0; i
< sparrow
->in
.pixcount
; i
++){
607 data
[i
] |= (fl
->map
[i
].signal
[SPARROW_HORIZONTAL
] >> 1) << sparrow
->in
.gshift
;
608 data
[i
] |= (fl
->map
[i
].signal
[SPARROW_VERTICAL
] >> 1) << sparrow
->in
.rshift
;
610 MAYBE_DEBUG_IPL(fl
->debug
);
613 /* draw the line (in sparrow->colour) */
615 draw_line(GstSparrow
* sparrow
, sparrow_line_t
*line
, guint8
*out
){
616 guint32
*p
= (guint32
*)out
;
617 guint32 colour
= sparrow
->out
.colours
[sparrow
->colour
];
619 if (line
->dir
== SPARROW_HORIZONTAL
){
620 p
+= line
->offset
* sparrow
->out
.width
;
621 for (i
= 0; i
< sparrow
->out
.width
; i
++){
626 guint32
*p
= (guint32
*)out
;
628 for(i
= 0; i
< sparrow
->out
.height
; i
++){
630 p
+= sparrow
->out
.width
;
636 jump_state(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
, edges_state_t state
){
637 if (state
== EDGES_NEXT_STATE
){
644 case EDGES_FIND_NOISE
:
645 sparrow
->countdown
= sparrow
->lag
+ 2;
647 case EDGES_FIND_LINES
:
648 sparrow
->countdown
= sparrow
->lag
+ 2;
650 case EDGES_FIND_CORNERS
:
651 sparrow
->countdown
= 4;
653 GST_DEBUG("jumped to state %d\n", fl
->state
);
658 /* show each line for 2 frames, then wait sparrow->lag frames, leaving line on
662 draw_lines(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
, guint8
*in
, guint8
*out
)
664 sparrow_line_t
*line
= fl
->shuffled_lines
[fl
->current
];
665 sparrow
->countdown
--;
666 memset(out
, 0, sparrow
->out
.size
);
667 if (sparrow
->countdown
){
668 GST_DEBUG("current %d line %p\n", fl
->current
, line
);
669 draw_line(sparrow
, line
, out
);
672 /*show nothing, look for result */
673 look_for_line(sparrow
, in
, fl
, line
);
675 debug_map_image(sparrow
, fl
);
678 if (fl
->current
== fl
->n_lines
){
679 jump_state(sparrow
, fl
, EDGES_NEXT_STATE
);
682 sparrow
->countdown
= sparrow
->lag
+ 2;
687 #define LINE_THRESHOLD 32
690 find_threshold(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
, guint8
*in
, guint8
*out
)
692 memset(out
, 0, sparrow
->out
.size
);
693 /*XXX should average/median over a range of frames */
694 if (sparrow
->countdown
== 0){
695 memcpy(fl
->threshold
->imageData
, in
, sparrow
->in
.size
);
696 /*add a constant, and smooth */
697 cvAddS(fl
->threshold
, cvScalarAll(LINE_THRESHOLD
), fl
->working
, NULL
);
698 cvSmooth(tmp
, fl
->threshold_im
, CV_GAUSSIAN
, 3, 0, 0, 0);
699 //cvSmooth(fl->working, fl->threshold, CV_MEDIAN, 3, 0, 0, 0);
700 jump_state(sparrow
, fl
, EDGES_NEXT_STATE
);
702 sparrow
->countdown
--;
705 /*match up lines and find corners */
707 find_corners(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
)
709 sparrow
->countdown
--;
710 switch(sparrow
->countdown
){
712 make_clusters(sparrow
, fl
);
715 make_corners(sparrow
, fl
);
718 make_map(sparrow
, fl
);
721 corners_to_lut(sparrow
, fl
);
724 GST_DEBUG("how did sparrow->countdown get to be %d?", sparrow
->countdown
);
725 sparrow
->countdown
= 4;
727 return sparrow
->countdown
;
731 INVISIBLE sparrow_state
732 mode_find_edges(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
){
733 sparrow_find_lines_t
*fl
= (sparrow_find_lines_t
*)sparrow
->helper_struct
;
735 case EDGES_FIND_NOISE
:
736 find_threshold(sparrow
, fl
, in
, out
);
738 case EDGES_FIND_LINES
:
739 draw_lines(sparrow
, fl
, in
, out
);
741 case EDGES_FIND_CORNERS
:
742 if (find_corners(sparrow
, fl
))
744 return SPARROW_NEXT_STATE
;
745 case EDGES_NEXT_STATE
:
746 break; /*shush gcc */
748 return SPARROW_STATUS_QUO
;
753 finalise_find_edges(GstSparrow
*sparrow
){
754 sparrow_find_lines_t
*fl
= (sparrow_find_lines_t
*)sparrow
->helper_struct
;
755 //DEBUG_FIND_LINES(fl);
756 if (sparrow
->save
&& *(sparrow
->save
)){
757 GST_DEBUG("about to save to %s\n", sparrow
->save
);
758 dump_edges_info(sparrow
, fl
, sparrow
->save
);
761 cvReleaseImage(&fl
->debug
);
764 free(fl
->shuffled_lines
);
768 cvReleaseImage(&fl
->threshold
);
769 cvReleaseImage(&fl
->working
);
770 cvReleaseImageHeader(&fl
->input
);
772 sparrow
->helper_struct
= NULL
;
777 setup_colour_shifts(GstSparrow
*sparrow
, sparrow_find_lines_t
*fl
){
778 switch (sparrow
->colour
){
781 fl
->shift1
= sparrow
->in
.gshift
;
782 fl
->shift2
= sparrow
->in
.gshift
;
784 case SPARROW_MAGENTA
:
785 fl
->shift1
= sparrow
->in
.rshift
;
786 fl
->shift2
= sparrow
->in
.bshift
;
793 init_find_edges(GstSparrow
*sparrow
){
794 gint32 w
= sparrow
->out
.width
;
795 gint32 h
= sparrow
->out
.height
;
797 sparrow_find_lines_t
*fl
= zalloc_aligned_or_die(sizeof(sparrow_find_lines_t
));
798 sparrow
->helper_struct
= (void *)fl
;
800 gint h_lines
= (h
+ LINE_PERIOD
- 1) / LINE_PERIOD
;
801 gint v_lines
= (w
+ LINE_PERIOD
- 1) / LINE_PERIOD
;
802 gint n_lines
= (h_lines
+ v_lines
);
803 gint n_corners
= (h_lines
* v_lines
);
804 fl
->n_hlines
= h_lines
;
805 fl
->n_vlines
= v_lines
;
806 fl
->n_lines
= n_lines
;
808 fl
->h_lines
= malloc_aligned_or_die(sizeof(sparrow_line_t
) * n_lines
);
809 fl
->shuffled_lines
= malloc_aligned_or_die(sizeof(sparrow_line_t
*) * n_lines
);
810 GST_DEBUG("shuffled lines, malloced %p\n", fl
->shuffled_lines
);
812 fl
->map
= zalloc_aligned_or_die(sizeof(sparrow_intersect_t
) * sparrow
->in
.pixcount
);
813 fl
->clusters
= zalloc_or_die(n_corners
* sizeof(sparrow_cluster_t
));
814 fl
->mesh
= zalloc_aligned_or_die(n_corners
* sizeof(sparrow_corner_t
));
816 sparrow_line_t
*line
= fl
->h_lines
;
817 sparrow_line_t
**sline
= fl
->shuffled_lines
;
818 int offset
= LINE_PERIOD
/ 2;
820 for (i
= 0, offset
= LINE_PERIOD
/ 2; offset
< h
;
821 i
++, offset
+= LINE_PERIOD
){
822 line
->offset
= offset
;
823 line
->dir
= SPARROW_HORIZONTAL
;
830 /*now add the vertical lines */
832 for (i
= 0, offset
= LINE_PERIOD
/ 2; offset
< w
;
833 i
++, offset
+= LINE_PERIOD
){
834 line
->offset
= offset
;
835 line
->dir
= SPARROW_VERTICAL
;
841 //DEBUG_FIND_LINES(fl);
843 GST_DEBUG("allocated %d lines, status %d\n", n_lines
, line
- fl
->h_lines
);
846 for (i
= 0; i
< n_lines
- 1; i
++){
847 int j
= RANDINT(sparrow
, 0, n_lines
);
848 sparrow_line_t
*tmp
= fl
->shuffled_lines
[j
];
849 fl
->shuffled_lines
[j
] = fl
->shuffled_lines
[i
];
850 fl
->shuffled_lines
[i
] = tmp
;
853 setup_colour_shifts(sparrow
, fl
);
855 if (sparrow
->reload
&& *(sparrow
->reload
)){
856 GST_DEBUG("sparrow>reload is %s\n", sparrow
->reload
);
857 read_edges_info(sparrow
, fl
, sparrow
->reload
);
858 memset(fl
->map
, 0, sizeof(sparrow_intersect_t
) * sparrow
->in
.pixcount
);
859 //memset(fl->clusters, 0, n_corners * sizeof(sparrow_cluster_t));
860 memset(fl
->mesh
, 0, n_corners
* sizeof(sparrow_corner_t
));
861 jump_state(sparrow
, fl
, EDGES_FIND_CORNERS
);
865 jump_state(sparrow
, fl
, EDGES_FIND_NOISE
);
867 /* opencv images for threshold finding */
868 CvSize size
= {sparrow
->in
.width
, sparrow
->in
.height
};
869 fl
->working
= cvCreateImage(size
, IPL_DEPTH_8U
, PIXSIZE
);
870 fl
->threshold
= cvCreateImage(size
, IPL_DEPTH_8U
, PIXSIZE
);
872 /*input has no data allocated -- it uses latest frame*/
873 fl
->input
= init_ipl_image(&sparrow
->in
, PIXSIZE
);
875 //DEBUG_FIND_LINES(fl);
877 fl
->debug
= cvCreateImage(size
, IPL_DEPTH_8U
, PIXSIZE
);