scale fixed point back to integer, or nothing works
[sparrow.git] / floodfill.c
blob557fa463e3debb6df3da0ff489add6d87787171d
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.
19 #include "sparrow.h"
20 #include "gstsparrow.h"
22 #include <string.h>
23 #include <math.h>
25 #define STUPID_DEBUG_TRICK 0
26 #define WAIT_TIME CALIBRATE_MAX_T + 5
28 typedef struct sparrow_find_screen_s {
29 IplImage *green;
30 IplImage *working;
31 IplImage *mask;
32 IplImage *im;
33 gboolean waiting;
34 IplImage *signal;
35 } sparrow_find_screen_t;
38 /* Floodfill for find screen */
39 static inline void
40 expand_one_mono(int x, int y, int c,
41 CvPoint *nexts, int *n_nexts, guint8 *im, guint8 *mask, int w, int h){
42 guint8 p = im[y * w + x];
43 guint8 *m = &mask[y * w + x];
44 if (*m && (p == c)){
45 *m = 0;
46 nexts[*n_nexts].x = x;
47 nexts[*n_nexts].y = y;
48 (*n_nexts)++;
53 im: the image to be analysed
54 mim: the mask image to be written
55 start: a point of the right colour.
58 static IplImage*
59 floodfill_mono_superfast(IplImage *im, IplImage *mim, CvPoint start)
61 guint8 * data = (guint8 *)im->imageData;
62 guint8 * mdata = (guint8 *)mim->imageData;
63 int w = im->width;
64 int h = im->height;
65 int n_starts;
66 int n_nexts = 0;
67 CvPoint *starts;
68 CvPoint *nexts;
70 //malloc 2 lists of points. These *could* be as large as the image (but never should be)
71 void * mem = malloc_or_die(w * h * 2 * sizeof(CvPoint));
72 starts = mem;
73 nexts = starts + w * h;
74 n_starts = 1;
75 starts[0] = start;
77 while(n_starts){
78 n_nexts = 0;
79 int i;
80 for (i = 0; i < n_starts; i++){
81 int x = starts[i].x;
82 int y = starts[i].y;
83 int c = data[y * w + x];
84 if (x > 0){
85 expand_one_mono(x - 1, y, c, nexts, &n_nexts, data, mdata, w, h);
87 if (x < w - 1){
88 expand_one_mono(x + 1, y, c, nexts, &n_nexts, data, mdata, w, h);
90 if (y > 0){
91 expand_one_mono(x, y - 1, c, nexts, &n_nexts, data, mdata, w, h);
93 if (y < h - 1){
94 expand_one_mono(x, y + 1, c, nexts, &n_nexts, data, mdata, w, h);
97 CvPoint *tmp = starts;
98 starts = nexts;
99 nexts = tmp;
100 n_starts = n_nexts;
102 free(mem);
103 return im;
106 static inline IplImage *
107 extract_green_channel(GstSparrow *sparrow, sparrow_find_screen_t *finder, guint8 *in)
109 IplImage *im = finder->im;
110 IplImage *green = finder->green;
111 im->imageData = (char*)in;
112 guint32 gshift = sparrow->in.gshift;
113 cvSplit(im,
114 (gshift == 24) ? green : NULL,
115 (gshift == 16) ? green : NULL,
116 (gshift == 8) ? green : NULL,
117 (gshift == 0) ? green : NULL);
118 return green;
122 #define SIGNAL_THRESHOLD 100
123 /*see whether there seems to be activity: */
124 gboolean INVISIBLE
125 check_for_signal(GstSparrow *sparrow, sparrow_find_screen_t *finder, guint8 *in){
126 IplImage *green = extract_green_channel(sparrow, finder, in);
127 IplImage *working = finder->working;
128 guint i;
129 gboolean answer = FALSE;
130 cvAbsDiff(green, finder->working, finder->signal);
131 for (i = 0; i < sparrow->in.pixcount; i++){
132 if (finder->signal->imageData[i] > SIGNAL_THRESHOLD){
133 answer = TRUE;
134 break;
137 //memcpy(finder->working, green, sparrow->in.pixcount);
138 char *tmp = working->imageData;
139 working->imageData = green->imageData;
140 green->imageData = tmp;
141 return answer;
145 /* a minature state progression within this one, in case the processing is too
146 much for one frame.*/
147 INVISIBLE sparrow_state
148 mode_find_screen(GstSparrow *sparrow, guint8 *in, guint8 *out){
149 sparrow->countdown--;
150 GST_DEBUG("in find_screen with countdown %d\n", sparrow->countdown);
151 sparrow_find_screen_t *finder = (sparrow_find_screen_t *)sparrow->helper_struct;
152 IplImage *green;
153 IplImage *working = finder->working;
154 IplImage *mask = finder->mask;
155 /* size is 1 byte per pixel, not 4! */
156 size_t size = sparrow->in.pixcount;
157 CvPoint middle, corner;
158 switch (sparrow->countdown){
159 case 6:
160 case 5:
161 case 4:
162 case 3:
163 /*send white and wait for the picture to arrive back. */
164 goto white;
165 case 2:
166 /* time to look and see if the screen is there.
167 Look at the histogram of a single channel. */
168 green = extract_green_channel(sparrow, finder, in);
169 cvCanny(green, mask, 100, 170, 3);
170 MAYBE_DEBUG_IPL(mask);
171 goto black;
172 case 1:
173 /* floodfill where the screen is, removing outlying bright spots*/
174 middle = (CvPoint){sparrow->in.width / 2, sparrow->in.height / 2};
175 memset(working->imageData, 255, size);
176 floodfill_mono_superfast(mask, working, middle);
177 MAYBE_DEBUG_IPL(working);
178 goto black;
179 case 0:
180 /* floodfill the border, removing onscreen dirt.*/
181 corner = (CvPoint){0, 0};
182 memset(mask->imageData, 255, size);
183 floodfill_mono_superfast(working, mask, corner);
184 #if STUPID_DEBUG_TRICK
185 cvErode(mask, mask, NULL, 9);
186 #endif
187 MAYBE_DEBUG_IPL(mask);
188 goto finish;
189 default:
190 GST_DEBUG("checking for signal. sparrow countdown is %d", sparrow->countdown);
191 if (check_for_signal(sparrow, finder, in)){
192 sparrow->countdown = sparrow->lag + WAIT_TIME;
194 goto black;
196 white:
197 memset(out, 255, sparrow->out.size);
198 return SPARROW_STATUS_QUO;
199 black:
200 memset(out, 0, sparrow->out.size);
201 return SPARROW_STATUS_QUO;
202 finish:
203 memset(out, 0, sparrow->out.size);
204 return SPARROW_NEXT_STATE;
207 INVISIBLE void
208 finalise_find_screen(GstSparrow *sparrow){
209 sparrow_find_screen_t *finder = (sparrow_find_screen_t *)sparrow->helper_struct;
210 GST_DEBUG("finalise_find_screen: green %p, working %p, mask %p, im %p finder %p\n",
211 finder->green, finder->working, finder->mask, finder->im, finder);
212 cvReleaseImage(&finder->signal);
213 cvReleaseImage(&finder->green);
214 cvReleaseImage(&finder->working);
215 cvReleaseImageHeader(&finder->mask);
216 cvReleaseImageHeader(&finder->im);
217 free(finder);
220 INVISIBLE void
221 init_find_screen(GstSparrow *sparrow){
222 sparrow_find_screen_t *finder = zalloc_aligned_or_die(sizeof(sparrow_find_screen_t));
223 sparrow->helper_struct = (void *)finder;
224 sparrow->countdown = sparrow->lag + WAIT_TIME;
225 finder->waiting = TRUE;
226 CvSize size = {sparrow->in.width, sparrow->in.height};
227 finder->green = cvCreateImage(size, IPL_DEPTH_8U, 1);
228 finder->working = cvCreateImage(size, IPL_DEPTH_8U, 1);
229 finder->signal = cvCreateImage(size, IPL_DEPTH_8U, 1);
230 finder->im = init_ipl_image(&sparrow->in, PIXSIZE);
231 finder->mask = init_ipl_image(&sparrow->in, 1);
233 finder->mask->imageData = (char *)sparrow->screenmask;
234 GST_DEBUG("init_find_screen: green %p, working %p, mask %p, im %p finder %p\n",
235 finder->green, finder->working, finder->mask, finder->im, finder);