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


/*
 *  Grey8Image.cc
 *  Image class for 8-bit greylevel images
 *
 *  author : A M Baumberg
 */

#include "Grey8Image.h"

#include 
#include 
#include 
#include 
#include 

#include "Kernel.h"
#include "RGB32Image.h"
#include "Point2.h"
#include "text_output.h"

#include "tracker_defines_types_and_helpers.h" 

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

namespace ReadingPeopleTracker
{

// definition and initialisation of static member variables
const int Grey8Image::BOX_SIZE = 8;

// definition and initialisation of static member variables

#ifndef NO_DISPLAY
#ifndef USE_GL
// definition and initialisation of X11 interface specific static member variables
Grey8Image::Colormap cmap = 0;
int Grey8Image::no_using_cmap = 0;
unsigned char Grey8Image::pixel;
//unsigned long plane_masks[8];
//unsigned int no_planes = 8;
unsigned long Grey8Image::reverse_cmap[256];
int Grey8Image::no_grey_cells;
#endif   // ifndef USE_GL
#endif   // ifndef NO_DISPLAY

Image *Grey8Image::copy(Image *res) const
{
    if (res == NULL)
	res = (Image *) new Grey8Image(width, height, frame_id, frame_time_in_ms);
    else
    {
	// check destination image format and dimensions
	assert (res->get_image_type() == GREY8);
	assert (res->get_width() == width);
	assert (res->get_height() == height);
	
	// use same frame id and time since it is the same image
	res->set_frame_id(frame_id);
	res->set_frame_time_in_ms(frame_time_in_ms);
    }
    
    res->set_draw_colour(Grey8_draw_colour);
    res->set_timestamp(×tamp);
    
    // copy over actual image data...
    void *src = data;
    void *dest = res->get_data();
    size_t n = width * height;
    
    memcpy(dest, src, n);
    
    return res;
}

Image *Grey8Image::resample(unsigned int xstep, unsigned int ystep, Image *resampled)
{
    int new_width = ((width / xstep) / 4) * 4;
    int new_height = height / ystep;

    if ((height % ystep) != 0)
	new_height++;

    if (resampled == NULL)
	resampled = new Grey8Image(new_width, new_height, frame_id, frame_time_in_ms);

    unsigned char *idat;
    unsigned char *odat;
    unsigned int outy = 0;
    for (unsigned int y = 0; y < height; y += ystep)
    {
	idat = get_pixel(0,y);
	odat = resampled->get_pixel(0, outy);
	for (unsigned int x = 0; x < new_width; x ++)
	{
	    *odat = *idat;
	    odat++;
	    idat = idat + xstep;
	}
	outy++;
    }
    return resampled;
}


void Grey8Image::clear_border()
{
    int w1 = width-1;
    int h1 = height-1;
    for (int y = 0; y < height; y++)
    {
	*get_pixel(0,y) = CLEAR_MARK;
	*get_pixel(w1,y) = CLEAR_MARK;
    }
    for (int x = 0; x < width; x++)
    {
	*get_pixel(x,0) = CLEAR_MARK;
	*get_pixel(x,h1) = CLEAR_MARK;
    }
}

Image *Grey8Image::convolve(Kernel k, Image *convolved)
{
    unsigned char *upnt, *pnt, *dpnt;
    unsigned char *out;
    int temp_total;
    int k11 = k.coeff[0][0], k12 = k.coeff[0][1], k13 = k.coeff[0][2]; 
    int k21 = k.coeff[1][0], k22 = k.coeff[1][1], k23 = k.coeff[1][2]; 
    int k31 = k.coeff[2][0], k32 = k.coeff[2][1], k33 = k.coeff[2][2];
    int ksum = abs(k11)+abs(k12)+abs(k13)
	+abs(k21)+abs(k22)+abs(k23)
	+abs(k31)+abs(k32)+abs(k33);
    
    if (convolved == NULL)
	convolved = new Grey8Image(width, height, frame_id, frame_time_in_ms);

    convolved->clear_border();

    for (int y = 1; y < (height-1); y++)
    {
	upnt = get_pixel(0,y-1);
	pnt = get_pixel(0,y);
	dpnt = get_pixel(0,y+1);
	out = convolved->get_pixel(1,y);
	for (int x = 1; x < (width-1); x++)
	{
	    temp_total  = k11 * upnt[0] + k12 * upnt[1] + k13 * upnt[2];
	    temp_total += k21 * pnt[0] + k22 * pnt[1] + k23 * pnt[2];
	    temp_total += k31 * dpnt[0] + k32 * dpnt[1] + k33 * dpnt[2];
	    *(out++) = (unsigned char) abs(temp_total / ksum);
	    upnt++; pnt++; dpnt++;
	}
    }
    return convolved;
}


inline int Grey8Image::compar_char(const void *c1, const void *c2)
{
    return (int) (*((unsigned char *) c1) - *((unsigned char *) c2));
}

Image *Grey8Image::neighbour_order(unsigned int n, Image *ordered)
{
    if (ordered == NULL) 
	ordered = new Grey8Image (width, height, frame_id, frame_time_in_ms);
    
    ordered->clear_border();
    unsigned char table[9];
    unsigned char *upnt, *pnt, *dpnt;  
    unsigned char *out;
    int ntake1 = n - 1;
    for (int y = 1; y < height-1; y++)
    {
	upnt = get_pixel(0,y-1);
	pnt = get_pixel(0,y);
	dpnt = get_pixel(0,y+1);  
	out = ordered->get_pixel(1,y);
	for (int x = 1; x < width-1; x++)
	{
	    table[0] = upnt[0]; table[1] = upnt[1]; table[2] = upnt[2];
	    table[3] = pnt[0]; table[4] = pnt[1]; table[5] = pnt[2];
	    table[6] = dpnt[0]; table[7] = dpnt[1]; table[8] = dpnt[2];
	    
	    qsort(table, 9, sizeof(unsigned char), &compar_char);
	    *out = table[ntake1];
	    upnt++; pnt++; dpnt++;out++;
	}
    }
    return ordered;
}

Image *Grey8Image::minimum(Image *res)
{
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    res->clear_border();
    unsigned char *upnt, *pnt, *dpnt, min, tmp;  
    unsigned char *out;
    for (int y = 1; y < height-1; y++)
    {
	upnt = get_pixel(0,y-1);
	pnt = get_pixel(0,y);
	dpnt = get_pixel(0,y+1);  
	out = res->get_pixel(1,y);
	for (int x = 1; x < width-1; x++)
	{
	    min = *upnt;
	    if (min > (tmp = *(upnt + 1))) min = tmp;
	    if (min > (tmp = *(upnt + 2))) min = tmp;
	    if (min > (tmp = *(pnt))) min = tmp;
	    if (min > (tmp = *(pnt + 1))) min = tmp;
	    if (min > (tmp = *(pnt + 2))) min = tmp;
	    if (min > (tmp = *(dpnt))) min = tmp;
	    if (min > (tmp = *(dpnt + 1))) min = tmp;
	    if (min > (tmp = *(dpnt + 2))) min = tmp;
	    
	    *out++ = min;
	    upnt++; pnt++; dpnt++;
	}
    }
    return res;
}

Image *Grey8Image::maximum(Image *res)
{
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    res->clear_border();
    unsigned char *upnt, *pnt, *dpnt, max, tmp;  
    unsigned char *out;
    for (unsigned int y = 1; y < height-1; y++)
    {
	upnt = get_pixel(0,y-1);
	pnt = get_pixel(0,y);
	dpnt = get_pixel(0,y+1);  
	out = res->get_pixel(1,y);
	for (unsigned int x = 1; x < width-1; x++)
	{
	    max = *upnt;
	    if (max < (tmp = *(upnt + 1))) max = tmp;
	    if (max < (tmp = *(upnt + 2))) max = tmp;
	    if (max < (tmp = *(pnt))) max = tmp;
	    if (max < (tmp = *(pnt + 1))) max = tmp;
	    if (max < (tmp = *(pnt + 2))) max = tmp;
	    if (max < (tmp = *(dpnt))) max = tmp;
	    if (max < (tmp = *(dpnt + 1))) max = tmp;
	    if (max < (tmp = *(dpnt + 2))) max = tmp;
	    
	    *out++ = max;
	    upnt++; pnt++; dpnt++;
	}
    }
    return res;
}


unsigned char Grey8Image::get_mid (unsigned char &a, 
				   unsigned char &b,
				   unsigned char &c)
{
    if (a < b)
    {
	if (b <= c)
	    return b;
	else
	{
	    if (c <= a)
		return a;
	    else
		return c;
	}
    }
    else 
    {
	if (a <= c)
	    return a;
	else 
	{
	    if (b >= c)
		return b;
	    else
		return c;
	}
    }
}


Image *Grey8Image::fmed(Image *res)
{
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    res->clear_border();
    unsigned char *upnt, *pnt, *dpnt, mid1, mid2, mid3;  
    unsigned char *out;
    for (int y = 1; y < height-1; y++)
    {
	upnt = get_pixel(0,y-1);
	pnt = get_pixel(0,y);
	dpnt = get_pixel(0,y+1);  
	out = res->get_pixel(1,y);
	for (int x = 1; x < width-1; x++)
	{
	    mid1 = get_mid(upnt[0],upnt[1],upnt[2]);
	    mid2 = get_mid(pnt[0],pnt[1],pnt[2]);
	    mid3 = get_mid(dpnt[0],dpnt[1],dpnt[2]);
	    *out++ = get_mid(mid1, mid2, mid3);
	    
	    upnt++; pnt++; dpnt++;
	}
    }
    return res;
}


Image *Grey8Image::sobel(unsigned int threshold, Image *hsobel)
{
    unsigned int sqthresh = threshold * threshold;
    unsigned int hpix;
    unsigned int vpix;
    hsobel = convolve(SOBELH_KER, hsobel);
    Image *vsobel = convolve(SOBELV_KER);
    unsigned char *hdat, *vdat, *idat, *enddat;
    enddat = get_end_data();
    hdat = hsobel->get_data();
    vdat = vsobel->get_data();
    for (idat = data; idat < enddat; idat++)
    {
	hpix = (int) *hdat;
	vpix = (int) *vdat;
	if ((hpix * hpix + vpix * vpix) > sqthresh)
	    *hdat = MARK;
	else
	    *hdat = CLEAR_MARK;
	hdat++; vdat++;
    }
    delete vsobel;
    return hsobel;
}

Image *Grey8Image::sobel(Image *hsobel)
{
    int hpix, vpix;
    hsobel = convolve(Kernel(1,0,-1,2,0,-2,1,0,-1,true), hsobel);
    Image *vsobel = convolve(Kernel(1,0,-1,2,0,-2,1,0,-1,false));
    unsigned char *hdat, *vdat, *idat, *enddat;
    enddat = get_end_data();
    hdat = hsobel->get_data();
    vdat = vsobel->get_data();
    for (idat = data; idat < enddat; idat++)
    {
	hpix = (int) *hdat;
	vpix = (int) *vdat;
	*hdat = (unsigned char) (MAX(hpix,vpix));
	hdat++; vdat++;
    }
    delete vsobel;
    return hsobel;
}

Image *Grey8Image::threshold(unsigned int thresh, Image *outimg,
			     unsigned int *no_marked)
{
    if (outimg == NULL)
        outimg = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    unsigned int mark_count = 0;
    unsigned char *idat = data, *odat = outimg->get_data();
    unsigned char *enddat = get_end_data();
    
    for (;idat thresh) 
	{
	    *odat = MARK;
	    mark_count++;
	}
	else
            *odat = CLEAR_MARK;
	odat ++;
    }
    if (no_marked != NULL)
	*no_marked = mark_count;
    
