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.
20 #include "gstsparrow.h"
26 typedef struct sparrow_find_screen_s
{
31 } sparrow_find_screen_t
;
34 /* Floodfill for find screen */
36 expand_one_mono(int x
, int y
, int c
,
37 CvPoint
*nexts
, int *n_nexts
, guint8
*im
, guint8
*mask
, int w
, int h
){
38 guint8 p
= im
[y
* w
+ x
];
39 guint8
*m
= &mask
[y
* w
+ x
];
42 nexts
[*n_nexts
].x
= x
;
43 nexts
[*n_nexts
].y
= y
;
49 im: the image to be analysed
50 mim: the mask image to be written
51 start: a point of the right colour.
55 floodfill_mono_superfast(IplImage
*im
, IplImage
*mim
, CvPoint start
)
57 guint8
* data
= (guint8
*)im
->imageData
;
58 guint8
* mdata
= (guint8
*)mim
->imageData
;
66 //malloc 2 lists of points. These *could* be as large as the image (but never should be)
67 void * mem
= malloc_or_die(w
* h
* 2 * sizeof(CvPoint
));
69 nexts
= starts
+ w
* h
;
76 for (i
= 0; i
< n_starts
; i
++){
79 int c
= data
[y
* w
+ x
];
81 expand_one_mono(x
- 1, y
, c
, nexts
, &n_nexts
, data
, mdata
, w
, h
);
84 expand_one_mono(x
+ 1, y
, c
, nexts
, &n_nexts
, data
, mdata
, w
, h
);
87 expand_one_mono(x
, y
- 1, c
, nexts
, &n_nexts
, data
, mdata
, w
, h
);
90 expand_one_mono(x
, y
+ 1, c
, nexts
, &n_nexts
, data
, mdata
, w
, h
);
93 CvPoint
*tmp
= starts
;
107 /* find a suitable threshold level by looking at the histogram of a monochrome
110 find_edges_threshold(IplImage
*im
)
114 CvSize small_size
= {w
/ 8, h
/ 8};
115 IplImage
*small
= cvCreateImage(small_size
, IPL_DEPTH_8U
, 1); /*for quicker histogram (stupid, perhaps?)*/
116 cvResize(im
, small
, CV_INTER_NN
);
117 int hist_size
[] = {255};
118 float range
[] = {0, 255};
119 float *ranges
[] = {range
};
120 CvHistogram
* hist
= cvCreateHist(1, hist_size
, CV_HIST_ARRAY
, ranges
, 1);
121 cvCalcHist(&small
, hist
, 0, NULL
);
123 int pixels
= small
->width
* small
->height
;
124 int min_black
= pixels
/ 16;
125 int max_black
= pixels
* 3 / 4;
126 int totals
[256] = {0};
128 int best_d
= pixels
+ 1;
131 /* look for a low region in the histogram between the two peaks.
132 (big assumption: two peaks, with most in whiter peak) */
134 for (int i
= 0; i
< 255; i
++){
135 int v
= (int)cvQueryHistValue_1D(hist
, i
);
138 if (total
>= min_black
){
140 int diff
= total
- totals
[i
- 5];
145 if (total
>= max_black
){
151 GST_DEBUG("found best threshold %d -- %d pixel change at %d/%d pixels\n",
152 best_t
, best_d
, totals
[best_t
], pixels
);
153 //MAYBE_DEBUG_IPL(small);
154 cvReleaseImage(&small
);
155 cvReleaseHist(&hist
);
161 /* a minature state progression within this one, in case the processing is too
162 much for one frame.*/
163 INVISIBLE sparrow_state
164 mode_find_screen(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
){
165 sparrow
->countdown
--;
166 GST_DEBUG("in find_screen with countdown %d\n", sparrow
->countdown
);
167 sparrow_find_screen_t
*finder
= (sparrow_find_screen_t
*)sparrow
->helper_struct
;
168 IplImage
*im
= finder
->im
;
169 IplImage
*green
= finder
->green
;
170 IplImage
*working
= finder
->working
;
171 IplImage
*mask
= finder
->mask
;
172 /* size is 1 byte per pixel, not 4! */
173 size_t size
= sparrow
->in
.pixcount
;
174 CvPoint middle
, corner
;
175 switch (sparrow
->countdown
){
177 /* time to look and see if the screen is there.
178 Look at the histogram of a single channel. */
179 im
->imageData
= (char*)in
;
180 guint32 gshift
= sparrow
->in
.gshift
;
182 (gshift
== 24) ? green
: NULL
,
183 (gshift
== 16) ? green
: NULL
,
184 (gshift
== 8) ? green
: NULL
,
185 (gshift
== 0) ? green
: NULL
);
186 int best_t
= find_edges_threshold(green
);
187 /*XXX if best_t is wrong, add to sparrow->countdown: probably the light is
188 not really on. But what counts as wrong? */
189 MAYBE_DEBUG_IPL(green
);
190 cvCmpS(green
, best_t
, mask
, CV_CMP_GT
);
193 /* floodfill where the screen is, removing outlying bright spots*/
194 middle
= (CvPoint
){sparrow
->in
.width
/ 2, sparrow
->in
.height
/ 2};
195 memset(working
->imageData
, 255, size
);
196 floodfill_mono_superfast(mask
, working
, middle
);
197 MAYBE_DEBUG_IPL(working
);
200 /* floodfill the border, removing onscreen dirt.*/
201 corner
= (CvPoint
){0, 0};
202 memset(mask
->imageData
, 255, size
);
203 floodfill_mono_superfast(working
, mask
, corner
);
204 MAYBE_DEBUG_IPL(mask
);
205 sparrow
->screenmask
= (guint8
*)mask
->imageData
;
206 cvReleaseImage(&(finder
->green
));
207 cvReleaseImage(&(finder
->working
));
210 /*send white and wait for the picture to arrive back. */
211 memset(out
, 255, sparrow
->out
.size
);
212 return SPARROW_STATUS_QUO
;
215 memset(out
, 0, sparrow
->out
.size
);
216 return SPARROW_STATUS_QUO
;
218 memset(out
, 0, sparrow
->out
.size
);
219 finalise_find_screen(sparrow
);
220 return SPARROW_NEXT_STATE
;
224 finalise_find_screen(GstSparrow
*sparrow
){
225 sparrow_find_screen_t
*finder
= (sparrow_find_screen_t
*)sparrow
->helper_struct
;
226 cvReleaseImage(&finder
->green
);
227 cvReleaseImage(&finder
->working
);
228 cvReleaseImageHeader(&finder
->mask
);
229 cvReleaseImageHeader(&finder
->im
);
234 init_find_screen(GstSparrow
*sparrow
){
235 sparrow_find_screen_t
*finder
= zalloc_aligned_or_die(sizeof(sparrow_find_screen_t
));
236 sparrow
->helper_struct
= (void *)finder
;
237 sparrow
->countdown
= sparrow
->lag
+ 5;
238 CvSize size
= {sparrow
->in
.width
, sparrow
->in
.height
};
239 finder
->green
= cvCreateImage(size
, IPL_DEPTH_8U
, 1);
240 finder
->working
= cvCreateImage(size
, IPL_DEPTH_8U
, 1);
242 finder
->im
= cvCreateImageHeader(size
, IPL_DEPTH_8U
, PIXSIZE
);
243 cvInitImageHeader(finder
->im
, size
, IPL_DEPTH_8U
, PIXSIZE
, 0, 8);
245 finder
->mask
= cvCreateImageHeader(size
, IPL_DEPTH_8U
, 1);
246 cvInitImageHeader(finder
->mask
, size
, IPL_DEPTH_8U
, 1, 0, 8);
247 finder
->mask
->imageData
= (char *)sparrow
->screenmask
;