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"
25 /* static functions (via `make cproto`) */
26 static void change_state(GstSparrow
*sparrow
, sparrow_state state
);
27 static __inline__ gint
mask_to_shift(guint32 mask
);
28 static guint32
get_mask(GstStructure
*s
, char *mask_name
);
29 static void init_debug(GstSparrow
*sparrow
);
30 static void rng_init(GstSparrow
*sparrow
, guint32 seed
);
31 static void simple_negation(guint8
*bytes
, guint size
);
32 static void gamma_negation(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
);
33 static void calibrate_new_pattern(GstSparrow
*sparrow
);
34 static __inline__
void init_one_square(GstSparrow
*sparrow
, sparrow_shape_t
*shape
);
35 static void calibrate_init_squares(GstSparrow
*sparrow
);
36 static void add_random_signal(GstSparrow
*sparrow
, guint8
*out
);
37 static void calibrate_init_lines(GstSparrow
*sparrow
);
38 static __inline__
void horizontal_line(GstSparrow
*sparrow
, guint8
*out
, guint32 y
);
39 static __inline__
void vertical_line(GstSparrow
*sparrow
, guint8
*out
, guint32 x
);
40 static __inline__
void rectangle(GstSparrow
*sparrow
, guint8
*out
, sparrow_shape_t
*shape
);
41 static void draw_shapes(GstSparrow
*sparrow
, guint8
*out
);
42 static __inline__
void record_calibration(GstSparrow
*sparrow
, gint32 offset
, guint32 signal
);
43 static __inline__
int find_lag(GstSparrow
*sparrow
);
44 static __inline__
void debug_calibration_histogram(GstSparrow
*sparrow
);
45 static void debug_frame(GstSparrow
*sparrow
, guint8
*data
, guint32 width
, guint32 height
);
46 static void ppm_dump(sparrow_format
*rgb
, guint8
*data
, guint32 width
, guint32 height
, char *name
);
47 static int cycle_pattern(GstSparrow
*sparrow
, int repeat
);
48 static void see_grid(GstSparrow
*sparrow
, guint8
*in
);
49 static void find_grid(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
);
50 static void find_self(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
);
51 static void extract_caps(sparrow_format
*im
, GstCaps
*caps
);
52 static __inline__ IplImage
*init_ipl_image(sparrow_format
*dim
);
57 #include <liboil/liboil.h>
58 #include <liboil/liboilcpu.h>
59 #include <liboil/liboilfunction.h>
64 mask_to_shift(guint32 mask
){
65 /*mask is big-endian, so these numbers are reversed */
76 GST_WARNING("mask not byte aligned: %x\n", mask
);
80 static guint32
get_mask(GstStructure
*s
, char *mask_name
){
82 int res
= gst_structure_get_int(s
, mask_name
, &mask
);
84 GST_WARNING("No mask for '%s' !\n", mask_name
);
92 init_debug(GstSparrow
*sparrow
){
93 if (!sparrow
->debug_frame
){
94 sparrow
->debug_frame
= malloc_aligned_or_die(MAX(sparrow
->in
.size
, sparrow
->out
.size
));
100 /*seed with -1 for automatic seed choice */
101 static void rng_init(GstSparrow
*sparrow
, guint32 seed
){
102 GST_DEBUG("in RNG init\n");
103 if (seed
== (guint32
)-1){
104 /* XXX should really use /dev/urandom */
106 GST_DEBUG("Real seed %u\n", seed
);
111 dsfmt_init_gen_rand(sparrow
->dsfmt
, seed
);
112 dsfmt_gen_rand_all(sparrow
->dsfmt
);
113 GST_DEBUG("RNG seeded with %u\n", seed
);
120 simple_negation(guint8
* bytes
, guint size
){
122 guint32
* data
= (guint32
*)bytes
;
123 //could use sse for superspeed
124 for (i
= 0; i
< size
/ 4; i
++){
130 gamma_negation(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
){
132 //XXX could try oil_tablelookup_u8
133 //for (i = 0; i < size; i++){
134 // out[i] = sparrow_rgb_gamma_full_range_REVERSE[in[i]];
138 static void calibrate_new_pattern(GstSparrow
*sparrow
){
140 sparrow
->calibrate
.index
= CALIBRATE_PATTERN_L
;
141 sparrow
->calibrate
.wait
= 0;
142 for (i
= 0; i
< CALIBRATE_PATTERN_L
; i
+=2){
143 sparrow
->calibrate
.pattern
[i
] = RANDINT(sparrow
, CALIBRATE_OFF_MIN_T
, CALIBRATE_OFF_MAX_T
);
144 sparrow
->calibrate
.pattern
[i
+ 1] = RANDINT(sparrow
, CALIBRATE_ON_MIN_T
, CALIBRATE_ON_MAX_T
);
146 GST_DEBUG("New Pattern: wait %u, index %u\n", sparrow
->calibrate
.wait
, sparrow
->calibrate
.index
);
150 init_one_square(GstSparrow
*sparrow
, sparrow_shape_t
* shape
){
151 shape
->shape
= RECTANGLE
;
152 shape
->w
= CALIBRATE_SELF_SIZE
;
153 shape
->h
= CALIBRATE_SELF_SIZE
;
154 shape
->x
= RANDINT(sparrow
, sparrow
->out
.width
/ 8,
155 sparrow
->out
.width
* 7 / 8 - shape
->w
);
156 shape
->y
= RANDINT(sparrow
, sparrow
->out
.height
/ 8,
157 sparrow
->out
.height
* 7 / 8 - shape
->h
);
160 static void calibrate_init_squares(GstSparrow
*sparrow
){
162 for (i
= 0; i
< MAX_CALIBRATE_SHAPES
; i
++){
163 init_one_square(sparrow
, &(sparrow
->shapes
[i
]));
168 static void add_random_signal(GstSparrow
*sparrow
, guint8
*out
){
170 static sparrow_shape_t shapes
[MAX_CALIBRATE_SHAPES
];
171 static int been_here
= 0;
172 static int countdown
= 0;
175 for (i
= 0; i
< MAX_CALIBRATE_SHAPES
; i
++){
176 init_one_square(sparrow
, &shapes
[i
]);
182 countdown
= on
? RANDINT(sparrow
, CALIBRATE_ON_MIN_T
, CALIBRATE_ON_MAX_T
) :
183 RANDINT(sparrow
, CALIBRATE_ON_MIN_T
, CALIBRATE_ON_MAX_T
);
186 for (i
= 0; i
< MAX_CALIBRATE_SHAPES
; i
++){
187 rectangle(sparrow
, out
, &shapes
[i
]);
194 static void calibrate_init_lines(GstSparrow
*sparrow
){
196 sparrow_shape_t
* shape
= sparrow
->shapes
;
197 for (i
= 0; i
< MAX_CALIBRATE_SHAPES
; i
++){
202 shape
[i
].shape
= NO_SHAPE
;
204 /* shape[0] will be set to vertical or horizontal in due course */
209 /* in a noisy world, try to find the spot you control by stoping and watching
214 horizontal_line(GstSparrow
*sparrow
, guint8
*out
, guint32 y
){
215 guint stride
= sparrow
->out
.width
* PIXSIZE
;
216 guint8
*line
= out
+ y
* stride
;
217 memset(line
, 255, stride
);
221 vertical_line(GstSparrow
*sparrow
, guint8
*out
, guint32 x
){
223 guint32
*p
= (guint32
*)out
;
225 for(y
= 0; y
< (guint
)(sparrow
->out
.height
); y
++){
227 p
+= sparrow
->out
.width
;
232 rectangle(GstSparrow
*sparrow
, guint8
*out
, sparrow_shape_t
*shape
){
234 guint stride
= sparrow
->out
.width
* PIXSIZE
;
235 guint8
*line
= out
+ shape
->y
* stride
+ shape
->x
* PIXSIZE
;
236 for(y
= 0; y
< (guint
)shape
->h
; y
++){
237 memset(line
, 255, shape
->w
* PIXSIZE
);
244 static void draw_shapes(GstSparrow
*sparrow
, guint8
*out
){
246 sparrow_shape_t
*shape
;
247 for (i
= 0; i
< MAX_CALIBRATE_SHAPES
; i
++){
248 shape
= sparrow
->shapes
+ i
;
249 switch (shape
->shape
){
251 goto done
; /* an empty one ends the list */
253 vertical_line(sparrow
, out
, shape
->x
);
255 case HORIZONTAL_LINE
:
256 horizontal_line(sparrow
, out
, shape
->x
);
259 rectangle(sparrow
, out
, shape
);
262 memset(out
, 255, sparrow
->out
.size
);
272 record_calibration(GstSparrow
*sparrow
, gint32 offset
, guint32 signal
){
273 guint16
*t
= sparrow
->lag_table
[offset
].lag
;
274 guint32 r
= sparrow
->lag_record
;
275 if (signal
> CALIBRATE_SIGNAL_THRESHOLD
){
276 sparrow
->lag_table
[offset
].hits
++;
297 colour_coded_pixel(guint32
* pixel
, guint32 weight
, guint32 lag
){
299 guint32 c
= lag_false_colour
[lag
];
312 /*return 1 if a reasonably likely lag has been found */
315 find_lag(GstSparrow
*sparrow
){
318 guint votes
[MAX_CALIBRATION_LAG
] = {0};
319 guint32
*frame
= (guint32
*)sparrow
->debug_frame
;
320 //GST_DEBUG("sparrow->debug is %d\n", sparrow->debug);
322 if (sparrow
->calibrate
.transitions
>= CALIBRATION_START_LAG_SEARCH
){
323 guint expected_hits_min
= sparrow
->calibrate
.transitions
/ 2;
324 guint expected_hits_max
= sparrow
->calibrate
.transitions
+ 1;
327 memset(frame
, 0, sparrow
->in
.size
);
329 for (i
= 0; i
< sparrow
->in
.pixcount
; i
++){
330 lag_times_t
*lt
= &(sparrow
->lag_table
[i
]);
331 if (lt
->hits
> CALIBRATION_MIN_HITS
){
337 for(j
= 0; j
< MAX_CALIBRATION_LAG
; j
++){
338 guint16 v
= lt
->lag
[j
];
345 /* Heuristic for confidence:
346 one point for each of:
347 * the peak is twice average
348 * the peak is 4/3 average
349 * the number of hits is close to the number of transitions
351 There of course is a proper way, but it might be slower.
353 //XXX perhaps adjust centre according to neighbours, using sub-frame values (fixed point)
355 guint32 peak2
= peak
* MAX_CALIBRATION_LAG
; //scale to make sum equivalant to mean
356 confidence
= ((peak2
* 7 >= sum
* 8) +
357 (peak2
* 6 >= sum
* 8) +
358 (peak2
* 5 >= sum
* 8) +
359 (peak2
* 4 >= sum
* 8));
360 if (lt
->hits
> expected_hits_min
&&
361 lt
->hits
< expected_hits_max
){
363 //GST_DEBUG("hits %u, transitions %u\n", lt->hits, sparrow->calibrate.transitions);
365 confidence
*= lt
->hits
;
366 votes
[offset
] += confidence
;
368 colour_coded_pixel(&frame
[i
], confidence
, offset
);
377 for (j
= 0; j
< MAX_CALIBRATION_LAG
; j
++){
379 if (votes
[j
] > max_vote
){
384 if ((max_vote
+ (total
>> 2)) > total
){
385 GST_DEBUG("80%% majority for %u: %u out of %u\n", offset
, max_vote
, total
);
387 sparrow
->lag
= offset
;
390 /*draw a histogram on the screen*/
391 guint8
*row
= sparrow
->debug_frame
;
392 for (j
= 0; j
< MAX_CALIBRATION_LAG
; j
++){
393 row
+= sparrow
->in
.width
* PIXSIZE
;
394 memset(row
, 255, votes
[j
] * sparrow
->in
.width
* (PIXSIZE
) / total
);
399 debug_frame(sparrow
, sparrow
->debug_frame
, sparrow
->in
.width
, sparrow
->in
.height
);
405 debug_calibration_histogram(GstSparrow
*sparrow
){
406 int pixels
= sparrow
->in
.pixcount
;
407 guint32
*frame
= (guint32
*)sparrow
->debug_frame
;
408 memcpy(sparrow
->debug_frame
, sparrow
->in_frame
, sparrow
->in
.size
);
410 static guint32 high_peak
= 0;
411 static guint32 high_pix
= 0;
412 static guint32 high_offset
= 0;
413 for (i
= 0; i
< pixels
; i
++){
416 if (sparrow
->lag_table
[i
].hits
> CALIBRATION_MIN_HITS
){
417 for(j
= 0; j
< MAX_CALIBRATION_LAG
; j
++){
418 if (sparrow
->lag_table
[i
].lag
[j
] > peak
){
419 peak
= sparrow
->lag_table
[i
].lag
[j
];
423 if (peak
> high_peak
){
426 high_offset
= offset
;
431 /*draw a histogram on the screen*/
432 guint8
*row
= sparrow
->debug_frame
;
433 for (j
= 0; j
< MAX_CALIBRATION_LAG
; j
++){
434 row
+= sparrow
->in
.width
* PIXSIZE
;
435 memset(row
, 255, sparrow
->lag_table
[high_pix
].lag
[j
] * sparrow
->in
.width
* (PIXSIZE
/ 2) / high_peak
);
438 /*flicker most peaky pixel */
439 if (sparrow
->frame_count
& 4){
440 frame
[high_pix
] = (guint32
)-1 & (sparrow
->in
.rmask
);
446 debug_frame(sparrow
, sparrow
->debug_frame
, sparrow
->in
.width
, sparrow
->in
.height
);
451 #define PPM_FILENAME_TEMPLATE "/tmp/sparrow_%05d.pgm"
452 #define PPM_FILENAME_LENGTH (sizeof(PPM_FILENAME_TEMPLATE) + 10)
455 debug_frame(GstSparrow
*sparrow
, guint8
*data
, guint32 width
, guint32 height
){
456 #if SPARROW_PPM_DEBUG
457 char name
[PPM_FILENAME_LENGTH
];
458 int res
= snprintf(name
, PPM_FILENAME_LENGTH
, PPM_FILENAME_TEMPLATE
, sparrow
->frame_count
);
460 ppm_dump(&(sparrow
->in
), data
, width
, height
, name
);
468 ppm_dump(sparrow_format
*rgb
, guint8
*data
, guint32 width
, guint32 height
, char *name
)
471 FILE *fh
= fopen(name
, "w");
472 guint32 size
= width
* height
;
473 fprintf(fh
, "P6\n%u %u\n255\n", width
, height
);
474 /* 4 cases: xBGR xRGB BGRx RGBx
475 need to convert to 24bit R G B
476 XX maybe could optimise some cases?
478 guint32
*p
= (guint32
*)data
;
479 for (i
= 0; i
< size
; i
++){
480 putc((*p
>> rgb
->rshift
) & 255, fh
);
481 putc((*p
>> rgb
->gshift
) & 255, fh
);
482 putc((*p
>> rgb
->bshift
) & 255, fh
);
490 abs_diff(GstSparrow
*sparrow
, guint8
*a
, guint8
*b
, guint8
*target
){
491 sparrow
->in_ipl
[0]->imageData
= (char*) a
;
492 sparrow
->in_ipl
[1]->imageData
= (char*) b
;
493 sparrow
->in_ipl
[2]->imageData
= (char*) target
;
494 cvAbsDiff(sparrow
->in_ipl
[0], sparrow
->in_ipl
[1], sparrow
->in_ipl
[2]);
499 /*compare the frame to the new one. regions of change should indicate the
503 calibrate_find_square(GstSparrow
*sparrow
, guint8
*in
){
504 //GST_DEBUG("finding square\n");
506 if(sparrow
->prev_frame
){
507 abs_diff(sparrow
, in
, sparrow
->prev_frame
, sparrow
->work_frame
);
510 //pix_t *changes = (pix_t *)sparrow->work_frame;
511 for (i
= 0; i
< sparrow
->in
.pixcount
; i
++){
512 guint32 signal
= sparrow
->work_frame
[i
* PIXSIZE
+ 2];//possibly R, G, or B, but never A
513 record_calibration(sparrow
, i
, signal
);
516 res
= find_lag(sparrow
);
518 GST_DEBUG("lag is set at %u! after %u cycles\n", sparrow
->lag
, sparrow
->frame_count
);
524 static int cycle_pattern(GstSparrow
*sparrow
, int repeat
){
525 if (sparrow
->calibrate
.wait
== 0){
526 if(sparrow
->calibrate
.index
== 0){
527 //pattern has run out
529 sparrow
->calibrate
.index
= CALIBRATE_PATTERN_L
;
532 calibrate_new_pattern(sparrow
);
535 sparrow
->calibrate
.index
--;
536 sparrow
->calibrate
.wait
= sparrow
->calibrate
.pattern
[sparrow
->calibrate
.index
];
537 //GST_DEBUG("cycle_wait %u, cycle_index %u\n", sparrow->calibrate.wait, sparrow->calibrate.index);
538 sparrow
->lag_record
= (sparrow
->lag_record
<< 1) | 1;
539 sparrow
->calibrate
.transitions
++;
542 sparrow
->lag_record
= (sparrow
->lag_record
<< 1);
544 sparrow
->lag_record
&= ((1 << MAX_CALIBRATION_LAG
) - 1);
545 //XXX record the pattern in sparrow->lag_record
546 sparrow
->calibrate
.wait
--;
547 return sparrow
->calibrate
.index
& 1;
551 see_grid(GstSparrow
*sparrow
, guint8
*in
){
555 find_grid(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
){
556 see_grid(sparrow
, in
);
557 int on
= cycle_pattern(sparrow
, TRUE
);
558 memset(out
, 0, sparrow
->out
.size
);
560 draw_shapes(sparrow
, out
);
566 find_self(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
){
567 if(calibrate_find_square(sparrow
, in
)){
568 change_state(sparrow
, SPARROW_WAIT_FOR_GRID
);
571 int on
= cycle_pattern(sparrow
, TRUE
);
572 memset(out
, 0, sparrow
->out
.size
);
574 draw_shapes(sparrow
, out
);
577 add_random_signal(sparrow
, out
);
581 /* wait for the other projector to stop changing: sufficient to look for no
582 significant changes for as long as the longest pattern interval */
585 wait_for_blank(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
){
587 abs_diff(sparrow
, in
, sparrow
->prev_frame
, sparrow
->work_frame
);
588 for (i
= 0; i
< sparrow
->in
.pixcount
; i
++){
589 guint32 signal
= sparrow
->work_frame
[i
* PIXSIZE
+ 2]; //possibly R, G, or B, but never A
590 if (signal
> CALIBRATE_SIGNAL_THRESHOLD
){
591 sparrow
->countdown
= WAIT_COUNTDOWN
;
595 memset(out
, 0, sparrow
->out
.size
);
596 sparrow
->countdown
--;
597 return (sparrow
->countdown
== 0);
602 extract_caps(sparrow_format
*im
, GstCaps
*caps
)
604 GstStructure
*s
= gst_caps_get_structure (caps
, 0);
605 gst_structure_get_int(s
, "width", &(im
->width
));
606 gst_structure_get_int(s
, "height", &(im
->height
));
607 im
->rmask
= get_mask(s
, "red_mask");
608 im
->rshift
= mask_to_shift(im
->rmask
);
609 im
->gmask
= get_mask(s
, "green_mask");
610 im
->gshift
= mask_to_shift(im
->gmask
);
611 im
->bmask
= get_mask(s
, "blue_mask");
612 im
->bshift
= mask_to_shift(im
->bmask
);
614 im
->pixcount
= im
->width
* im
->height
;
615 im
->size
= im
->pixcount
* PIXSIZE
;
617 GST_DEBUG("\ncaps:\n%" GST_PTR_FORMAT
, caps
);
618 GST_DEBUG("shifts: r %u g %u b %u\n", im
->rshift
, im
->gshift
, im
->bshift
);
619 GST_DEBUG("dimensions: w %u h %u pix %u size %u\n", im
->width
, im
->height
,
620 im
->pixcount
, im
->size
);
623 static inline IplImage
*
624 init_ipl_image(sparrow_format
*dim
){
625 CvSize size
= {dim
->width
, dim
->height
};
626 IplImage
* im
= cvCreateImageHeader(size
, IPL_DEPTH_8U
, PIXSIZE
);
627 return cvInitImageHeader(im
, size
, IPL_DEPTH_8U
, PIXSIZE
, 0, 8);
631 calibrate_init_grid(GstSparrow
*sparrow
){}
634 change_state(GstSparrow
*sparrow
, sparrow_state state
)
637 case SPARROW_FIND_SELF
:
638 calibrate_init_squares(sparrow
);
640 case SPARROW_WAIT_FOR_GRID
:
642 case SPARROW_FIND_GRID
:
643 calibrate_init_grid(sparrow
);
646 case SPARROW_FIND_EDGES
:
650 sparrow
->state
= state
;
655 /*Functions below here are NOT static */
658 sparrow_rotate_history(GstSparrow
*sparrow
, GstBuffer
*inbuf
){
659 if (sparrow
->in_buffer
){
660 gst_buffer_unref(sparrow
->prev_buffer
);
661 sparrow
->prev_buffer
= sparrow
->in_buffer
;
662 sparrow
->prev_frame
= sparrow
->in_frame
;
664 gst_buffer_ref(inbuf
);
665 sparrow
->in_buffer
= inbuf
;
667 sparrow
->in_frame
= GST_BUFFER_DATA(inbuf
);
670 /* called by gst_sparrow_init() */
672 sparrow_pre_init(GstSparrow
*sparrow
){
675 /* called by gst_sparrow_set_caps() */
677 sparrow_init(GstSparrow
*sparrow
, GstCaps
*incaps
, GstCaps
*outcaps
){
678 extract_caps(&(sparrow
->in
), incaps
);
679 extract_caps(&(sparrow
->out
), outcaps
);
680 sparrow_format
*in
= &(sparrow
->in
);
682 GST_DEBUG("allocating %u * %u for lag_table\n", in
->pixcount
, sizeof(lag_times_t
));
683 sparrow
->lag_table
= zalloc_aligned_or_die(in
->pixcount
* sizeof(lag_times_t
));
684 sparrow
->work_frame
= zalloc_aligned_or_die(in
->size
);
685 sparrow
->dsfmt
= zalloc_aligned_or_die(sizeof(dsfmt_t
));
687 sparrow
->prev_buffer
= gst_buffer_new_and_alloc(in
->size
);
688 sparrow
->prev_frame
= GST_BUFFER_DATA(sparrow
->prev_buffer
);
689 memset(sparrow
->prev_frame
, 0, in
->size
);
691 /*initialise IPL structs for openCV */
692 for (int i
= 0; i
< 3; i
++){
693 sparrow
->in_ipl
[i
] = init_ipl_image(&(sparrow
->in
));
696 rng_init(sparrow
, sparrow
->rng_seed
);
702 calibrate_new_pattern(sparrow
);
704 change_state(sparrow
, SPARROW_FIND_SELF
);
708 /*called by gst_sparrow_transform_ip */
710 sparrow_transform(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
)
712 switch(sparrow
->state
){
713 case SPARROW_FIND_SELF
:
714 find_self(sparrow
, in
, out
);
716 case SPARROW_WAIT_FOR_GRID
:
717 if (wait_for_blank(sparrow
, in
, out
)){
718 change_state(sparrow
, SPARROW_FIND_GRID
);
721 case SPARROW_FIND_GRID
:
722 find_grid(sparrow
, in
, out
);
725 gamma_negation(sparrow
, in
, out
);
727 sparrow
->frame_count
++;
732 sparrow_finalise(GstSparrow
*sparrow
)
737 //cvReleaseImageHeader(IplImage** image)