gitignore ignorable gtksparrow executable
[sparrow.git] / floodfill.c
bloba767039ac1830eb2590465a43c92a716726e9cec
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 GST_DEBUG("gshift is %d, green is %p, data is %p, im data is %p",
114 gshift, green, green->imageData, im->imageData);
115 cvSplit(im,
116 (gshift == 24) ? green : NULL,
117 (gshift == 16) ? green : NULL,
118 (gshift == 8) ? green : NULL,
119 (gshift == 0) ? green : NULL);
120 GST_DEBUG("returning green %p, data %p",
121 green, green->imageData);
122 return green;
126 #define SIGNAL_THRESHOLD 100
127 /*see whether there seems to be activity: */
128 gboolean INVISIBLE
129 check_for_signal(GstSparrow *sparrow, sparrow_find_screen_t *finder, guint8 *in){
130 IplImage *green = extract_green_channel(sparrow, finder, in);
131 IplImage *working = finder->working;
132 guint i;
133 gboolean answer = FALSE;
134 cvAbsDiff(green, finder->working, finder->signal);
135 for (i = 0; i < sparrow->in.pixcount; i++){
136 if (finder->signal->imageData[i] > SIGNAL_THRESHOLD){
137 answer = TRUE;
138 break;
141 memcpy(working->imageData, green->imageData, sparrow->in.pixcount);
142 //char *tmp = working->imageData;
143 //working->imageData = green->imageData;
144 //green->imageData = tmp;
145 GST_DEBUG("answering %d", answer);
146 return answer;
150 /* a minature state progression within this one, in case the processing is too
151 much for one frame.*/
152 INVISIBLE sparrow_state
153 mode_find_screen(GstSparrow *sparrow, GstBuffer *inbuf, GstBuffer *outbuf){
154 guint8 *in = GST_BUFFER_DATA(inbuf);
155 guint8 *out = GST_BUFFER_DATA(outbuf);
156 sparrow->countdown--;
157 GST_DEBUG("in find_screen with countdown %d\n", sparrow->countdown);
158 sparrow_find_screen_t *finder = (sparrow_find_screen_t *)sparrow->helper_struct;
159 IplImage *green;
160 IplImage *working = finder->working;
161 IplImage *mask = finder->mask;
162 /* size is 1 byte per pixel, not 4! */
163 size_t size = sparrow->in.pixcount;
164 CvPoint middle, corner;
165 switch (sparrow->countdown){
166 case 6:
167 case 5:
168 case 4:
169 case 3:
170 /*send white and wait for the picture to arrive back. */
171 goto white;
172 case 2:
173 /* time to look and see if the screen is there.
174 Look at the histogram of a single channel. */
175 green = extract_green_channel(sparrow, finder, in);
176 cvCanny(green, mask, 100, 170, 3);
177 cvDilate(mask, mask, NULL, 1);
178 MAYBE_DEBUG_IPL(mask);
179 goto black;
180 case 1:
181 /* floodfill where the screen is, removing outlying bright spots*/
182 middle = (CvPoint){sparrow->in.width / 2, sparrow->in.height / 2};
183 memset(working->imageData, 255, size);
184 floodfill_mono_superfast(mask, working, middle);
185 MAYBE_DEBUG_IPL(working);
186 goto black;
187 case 0:
188 /* floodfill the border, removing onscreen dirt.*/
189 corner = (CvPoint){0, 0};
190 memset(mask->imageData, 255, size);
191 floodfill_mono_superfast(working, mask, corner);
192 #if STUPID_DEBUG_TRICK
193 cvErode(mask, mask, NULL, 9);
194 #endif
195 cvDilate(mask, mask, NULL, 1);
196 MAYBE_DEBUG_IPL(mask);
197 goto finish;
198 default:
199 GST_DEBUG("checking for signal. sparrow countdown is %d", sparrow->countdown);
200 if (check_for_signal(sparrow, finder, in)){
201 sparrow->countdown = sparrow->lag + WAIT_TIME;
203 goto black;
205 white:
206 memset(out, 255, sparrow->out.size);
207 return SPARROW_STATUS_QUO;
208 black:
209 memset(out, 0, sparrow->out.size);
210 return SPARROW_STATUS_QUO;
211 finish:
212 memset(out, 0, sparrow->out.size);
213 return SPARROW_NEXT_STATE;
216 INVISIBLE void
217 finalise_find_screen(GstSparrow *sparrow){
218 sparrow_find_screen_t *finder = (sparrow_find_screen_t *)sparrow->helper_struct;
219 GST_DEBUG("finalise_find_screen: green %p, working %p, mask %p, im %p finder %p\n",
220 finder->green, finder->working, finder->mask, finder->im, finder);
221 cvReleaseImage(&finder->signal);
222 cvReleaseImage(&finder->green);
223 cvReleaseImage(&finder->working);
224 cvReleaseImageHeader(&finder->mask);
225 cvReleaseImageHeader(&finder->im);
226 free(finder);
229 INVISIBLE void
230 init_find_screen(GstSparrow *sparrow){
231 sparrow_find_screen_t *finder = zalloc_aligned_or_die(sizeof(sparrow_find_screen_t));
232 sparrow->helper_struct = (void *)finder;
233 sparrow->countdown = sparrow->lag + WAIT_TIME;
234 finder->waiting = TRUE;
235 CvSize size = {sparrow->in.width, sparrow->in.height};
236 finder->green = cvCreateImage(size, IPL_DEPTH_8U, 1);
237 finder->working = cvCreateImage(size, IPL_DEPTH_8U, 1);
238 finder->signal = cvCreateImage(size, IPL_DEPTH_8U, 1);
239 finder->im = init_ipl_image(&sparrow->in, PIXSIZE);
240 finder->mask = init_ipl_image(&sparrow->in, 1);
242 finder->mask->imageData = (char *)sparrow->screenmask;
243 GST_DEBUG("init_find_screen: green %p, working %p, mask %p, im %p finder %p\n",
244 finder->green, finder->working, finder->mask, finder->im, finder);