    return outimg;
}


Image *Grey8Image::extract_subimage(int xmin, int xmax, int ymin, int ymax,
				    Image *subimg)
{
    assert (xmin < xmax);
    assert (ymin < ymax);
    assert (check_coords(xmin,ymin) == true);
    assert (check_coords(xmax,ymax) == true);

    if (subimg == NULL)
	subimg = new Grey8Image((xmax - xmin) + 1, (ymax - ymin) + 1,
				frame_id, frame_time_in_ms);
    else
    {
	assert (subimg->get_width() == (xmax - xmin) + 1);
	assert (subimg->get_height() == (ymax - ymin) + 1);
    }
    
    unsigned char *indat;
    unsigned char *outdat;
    
    for (int y = ymin; y <= ymax; y++)
    {
	indat = get_pixel(xmin,y);
	outdat = subimg->get_pixel(0,y-ymin);
	for (int x = xmin; x <= xmax; x++)
	{
	    *outdat++ = *indat;
	    *indat++ = CLEAR_MARK;
	}
    }
    return subimg;
}

Image *Grey8Image::fcombine(Image *image2, int (*func) (void*, void*),
			    Image *res)
{
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    unsigned char *idat1 = data, *idat2 = image2->get_data();
    unsigned char *odat = res->get_data(), *enddat = get_end_data();
    for (;idat1 < enddat; idat1++)
	*odat++ = (*func) ((void*) (idat1), (void*) (idat2++));
    return res;
}


