www.pudn.com > ReadingPeopleTracker-1.28.rar > RegionSet.cc


/*
 * RegionSet.cc
 * 
 * functions for RegionSet class
 * (declared in Region.h)
 *
 */

#include "RegionSet.h"

#include 

#ifndef NO_DISPLAY    
#ifdef USE_GL
#include 
#else
#include 
#include 
#endif

#ifdef DEBUG
#include "os_specific_things.h"   // for sleep()
#endif
#endif   // #ifndef NO_DISPLAY

#include "ProfileSet.h"
#include "Image.h"
#include "Grey8Image.h"
#include "tracker_defines_types_and_helpers.h"

namespace ReadingPeopleTracker
{

// definition and initialisation of static member variables
const unsigned int RegionSet::DEFAULT_MIN_REGION_SIZE = 20;
const unsigned int RegionSet::DEFAULT_MAX_REGION_SIZE = 100;

#define DEFAULT_BORDER_WIDTH 8

void RegionSet::grab_regions_and_subimages(const Grey8Image *img,
					   unsigned int min_size,
					   unsigned int max_size,
					   bool keep_edge_regions)
{
    unsigned int border_width;
    
    if (keep_edge_regions)
	border_width = 0;
    else
	border_width = DEFAULT_BORDER_WIDTH;
    
    Image *scene = new Grey8Image(img->get_width(), img->get_height());
    scene->clear(CLEAR_MARK);
    
    Image *temp_image = NULL;
    unsigned char *sptr, *eptr, *tptr;
    unsigned char *ptr = img->get_data();
    unsigned char *scene_data = scene->get_data();
    int offset;
    unsigned int width = scene->get_width();
    unsigned int height = scene->get_height();
    int count, x, y;
    int os1 = width+1;
    int os2 = width;
    int os3 = width-1;
    int tnx = width-border_width - 1;
    int tny = height-border_width - 1;
    bool on_edge = false;
    for (y = border_width; y < tny; y++)
    {
	tptr = img->get_pixel(border_width,y);
	eptr = img->get_pixel(tnx,y);
	for ( ; tptr < eptr; tptr++)
	{
	    if (*tptr == MARK)
	    {
		stack->push(tptr);
		*tptr = CLEAR_MARK;
		int xhi = 1;
		int yhi = 1;
		int xlo = tnx;
		int ylo = tny;
		count = 0;
		on_edge = false;
		while (! stack->is_empty())
		{
		    stack->pop(sptr);
		    img->get_pixel_coords(sptr, (unsigned int &) x, (unsigned int &) y);
		    offset = sptr - ptr;
		    *(scene_data + offset) = MARK;
		    count++;
		    
		    if (x < xlo) xlo = x;  // no else here!
		    if (x > xhi) xhi = x;
		    if (y < ylo) ylo = y;  // no else here!
		    if (y > yhi) yhi = y;
		    
		    /* add marked neighbours to stack */
		    if (y > border_width)
		    {
			if (x > border_width)
			    stack->test(sptr-os1);
			stack->test(sptr-os2);
			if (x < tnx)
			    stack->test(sptr-os3);
		    } 
		    else on_edge = true;
		    
		    if (x > border_width)
			stack->test(sptr-1);
		    else
			on_edge = true;
		    
		    if (x < tnx)
			stack->test(sptr+1);		    
		    else
			on_edge = true;
		    
		    if (y < tny)
		    {
			if (x > border_width)
			    stack->test(sptr+os3);
			stack->test(sptr+os2);
			if (x < tnx)
			    stack->test(sptr+os1);
		    }
		    else
			on_edge = true;
		    
		}
		
		if (keep_edge_regions)
		    on_edge = false;
		
		xlo -= 2; xhi += 2;
		ylo -= 2; yhi += 2;
		xhi = ((((xhi - xlo) >> 3)+1) << 3) + xlo - 1;
		yhi = ((((yhi - ylo) >> 3)+1) << 3) + ylo - 1;
		
		if (xlo < 0)
		    xlo = 0;
		if (xhi >=  width)
		    xhi = width - 1;
		if (ylo < 0)
		    ylo = 0;
		if (yhi >= height)
		    yhi = height -1;
		
		temp_image = scene->extract_subimage(xlo,xhi,ylo,yhi);
		
		if (!on_edge && (count <= max_size) && (count >= min_size))
		    add(new Region(xlo,xhi,ylo,yhi,temp_image));
		else
		    if (temp_image != NULL) 
			delete temp_image;  // free unused memory
	    }
	}
    }
    delete scene;
}


void RegionSet::grab_regions(const Grey8Image *img,
			     unsigned int min_size,
			     unsigned int max_size,
			     bool keep_edge_regions)
{
    int border_width;
    
    if (keep_edge_regions)
	border_width = 0;
    else
	border_width = DEFAULT_BORDER_WIDTH;
    
    unsigned char *sptr, *eptr, *tptr;
    unsigned char *ptr = img->get_data();
    int offset;
    int width = img->get_width();
    int height = img->get_height();
    int count, x, y;
    int os1 = width+1;
    int os2 = width;
    int os3 = width-1;
    int tnx = width-border_width - 1;
    int tny = height-border_width - 1;
    for (y = border_width; y < tny; y++)
    {
	tptr = img->get_pixel(border_width,y);
	eptr = img->get_pixel(tnx,y);
	for (;tptr < eptr; tptr++)
	{
	    if (*tptr == MARK)
	    {
		stack->push(tptr);
		*tptr = CLEAR_MARK;
		int xhi = 1;
		int yhi = 1;
		int xlo = tnx;
		int ylo = tny;
		count = 0;
		while (! stack->is_empty())
		{
		    stack->pop(sptr);
		    img->get_pixel_coords(sptr, (unsigned int &) x, (unsigned int &) y);
		    offset = sptr - ptr;
		    count++;
		    
		    if (x < xlo) xlo = x;  // no else here!
		    if (x > xhi) xhi = x;
		    if (y < ylo) ylo = y;  // no else here!
		    if (y > yhi) yhi = y;
		    
		    /* add marked neighbours to stack */
		    if (y > border_width)
		    {
			if (x > border_width)
			    stack->test(sptr-os1);
			stack->test(sptr-os2);
			if (x < tnx)
			    stack->test(sptr-os3);
		    } 
		    if (x > border_width)
			stack->test(sptr-1);
		    if (x < tnx)
			stack->test(sptr+1);
		    if (y < tny)
		    {
			if (x > border_width)
			    stack->test(sptr+os3);
			stack->test(sptr+os2);
			if (x < tnx)
			    stack->test(sptr+os1);
		    }
		}
		
		//if (!((xlo < (0.75 * width)) && 
		//(xhi > (0.25 * width)) &&
		//(ylo < (0.75 *height)) &&
		//(yhi > (0.25 * height))) &&
		
		if ((xlo > border_width) &&
		    (xhi < (width - border_width)) &&
		    (ylo > border_width) &&
		    (yhi < (height - border_width)) &&
		    ((count <= max_size) && (count >= min_size)))
		    add(new Region(xlo,xhi,ylo,yhi,NULL));
	    }
	}
    }
}


void RegionSet::draw_regions()
{
#ifndef NO_DISPLAY
    for (ListNode *curr = first; curr != NULL; curr = curr->next)
	curr->dat->draw_points();
#endif   // #ifndef NO_DISPLAY
}


// draw rectangles around all regions
void RegionSet::draw_boxes(frame_id_t min_draw_age)
{
#ifndef NO_DISPLAY
    for (ListNode *curr = first; curr != NULL; curr = curr->next)
    {
	if (curr->dat->frame_first_detected + min_draw_age <= curr->dat->frame_last_detected)
	    curr->dat->draw_box();
    }
    
#endif   // #ifndef NO_DISPLAY
}

// draw rectangles around all regions, into given Image
void RegionSet::draw_boxes_in_image(Image *canvas, frame_id_t min_draw_age)
{
    for (ListNode *curr = first; curr != NULL; curr = curr->next)
    {
	// if max_age is not 0, only draw visible regions of age >= min_age
	if ((curr->dat->frame_first_detected) + min_draw_age <= (curr->dat->frame_last_detected))
	{	    
	    assert(curr->dat->is_visible);  // otherwise the above should be false
	    curr->dat->draw_box_in_image(canvas);
 	}
	
    }
}

void RegionSet::clear_window()
{
#ifndef NO_DISPLAY
    //winset(gl_win);
    color(BLACK);
    clear();
#endif   // #ifndef NO_DISPLAY
}

void RegionSet::trace_regions()
{
    for (ListNode *curr = first; curr != NULL; curr = curr->next)
	curr->dat->trace();
}

void RegionSet::smooth(realno sd, int window_size)
{
    for (ListNode *curr = first; curr != NULL; curr = curr->next)
	curr->dat->smooth_boundary(sd, window_size);
}

ProfileSet *RegionSet::to_profiles()
{
    ProfileSet *profiles = new ProfileSet;
    Profile *tmp;
    for (ListNode *curr = first; curr != NULL; curr = curr->next)
    {
	tmp = curr->dat->to_profile(); // which allocates memory
	if (tmp != NULL)
	    profiles->add(tmp);
    }
    return profiles;
}      

// distance between 2 blobs (regions)
realno RegionSet::bbdistance(Region *r, Region *t)
{
    realno d1;
    realno d2;
    realno dx;
    realno dy;

    d1 = r->xlo - t->xhi;
    d2 = t->xlo - r->xhi;
    
    if (d1 > 0)       // r is right of t
	dx = d1;
    else
	if (d2 > 0)   // t is right of r
	    dx = d2;
	else
	    dx = 0;   // regions are not apart in x direction
    
    d1 = r->ylo - t->yhi;
    d2 = t->ylo - r->yhi;
    
    if (d1 > 0)       // r is over t (thinking bottom to top)
	dy = d1;
    else
	if (d2 > 0)   // t is over r
	    dy = d2; 
	else
	    dy = 0;   // regions are not apart in y direction
	        
    d1 = MAX(r->width, r->height);
    d2 = MAX(t->width, t->height);
    
    // divided by 16 in order for the regions to have a greater tendency to 
    // merge vertically rather than horizontally.
    register realno dd = (dx + dy/16) / (d1 + d2 + 1);

    return dd;
}

void RegionSet::merge_regions(realno dist_threshold)
{
    bool flag=true;
    //dist_threshold = dist_threshold*dist_threshold;    /* bbdistance returns square of distance */
    ListNode *reg_r, *reg_t, *reg_t2;
    
    while (flag == true) 
    {
	flag = false;
	for (reg_r=first; reg_r != NULL; reg_r = (reg_r->next))
	{
	    for (reg_t = (reg_r->next); reg_t != NULL; reg_t = (reg_t->next))
	    {
		if (bbdistance(reg_r->dat, reg_t->dat) < dist_threshold)
		{
		    reg_r->dat->merge(reg_t->dat);
		    flag = true;
		    reg_t2 = (reg_t->prev);
		    destroy(reg_t);
		    reg_t = reg_t2;
		}
	    }
	}
    }
}

void RegionSet::filter(realno min_region_size = 0.0)
{
    for (ListNode *regn = first; regn != NULL; )
    {
	if (abs((regn->dat->xhi - regn->dat->xlo) * (regn->dat->yhi - regn->dat->ylo))
	    < min_region_size) 
	{
	    ListNode *rgn_tmp = regn;
	    regn = regn->next;
	    destroy(rgn_tmp);
	}
	else
	    regn = regn->next;
	
    }
}

} // namespace ReadingPeopleTracker