Image *Grey8Image::simple_difference(Image *image2, realno thresh, 
				     unsigned int *no_marked, Image *res)
{
    unsigned int mark_count = 0;
    unsigned int threshold = (unsigned int) thresh;
    // if thresh < 0 don't threshold, just subtract
    if (thresh < 0) 
    {
	if (no_marked != NULL)
	    *no_marked = 0;
	return difference(image2, res);
    }
    if (image2->get_width() != width || image2->get_height() != height)
    {
	cerror << " cannot difference different sized images !";
	exit(1);
    }
    
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    unsigned char *idat1 = data;
    unsigned char *idat2 = image2->get_data();
    unsigned char *odat = res->get_data();
    unsigned char *enddat = get_end_data();
    
    for ( ;idat1 < enddat; idat1++)
    {
	if (abs(*idat1 - *idat2) > threshold) 
	{
	    *odat = MARK;
	    mark_count++;
	}
	else
	    *odat = CLEAR_MARK;
	idat2++;odat++;
    }
    if (no_marked != NULL)
	*no_marked = mark_count;
    
    return res;
}

Image *Grey8Image::difference(Image *image2, Image *res)
{
    if (image2->get_width() != width || image2->get_height() != height)
    {
	cerror << " cannot difference different sized images !";
	exit(1);
    }
    
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    unsigned char *idat1;
    unsigned char *idat2 = image2->get_data();
    unsigned char *odat = res->get_data();
    unsigned char *enddat = get_end_data();
    
    for (idat1 = data; idat1 < enddat; idat1++, idat2++)
    {
  	*odat++ =  abs (*idat1 - *idat2);
    }
    return res;
}

Image *Grey8Image::half_blur(Image *res)
{
    int new_width = width  / 2;
    int new_height = height / 2;
    if (res == NULL)
	res = new Grey8Image(new_width, new_height, frame_id, frame_time_in_ms);
    
    unsigned char *odat = res->get_data();
    for (int y = 0; y < new_height; y++)
    {
	unsigned char *in_even = get_pixel(0,y * 2);
	unsigned char *in_odd = get_pixel(0,y * 2 + 1);
	for (int x = 0; x < new_width; x++)
	{
	    int curr_pix = *in_even++ + *in_odd++ + 
		*in_even++ + *in_odd++;
	    *odat++ = (curr_pix >> 2);
	}
    }
    return res;
}

Image *Grey8Image::blur(Image *res)
{      
    unsigned char *upnt, *pnt, *dpnt;
    unsigned char *out;
    int temp_total;
    if (res  == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    for (int y = 1; y < height-1; y++)
    {
	upnt = get_pixel(0,y-1);
	pnt = get_pixel(0,y);
	dpnt = get_pixel(0,y+1);
	out = res->get_pixel(1,y);
	for (int x = 1; x < width; x++)
	{
	    temp_total  = upnt[0] + upnt[1] + upnt[2] 
		+ pnt[0] + pnt[2]
		+ dpnt[0] + dpnt[1] + dpnt[2];
	    *(out++) = (unsigned char) (temp_total >> 3);
	    upnt++; pnt++; dpnt++;
	}
    }
    return res;
}

Image *Grey8Image::mask(Image *mask, Image *res)
{
    if (mask == NULL)
	return NULL;
    
    if (res == NULL) 
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    if ((mask->get_width() != width) || (mask->get_height() != height))
    {
	int x;
	int y;
	register unsigned char *mask_pix;
	for (y = 0; y < height; y++)
	    for (x = 0; x < width; x++)
	    {
		if (mask->check_coords(x,y))
		{
		    mask_pix = mask->get_pixel(x,y);
		    if (*mask_pix != (unsigned char) 0x00)
			*res->get_pixel(x,y) = *get_pixel(x,y);
		}
	    }
    }
    else 
    {
	unsigned char *rdat = res->get_data();
	unsigned char *dat1 = data;
	unsigned char *dat2 = mask->get_data();
	unsigned char *edat = get_end_data();
	while (dat1 < edat)
	    *rdat++ = *dat1++ & *dat2++;
    }
    
    return res;
}


Image *Grey8Image::fix_holes(int gapsize, Image *res)
{
    int i;
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    Grey8Image *temp_img1;
    Grey8Image *temp_img2;
    Grey8Image *dummy;
    
    temp_img1 = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    temp_img2 = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    temp_img1->clear(CLEAR_MARK);
    temp_img2->clear(CLEAR_MARK);
    this->maximum(temp_img1);
    
    for (i = 1; i < gapsize; i++)
    {
	temp_img1->maximum(temp_img2);
	dummy = temp_img1;
	temp_img1 = temp_img2;
	temp_img2 = dummy;
    }    
    
    for (i = 0; i < gapsize; i++)
    {
	temp_img1->minimum(temp_img2);
	dummy = temp_img1;
	temp_img1 = temp_img2;
	temp_img2 = dummy;
    }
    
    temp_img1->copy(res);
    delete temp_img2;
    delete temp_img1;
    return res;
}



#ifdef USE_GL 
/////////////////////////   GL interface    ////////////////////////////

long Grey8Image::display(long awindow)
{
#ifdef NO_DISPLAY
    return NULLWIN;
#else
    int width4 = width;
    
    if ((width % 4) != 0)
	width4 = 4 * ((width / 4) + 1);
    
    if (awindow != NULLWIN)
	glwin = awindow;
    
    if (glwin == NULLWIN)
    {
	int zoom = Image::display_zoom->value;
	prefsize(width4 * zoom, height * zoom);
// nts: this gives an error in Ygl version 4.x
//	foreground();
	if (window_title[0] == 0)  // no title given?  default to this:
	    sprintf(window_title," GREY8 image %d by %d ", width, height);
	
	glwin = winopen(window_title);
	
	if (glwin < 0) // error
	{
	    cerror << " Warning: cannot open window for Grey8Image display "
		   << endl << flush;
	}
	
	winset(glwin);
	reshapeviewport();
	prefsize(width4 * zoom, height * zoom);
	if (zoom  != 1)
	{
	    // nts: this is included in Ygl version 4.x !
	    rectzoom((float) zoom, (float) zoom);
	    viewport(0, width4 * zoom - 1, 0, height * zoom - 1);
	    ortho2(-0.5, width4 + 0.5, -0.5, height + 0.5);
	}
	winconstraints();
	cmode();
	gflush();
	
//#ifndef LINUX
	for (int k = 0; k < 256; k++)
	    mapcolor(k,k,k,k);
//#endif
	
	gflush();
	gconfig();
    }
    if (width != width4)
    {
	Grey8Image tmp_image(width4,height);
	tmp_image.clear(CLEAR_MARK);
	tmp_image.paste_subimage(0,width-1,0,height-1, this);
	winset(glwin);
	
	crectwrite(0,0,width4-1,height-1, (Uint8*)
		   tmp_image.get_data());
    }
    else
    {
	winset(glwin);
	crectwrite(0,0,width-1,height-1,(Uint8 *) data);
    }
    return glwin;
#endif   // #ifdef NO_DISPLAY  #else
}

/////////////////////////   GL interface ends   ////////////////////////////
#else
/////////////////////////   X interface   ////////////////////////////


#ifndef NO_DISPLAY
void Grey8Image::setup_greymap(Display *mydisplay, int screen, Window mywindow)
{
    cmap = DefaultColormap(mydisplay, screen);
    no_grey_cells = 256;
    unsigned int min_cells = 256;
    
    Status res = 0;
    unsigned long pix_vals[256];
    unsigned int no_cells = no_grey_cells;
    
    while ((res == 0) && (no_cells >= min_cells))
    {
	
	res = XAllocColorCells(mydisplay, cmap, False, NULL,
			       0, pix_vals, no_cells);
	no_cells /= 2;
    }
    
    if (res == 0)
    {
	cmap = XCreateColormap(mydisplay, mywindow,
			       DefaultVisual(mydisplay, screen),
			       AllocNone);
	no_cells = no_grey_cells;
	while ((res == 0) && (no_cells >= 8))
	{
	    res = XAllocColorCells(mydisplay, cmap, True, NULL,
				   0, pix_vals, no_cells);
	    
	    no_cells /= 2;
	}
	
	if (res == 0) exit(1);
    }
    
    no_cells *= 2;
    
    XColor *grey = (XColor *) new XColor [no_cells];
    for (unsigned int cell = 0; cell < no_cells; cell++)
    {
	unsigned int intensity = (unsigned int) ((cell  * (long) 65536 ) / (no_cells));
	grey[cell].red = grey[cell].green = grey[cell].blue =
	    intensity;
	grey[cell].pixel = pix_vals[cell];
	grey[cell].flags = DoRed | DoGreen | DoBlue;
    }
    
    for (unsigned int i = 0; i < 256; i++)
	reverse_cmap[i] = pix_vals[(i * no_cells) / 256];
    
    XStoreColors(mydisplay, cmap, grey, no_cells);
    delete grey;
    pixel = (unsigned char) pix_vals[0];
}
#endif   // #ifndef NO_DISPLAY

void Grey8Image::virtual_display()
{
#ifndef NO_DISPLAY
    if (mydisplay == NULL)
    {
	mydisplay = XOpenDisplay("");
	int screen = DefaultScreen(mydisplay);
	mypixmap = XCreatePixmap(mydisplay,
				 DefaultRootWindow(mydisplay), width,
				 height, 8);
	myimage = XCreateImage( mydisplay, DefaultVisual(mydisplay, screen),
				8, ZPixmap, 0, None, width, height,
				8, 0);
	mygc = XCreateGC (mydisplay, mypixmap, 0, 0);
	
	// X11 works with images stored IA_TOP_TO_BOTTOM and 8-bit grey values.
	// Check whether we do, too:
	if ((no_grey_cells == 256) && (Image::image_storage_mode == IA_TOP_TO_BOTTOM))
	    myimage->data = (unsigned char *) data;
	else
	    myimage->data = new unsigned char[width * height];
    }
    if ((unsigned char*) data != myimage->data)
    {
	Grey8Image tmp_img(width, height, (unsigned char*) myimage->data);
	flip_vertically(&tmp_img);
    }
    XPutImage(mydisplay, mypixmap, mygc, myimage, 0,0,0,0,width,
	      height);
#endif   // #ifndef NO_DISPLAY
}

long Grey8Image::display(long dummy)
{ 
#ifndef NO_DISPLAY
    if (mydisplay == NULL)
    {
	if (window_title[0] == 0)
	{
	    if (window_title[0] == 0)  // no title given?  default to this:
		sprintf(window_title," GREY8 image %d by %d ", width, height);
	}
	
	XSizeHints myhints;
	myhints.width = width;
	myhints.height = height;
	myhints.flags = PSize;
	mydisplay = XOpenDisplay("");
	int screen = DefaultScreen(mydisplay);
	unsigned long white = WhitePixel(mydisplay, screen);
	unsigned long black = BlackPixel(mydisplay, screen);
	mywindow = XCreateSimpleWindow (mydisplay, DefaultRootWindow(mydisplay)
					,100,100,width,height,5,black, white);
	mypixmap = XCreatePixmap(mydisplay,
				 DefaultRootWindow(mydisplay), width,
				 height, 8);
	XSetStandardProperties(mydisplay, mywindow, window_title,
			       "image", None,
			       NULL, 0, &myhints);
	XSetWindowBackgroundPixmap(mydisplay, mywindow, mypixmap);
	XMapRaised(mydisplay, mywindow);
	myimage = XCreateImage( mydisplay, DefaultVisual(mydisplay, screen),
				8, ZPixmap, 0, None, width, height,
				8, 0);
	if (no_using_cmap == 0) setup_greymap(mydisplay, screen, mywindow);
	no_using_cmap++;
	XSetWindowColormap(mydisplay, mywindow, cmap);
//       XSetWindowAttributes xswa;
//       xswa.backing_pixel = (unsigned long) pixel;
//       xswa.backing_planes = plane_masks[0] | plane_masks[1] | plane_masks[2]
// 	| plane_masks[3] | plane_masks[4] | plane_masks[5] | plane_masks[6]
// 	  | plane_masks[7];
//       XChangeWindowAttributes(mydisplay, mywindow, CWBackingPlanes |
// 			      CWBackingPixel, &xswa); 
	//mygc = XCreateGC (mydisplay, mywindow, 0, 0);
	mygc = XCreateGC (mydisplay, mypixmap, 0, 0);
	/*if ((shift == 0) && (offset == 0))
	  myimage->data = (char *) data;
	  else*/
	
	// X11 works with images stored IA_TOP_TO_BOTTOM and 8-bit grey values.
	// Check whether we do, too:
	if ((no_grey_cells == 256) && (Image::image_storage_mode == IA_TOP_TO_BOTTOM))
	    myimage->data = (unsigned char*) data;
	else
	    myimage->data = new unsigned char[width * height];
    }
    
    if ((unsigned char*) data != myimage->data)
    {
	unsigned int x,y;
	unsigned char *idat, *odat = (unsigned char*) myimage->data;
	for (y = height; y > 0; y--)
	{
	    idat = get_pixel(0, (y-1));
	    for (x = 0; x < width; x++)
		*odat++ = reverse_cmap[*idat++];
	}
    }
    
    
    //XPutImage(mydisplay, mywindow, mygc, myimage, 0,0,0,0,width,
    
    //height);
    XPutImage(mydisplay, mypixmap, mygc, myimage, 0,0,0,0,width,
	      height);
    XClearArea(mydisplay, mywindow, 0,0,0,0, True);
    
#endif   // #ifndef NO_DISPLAY
    
    return 0;
}

#endif   // ifdef USE_GL else   ie use X11

/////////////////////////   X interface ends   ////////////////////////////





Image *Grey8Image::diff_stats(Image *image2, realno &mean,
			      realno &variance, Image *res)
{
    if (image2->get_width() != width || image2->get_height() != height)
    {
	cerror << " can't difference different sized images !";
	exit(1);
    }
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    unsigned char *idat1 = data,  *idat2 = image2->get_data()
	, *odat = res->get_data(), *enddat = get_end_data();
    int diff, no_pixels = enddat - data;
    realno total_diff = 0 , total_square = 0;
    
    for ( ;idat1 < enddat; idat1++)
    {
	diff = (*idat1 - *idat2);
	*odat++ =  abs (diff);
	total_diff += diff;
	total_square += (diff * diff);
	idat2++;
    }
    mean = (total_diff / no_pixels);
    variance = (total_square / no_pixels) - (mean * mean);
    return res;
}

Image *Grey8Image::image_blend(Image *i2, int a, int b, Image *res)
{
    // if trying to blend a Greyscale and colour image
    if ((i2 != NULL) && (i2->get_image_type() == RGB32))
	return i2->image_blend(this,b,a,res);
    
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    unsigned char *idat1 = data, *idat2 = i2->get_data(),
	*odat = res->get_data(),  *enddat = get_end_data();
    int pix;
    int aplusb = a + b;
    
    for ( ;idat1 < enddat; idat1++)
    {
	pix = (a * *idat1) + (b * *idat2);
	*odat++ = (pix / aplusb);
	idat2++;
    }
    return res;
}

Image *Grey8Image::map_intensities(PntGreyMap gmap, Image *res)
{
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    
    unsigned char *idat = data, *odat = res->get_data(),
	*enddat = get_end_data();
    for ( ;idat < enddat; idat++)
	*odat++ = gmap[*idat];
    
    return res;
}

Image *Grey8Image::b_w_compress(Image *res)
{
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    unsigned char *idat = data, *odat = res->get_data();
    unsigned char flag;
    int counter;
    while (idat < end_data)
    {
	flag = *idat;
	counter = -1;
	while ((idat < end_data) && (*idat == flag) && counter < 127)
	{
	    counter++;
	    idat++;
	}
	if (flag == MARK) counter = counter | 128;
	*odat++ = counter;
    }
    res->set_end_data(odat);
    return res;
}

Image *Grey8Image::b_w_uncompress(Image *res)
{
    if (res == NULL)
	res = new Grey8Image(width, height, frame_id, frame_time_in_ms);
    unsigned char *idat = data, *odat = res->get_data();
    unsigned char *edat = res->get_end_data();
    unsigned char flag;
    int counter;
    while (odat < edat)
    {
	counter = (*idat & 127) + 1;
	if ((*idat & 128) != 0)
	    flag = MARK;
	else
	    flag = CLEAR_MARK;
	while (counter > 0  && odat < edat)
	{
	    counter--;
	    *odat++ = flag;
	}
	idat++;
    }
    return res;
}

realno Grey8Image::get_marked_fraction()
{
    int total_marked  = 0;
    for (unsigned char *idat = data; idat < end_data; idat ++)
    {
	if (*idat == MARK)
	    total_marked++;
    }
    return (realno) total_marked / (end_data - data);
}

void Grey8Image::save_pnm(char *filename)  // save PGM file
{
    // save as portable grey map (binary mode)
    FILE *outfile = NULL;

    if (filename == NULL)
	outfile = stdout;
    else
    {
	outfile = fopen(filename,"wb");  // `b' may be important on non-UNIX

	if (outfile == NULL)
	{
	    cerror << " Grey8Image::save_pnm: could not open output file »"
		   << filename << "« " << endl;
	    exit(1);
	}
    }
    
    fprintf(outfile,"P5\n%d %d\n255\n", width, height);
    
    // write pixel values, depending on image_storage_mode
    // The PNM formats are storing the image IA_TOP_TO_BOTTOM
    if (Image::image_storage_mode == IA_TOP_TO_BOTTOM)
    {
	// no need to convert.  write out all data in one go:
	fwrite(data, 1, width*height, outfile);
    }
    else
    {
	// flip image (y lines) as we write the file
	for (unsigned int y = height; y > 0; y--)
	    fwrite(get_pixel(0, y-1), 1, width, outfile);
    }
    
    if (filename != NULL)
	fclose(outfile);
}

Grey8Image::Grey8Image(char *pgmfile)
{
    FILE *infile = NULL;
    if ((infile = fopen(pgmfile,"rb")) == NULL)  // `b' may be important on non-UNIX
    {
	cerror << " Grey8Image::Grey8Image: could not open input file »"
	       << pgmfile << "« " << endl;
	exit(1);
    }
    char c1,c2;
    fscanf(infile,"%c%c", &c1, &c2);
    if (c1 != 'P' || c2 != '5')
    {
	cerror << " file not pgm in Grey8Image::Grey8Image " << endl;
	exit(1);
    }
    char aline[100];
    fgets(aline, 99, infile);
    while (aline[0] == '#' || aline[0] == '\n') fgets(aline, 99, infile);
    sscanf(aline,"%d %d\n", (int *) &width, (int *) &height);
    fscanf(infile,"%d\n", (int *) &bytes_per_pixel);
    if (bytes_per_pixel != 255)
    {
	cerror << " bad pgm format " << endl;
	exit(1);
    }
    
    bytes_per_pixel = 1;
    line_length = width * bytes_per_pixel;
    data = new unsigned char[width * height * bytes_per_pixel];
    end_data = (data + width * height * bytes_per_pixel);
    image_type = GREY8;
    
    // read pixel values, depending on image_storage_mode
    // The PNM formats are storing the image IA_TOP_TO_BOTTOM
    if (Image::image_storage_mode == IA_TOP_TO_BOTTOM)
    {
	// no flipping necessary, read all data in one go
	fread(data, 1, width*height, infile);
    }
    else
    {
	// flip image (y lines) as we read the file
	for (unsigned int y = height; y > 0; y--)
	{
	    fread(get_pixel(0, y-1), 1, width, infile);
	}
    }
    
#ifndef NO_DISPLAY
#ifdef USE_GL
    glwin = NULLWIN;
#else
    mydisplay = NULL;
#endif
    Grey8_draw_colour = 255;
#endif   // #ifndef NO_DISPLAY
}

Image *Grey8Image::to_rgb(Image *res)
{
    if (res == NULL)
	res = new RGB32Image(width, height, frame_id, frame_time_in_ms);
    
    unsigned char *idat = data;
    //unsigned char *odat = res->get_data();
    RGB32pixel *odat = (RGB32pixel*) res->get_data();
    unsigned char *edat = get_end_data();
    //RGB8pixel *pix;
    unsigned char glevel;
    for ( ;idat < edat; idat ++)
    {
	if ((*idat * 1.164) > 255)
	    glevel = 255;
	else
	    glevel = (unsigned char) (*idat * 1.164);
	//glevel = glevel >> 5;
	//pix = (RGB32pixel*) odat;
	//pix->blue = (glevel / 2);
	odat->blue = (glevel);
	odat->green = (glevel);
	odat->red = (glevel); 
	odat++;
    }
    return res;
}

void Grey8Image::draw_rectangle(int xmin, int xmax, int ymin, int
				ymax, int val)
{
    if ((xmin > xmax) || (ymin > ymax))
    {
	cerror << " Grey8Image::draw_rectangle("
	       << xmin << "," << xmax << "," << ymin << "," << ymax
	       << ", " << val << ") : cannot draw! " << endl;
	return;
    }
    
    if (xmin < 0)
	xmin = 0;
    if (ymin < 0)
	ymin = 0;
    if (xmax >= width)
	xmax = (width-1);
    if (ymax >= height)
	ymax = (height-1);
    
    // maybe we were called with something like (-10,-5 \ETC) so check again:
    if ((xmin > xmax) || (ymin > ymax))
    {
	cerror << " Grey8Image::draw_rectangle (corrected values "
	       << xmin << "," << xmax << "," << ymin << "," << ymax
	       << ", " << val << ") : cannot draw! " << endl;
	return;
    }
    
    int nbytes = (xmax - xmin + 1) * bytes_per_pixel; 
    for (int y = ymin; y <= ymax; y++)
	memset(get_pixel(xmin,y),val, nbytes);
}

Image *Grey8Image::transform(int centre_x, int centre_y, realno angle,
			     realno scale, Image *res)
{
    if (res == NULL)
	res = copy_type();
    unsigned char *dest;
    int x_from, y_from;
    realno cosa = cos(angle) / scale;
    realno sina = sin(angle) / scale;
    const int &dw = res->get_width();
    const int &dh = res->get_height();
    int dw2 = dw / 2;
    int dh2 = dh / 2;
    for (int y = 0; y < dh; ++y) 
    {
	dest = res->get_pixel(0,y);
	for (int x = 0; x < dw; ++x) 
	{
	    int x1 = x - dw2;
	    int y1 = y - dh2;
	    
	    x_from = (int) (centre_x + x1 * cosa + y1 * sina);
	    y_from = (int) (centre_y + y1 * cosa - x1 * sina);
	    
	    if ((x_from < 0) || (y_from < 0) || (x_from >= width)
		|| (y_from >= height))
		*dest++ = 0;
	    else
		*dest++ = *get_pixel(x_from, y_from);
	}
    }
    return res;
}


Grey8Image::~Grey8Image()
{
#ifndef NO_DISPLAY
#ifndef USE_GL
    if (mydisplay != NULL)
    {
	XFreeGC(mydisplay, mygc);
	XFreePixmap(mydisplay, mypixmap);
	if (mywindow != NULLWIN)
	{
	    XDestroyWindow(mydisplay, mywindow);
	    no_using_cmap--;
	    if (no_using_cmap == 0)
	    {
		XFreeColormap(mydisplay, cmap);
		//cerror << " Freeing colormap " << endl;
		cmap = 0;
		no_using_cmap = 0;
	    }
	    
	}
	if (myimage->data != (char *) data) delete [] (myimage->data);
	myimage->data = None;
	XFree((char *) myimage);
	mydisplay = NULL;
    }
#endif
#endif   // #ifndef NO_DISPLAY
}


void Grey8Image::median_img_array(Image* *img_array, int asize)
{
    
    if (img_array[0]->get_image_type() != GREY8)
    {
	cerror << " bad call to Grey8Image::median_img_array " << endl;
	abort();
    }
    
    unsigned char *table = new unsigned char[asize];
    int cpos = (asize + 1) / 2;
    int i,j,k;
    for (i = 0; i < width; i++)
	for (j = 0; j < height; j++)
	{
	    for (k = 0; k < asize; k++)
		table[k] = *(img_array[k]->get_pixel(i,j));
	    
	    qsort(table, asize, sizeof(unsigned char), &compar_char);
	    *get_pixel(i,j) = table[cpos];
	}
    delete [] table;
}


RGB32Image *Grey8Image::rgb_read_image(RGB32Image *res)
{
#ifdef NO_DISPLAY
    // mission impossible
    cerror << "Grey8Image::rgb_read_image not possible without display " << endl;
    abort();
    return NULL;
#else
    
#ifdef USE_GL
    
    Int32 xsize;
    Int32 ysize;
    winset(glwin);
    getsize(&xsize, &ysize);
    
    if (res == NULL)
	res = new RGB32Image(xsize, ysize, frame_id, frame_time_in_ms);
    
    // read colour mapped pixel data
    //Image *tmp_img = new Grey8Image(xsize, ysize, frame_id, frame_time_in_ms);
    
    Colorindex *image_data = new Colorindex[xsize * ysize];
    rectread(0,0,xsize-1,ysize-1, (Int16*)(image_data));
    
    // unmap the data
    Colorindex *idat = image_data;
    Colorindex *edat = &image_data[xsize * ysize];
    RGB32pixel *odat = (RGB32pixel*) res->get_data();
    
    Int16 red_val;
    Int16 green_val;
    Int16 blue_val;
    
    for ( ; idat < edat; idat++)
    {
	
	getmcolor(*idat, &red_val, &green_val, &blue_val);
	odat->alpha = 0;
	odat->red   = (unsigned char) red_val;
	odat->green = (unsigned char) green_val;
	odat->blue  = (unsigned char) blue_val;
	odat++;
    }
    
    delete [] image_data;
    return res;
#else
    
    // to be implemented !
    cerror << "Grey8Image::rgb_read_image not implemented on X11 " << endl;
    abort();
    return NULL;
    
#endif
#endif   // #ifdef NO_DISPLAY  #else
}



void Grey8Image::set_draw_colour(unsigned char red, unsigned char green,
				 unsigned char blue)
{
    realno col = 0.299 * red + 0.587 * green + 0.114 * blue;
    Grey8_draw_colour = (unsigned char) (col + 0.5);
}

void Grey8Image::set_draw_colour(unsigned char grey_value)
{
    Grey8_draw_colour = grey_value;
}

void Grey8Image::draw_horizontal(unsigned int y, unsigned int xl, unsigned int xr,
				 bool dotted)
{
    if ((check_coords(xl, y) == false) ||
	(check_coords(xr,y) == false))
	return;
    
    unsigned char *pixleft = get_pixel(xl, y);
    unsigned char *pixright = get_pixel(xr,y);

    while (pixleft <= pixright)
    {
	*pixleft++ = Grey8_draw_colour;
	
	if (dotted)
	    pixleft++;  // skip another pixel
    }
}

void Grey8Image::draw_vertical(unsigned int x, unsigned int yl, unsigned int yu,
			       bool dotted)
{
    if ((check_coords(x,yl) == false) ||
	(check_coords(x,yu) == false))
	return;
    
    if (yl > yu)
    {
	// exchange values if coordinates are upside down
	unsigned int tmp = yl;
	yl = yu;
	yu = tmp;
    }
	
    for (unsigned int y = yl; y <= yu; y++)
    {
	if ((dotted) && ((y & 1) == 1))
	    continue;
	*get_pixel(x,y) = Grey8_draw_colour;
    }
}

void Grey8Image::plot_pixel(unsigned int x, unsigned int y)
{
    if (check_coords(x,y) == true)
	*get_pixel(x,y) = Grey8_draw_colour;
}

Image *Grey8Image::to_rgb(RGB32pixel *color_map, Image *res)
{
    if (res == NULL)
	res = new RGB32Image(width, height, frame_id, frame_time_in_ms);
    
    RGB32pixel *pnt_out = (RGB32pixel*) res->get_data();
    unsigned char *pnt_in = data;
    while (pnt_in < end_data)
	*pnt_out++ = color_map[*pnt_in++];
    return res;
}

void Grey8Image::get_detail(unsigned char *g1, unsigned char *g2,
		 	    unsigned char *r, int &width)
{
    int lpx,lpy;
    unsigned char *tg1, *tg2, *tr;
    for (lpy = 0; lpy < BOX_SIZE; lpy++)
    {
	tg1 = g1; tg2 = g2;
	tr = r;
	for (lpx = 0; lpx < BOX_SIZE; lpx++)
	    *r++ = abs(*g2++ - *g1++);
	
	g1 = tg1 + width; g2 = tg2 + width;
	r = tr + width;
    }
}


Image *Grey8Image::difference(Image *image2, realno threshold, Image *res)
{
    if ((this == NULL) || (image2 == NULL))
	return NULL;
    
    if (image2->get_image_type() != GREY8)
    {
	cerror << " Grey8Image::difference: cannot difference different image types! " << endl;
	exit(1);
    }
    
    if (res == NULL)
	res = new Grey8Image(width, height);
    
    res->clear(CLEAR_MARK);
    unsigned char *g1 = data;
    unsigned char *g2 = image2->get_data();
    
    unsigned char *tg1, *tg2, *trdat;
    unsigned char *rdat = res->get_data();
    
    int up = BOX_SIZE * width;
    int left = BOX_SIZE;
    
    int upleft = left + up;
    int upleft2 = upleft / 2;
    int upright = up - left;
    
    g1 += (upleft2) * 3; g2 += (upleft2) * 3;
    rdat += (upleft2) * 3;
    
    unsigned int lx, ly;
    unsigned int lymax = height / BOX_SIZE;
    unsigned int lxmax = width / BOX_SIZE; 
    
    int interest_threshold = (int) threshold;
    
    int adj1 = upleft2;
    int adj2 = left+adj1;
    int adj3 = up+adj1;
    int adj4 = upleft+adj1;
    int adj5 = adj1-left;
    int adj6 = adj1-up;
    int adj7 = adj1-upleft;
    int adj8 = adj1-upright;
    int adj9 = adj1+upright;
    
    Image *flag_img = new Grey8Image(lxmax, lymax);
    lxmax -=2 ;lymax -=2;
    flag_img->clear(CLEAR_MARK);
    for (ly = 1; ly < lymax; ly++)
    {
	tg1 = g1; tg2 = g2; 
	trdat = rdat;
	for (lx = 1; lx < lxmax; lx++)
	{
	    *rdat = abs (*g2 - *g1);
	    if (*rdat >= interest_threshold)
	    {
		// this square
		if (!*(flag_img->get_pixel(lx,ly)))
		{
		    get_detail(g1-adj1,g2-adj1, rdat-adj1, (int &) width);
		    *(flag_img->get_pixel(lx,ly)) = MARK;
		}
		// left
		if (!*(flag_img->get_pixel(lx-1,ly)))
		{
		    get_detail(g1-adj2,g2-adj2, rdat-adj2, (int &) width);
		    *(flag_img->get_pixel(lx-1,ly)) = MARK;
		}
		// up
		if (!*(flag_img->get_pixel(lx,ly-1)))
		{
		    get_detail(g1-adj3,g2-adj3, rdat-adj3, (int &) width);
		    *(flag_img->get_pixel(lx,ly-1)) = MARK;
		}
		// up-left
		if (!*(flag_img->get_pixel(lx-1,ly-1)))
		{
		    get_detail(g1-adj4,g2-adj4, rdat-adj4, (int &) width);
		    *(flag_img->get_pixel(lx-1,ly-1)) = MARK;
		}
		// right 
		if (!*(flag_img->get_pixel(lx+1,ly)))
		{
		    get_detail(g1-adj5,g2-adj5, rdat-adj5, (int &) width);
		    *(flag_img->get_pixel(lx+1,ly)) = MARK;
		}
		// down
		if (!*(flag_img->get_pixel(lx,ly+1)))
		{
		    get_detail(g1-adj6,g2-adj6, rdat-adj6, (int &) width);
		    *(flag_img->get_pixel(lx,ly+1)) = MARK;
		}
		// down-right
		if (!*(flag_img->get_pixel(lx+1,ly+1)))
		{
		    get_detail(g1-adj7,g2-adj7, rdat-adj7, (int &) width);
		    *(flag_img->get_pixel(lx+1,ly+1)) = MARK;
		}
		// down-left
		if (!*(flag_img->get_pixel(lx-1,ly+1)))
		{
		    get_detail(g1-adj8,g2-adj8, rdat-adj8, (int &) width);
		    *(flag_img->get_pixel(lx-1,ly+1)) = MARK;
		}
		// up-right
		if (!*(flag_img->get_pixel(lx+1,ly-1)))
		{
		    get_detail(g1-adj9,g2-adj9, rdat-adj9, (int &) width);
		    *(flag_img->get_pixel(lx+1,ly-1)) = MARK;
		}
	    } 
	    g1 += left; g2 += left;
	    rdat += left;
	}
	g1 = tg1 + up; g2 = tg2 + up;
	rdat = trdat + up;
	
    }
    delete flag_img;
    return res;
}

Grey8Image *Grey8Image::invert(Grey8Image *res)
{
    assert (line_length %4 == 0);  // we will read 4 pixels in one go for speed

    if (res == NULL)
	res = new Grey8Image(width, height);
    else
	if ((width != res->get_width()) ||
	    (height != res->get_height()) ||
	    (image_type != res->get_image_type()))
	{
	    cerror << " Grey8Image::invert: Error: cannot invert to differnt size / type image "
		   << endl;
	    abort();
	}

    u_int32_t *from = (u_int32_t *) data;
    u_int32_t *to = (u_int32_t *) res->get_data();

    while ((void *) from < (void *) end_data)
	*to++ = ! (*from++);  // bitwise negation 

    return res;
}

} // namespace ReadingPeopleTracker