www.pudn.com > ReadingPeopleTracker-1.28.rar > Image.h


/*
 * Image.h
 * general image class (base class)
 *
 * author : A M Baumberg
 */

#ifndef __IMAGE_H__
#define __IMAGE_H__

#include 
#include   // for strncpy()

#ifndef NO_DISPLAY
// include graphics libraries
#ifdef USE_GL
#include 
#else 
// use X interface and not GL
#include 
#include 
// #include 
#include 
#endif   // #ifdef USE_GL
#endif   // #ifndef NO_DISPLAY

// includes
#include "realno.h"
#include "tracker_defines_types_and_helpers.h"
#include "Kernel.h"
#include "GreyMap.h"
#include "timestamp_c.h"
#include "EnvParameter.h"

namespace ReadingPeopleTracker
{

// forward declarations
class RGB32Image;
class Point2;
class GreyMap;

class Image
{
    // The following three lines should not be necessary since protected members
    // derived `public'ly should be accessible in derived classes.  Never mind.
    friend class Grey8Image;
    friend class RGB32Image;
    friend class HSV32Image;

public:
    // public static member variables

    // image_addressing_mode: determines the orientation of the v axis in the image.
    //   This should always be BOTTOM_TO_TOP, like axes in mathematics and physics.
    //   TOP_TO_BOTTOM: line 0 is the top line,  BOTTOM_TO_TOP: line 0 is the bottom line
    static const ImageAddressing image_addressing_mode;

    // image_storage_mode: determines the orientation of the image in memory.  This has an
    //   influence only on functions which operate in the image memory, e.g. JPEGSource.
    //   This should be set to the way your graphics library or display (e.g. X11) handles it.
    //   TOP_TO_BOTTOM: a lower memory address is closer to the top line of the image,
    //   BOTTOM_TO_TOP: a higher memory address is closer to the top line of the image.
    static const ImageAddressing image_storage_mode;
  
protected:
    frame_id_t frame_id;           // frame id: numeric identifier of this frame (frame number)
    frame_time_t frame_time_in_ms; // frame time in milliseconds since the Epoch
    // (01/01/1970) UTC (== GMT) à la 1000 * POSIX.1 (see annex B section 2.2.2)
    ImageType image_type;
    
    unsigned int width;
    unsigned int height;
    unsigned int bytes_per_pixel;
    // bpp_shift := number such that (x * bytes_per_pixel) equals (x << bpp_shift)
    unsigned int bpp_shift;		
    unsigned int line_length;
    
    bool own_data;  // whether we have allocated (and should therefore de-allocate) *data
    unsigned char *data;
    unsigned char *end_data;
    
    unsigned int *ypoints;  // array of offsets to (0,y)
    
    realno DrawLineWidth; // for graphics routines
    
    // time stamp: from JPEG Time Stamp Header specification (see timestamp_c.h)
    TS_TIMESTAMP timestamp;   // FIXME: might not be used by all `ImageSource's yet
    
#ifndef NO_DISPLAY    
    char window_title[64];
#ifdef USE_GL
    // use GL
    long int glwin;
#else

#ifdef USE_VOGL
    static int vogl_init_flag;
#endif

    // use X
    Display *mydisplay;
    Window mywindow;
    XImage *myimage;
    Pixmap mypixmap;
    GC mygc;
#endif

public:    
    // use setenv IMAGE_ZOOM 2
    // to display images magnified by a factor of 2
    static EnvIntParameter *display_zoom;

#endif   // ifndef NO_DISPLAY
    
public:
    
    // set drawing colour
    static void set_colour(unsigned int col);

    // data accessors and modifiers 
    inline frame_id_t get_frame_id() const
	{
	    return frame_id;
	}
    inline void set_frame_id(frame_id_t new_frame_id)
	{
	    frame_id = new_frame_id;
	}
    inline frame_time_t get_frame_time_in_ms() const
	{
	    return frame_time_in_ms;
	}
    inline void set_frame_time_in_ms(frame_time_t new_frame_time_in_ms) 
	{
	    frame_time_in_ms = new_frame_time_in_ms;
	}
    inline unsigned int get_width() const
	{
	    return width; 
	}
    inline unsigned int get_height() const
	{
	    return height; 
	}
    inline unsigned int get_bytes_per_pixel() const
	{
	    return bytes_per_pixel;
	}
    inline TS_TIMESTAMP *get_timestamp()
	{
	    return ×tamp;
	}
    inline void set_timestamp(const TS_TIMESTAMP *new_timestamp)
	{
	    timestamp = *new_timestamp;
	}

    inline unsigned char *get_data() const
	{
	    return data;
	}
    
    inline void set_data(unsigned char *new_data)  // use with caution!
	{
	    if (own_data)
		delete [] data;
	    data = new_data;
	    end_data = data + width * height * bytes_per_pixel;
	    
	    own_data = true;  // assume that the new data was allocated exclusively for us
	}
    
    inline unsigned char *get_end_data() const
	{
	    return end_data;
	}
    
    inline void set_end_data(unsigned char *new_end_data)   // use with caution!
	{ 
	    end_data = new_end_data;
        }
    void set_height(unsigned int new_height)
	{
	    height = new_height;
	}
    void set_width(unsigned int new_width)
	{
	    width = new_width;
	}
#ifndef NO_DISPLAY
#ifdef USE_GL
    void set_title(char *title)
	{
	    strncpy(window_title,title,63);
	    
	    // change if already displayed
	    if (glwin != NULLWIN)
	    {
		winset(glwin);
		wintitle(window_title);
	    }
	}
    
    inline long int get_glwin() const
	{
	    return glwin;
	}
    
    inline void set_glwin(long int new_glwin)
	{
	    glwin = new_glwin;
	}
    
#else
#error Tugdual: Please implement set_title, and, only if necessary, an equivalent to [gs]et_glwin for Qt
#endif   // ifdef USE_GL else
#endif   // #ifndef NO_DISPLAY

    
    virtual unsigned int measure_contrast(void *p1, void *p2);
    
    // constructor, destructor
    
    Image (unsigned int the_width, unsigned int the_height,
	   frame_id_t the_frame_id = 0, frame_time_t the_frame_time_in_ms = 0,
	   unsigned int the_bpp = 1, unsigned char *the_data = NULL);
    
    Image ()
	{   
	    frame_id = 0;
	    frame_time_in_ms = 0;
	    width = height = bytes_per_pixel = 0;
	    image_type = BASE;  // change in derived classes!
	    
	    data = end_data = NULL;
#ifndef NO_DISPLAY
	    window_title[0] = 0;
#endif   // #ifndef NO_DISPLAY
	}
    ~Image();
    
    // save Image as PNM file.  Redefined for each image type.
    virtual void save_pnm(char *filename = NULL) = 0;
    
    virtual void clear(unsigned char fill_char);
    
    // get pointer to pixel
    inline unsigned char *get_pixel(int x, int y) const
	{
	    assert (x >= 0);
	    assert (x < (unsigned) width);
	    assert (y >= 0);
	    assert (y < (unsigned) height);
	    assert (data != NULL);
	    assert (end_data > data);  // pointer arithmetic
    
	    return data + ypoints[y] + (x << bpp_shift);
	}

    inline bool check_coords(int x, int y) const
	{ 
	    return (x >= 0) && (x < (unsigned) width) && (y >= 0) && (y < (unsigned) height);
	}
    
    inline bool check_coords(unsigned int x, unsigned int y) const
	{ 
	    return (x < width) && (y < height);
	}
    
    inline bool check_coords(const realno &x, const realno &y) const
	{ 
	    return check_coords((int) (x+.5), (int) (y+.5));
	}

    inline unsigned char *nearest_pixel(realno x, realno y) const
	{
	    return get_pixel(real_to_int(x), real_to_int(y));
	}
    
    void get_pixel_coords(unsigned char *pnt, unsigned int &x, unsigned int &y) const;

    void draw_in_image();
    // lrectread the screen pixels
    void read_image();
    
    
    // VIRTUAL FUNCTIONS 
    
    // *new* graphics routines
    
    // virtual graphics routines
    virtual void set_draw_colour(unsigned char red, 
				 unsigned char geen, 
				 unsigned char blue) {}
    
    virtual void set_draw_colour(unsigned char grey) {}
    
    virtual void draw_horizontal(unsigned int y, unsigned int xl, 
				 unsigned int xr, bool dotted = false) = 0;
    
    virtual void draw_vertical(unsigned int y, unsigned int xl, 
			       unsigned int xr, bool dotted = false) = 0;
    
    virtual void plot_pixel(unsigned int x, unsigned int y) = 0;
    
    // base class graphics routines
    
    void draw_filled_circle(int x0, int y0, int r);
    
    void set_line_width(realno w)
	{
	    DrawLineWidth = w;
	}
    
    void draw_line(int x0, int y0, int x1, int y1);
    
    inline void draw_line(const realno &x0, const realno &y0, const realno &x1, const realno &y1)
	{
	    draw_line((int) (x0+.5), (int) (y0+.5), (int) (x1+.5), (int) (y1+.5));
	}

    static const int CIRCLE_PRECISION;
    void draw_circle(int xc, int yc, int r);
    
    // draw a filled concave polygon into the image
    void draw_filled_polygon(int nvertices, Point2 *vertices);
    
    // some more drawing functions from ActiveModel.cc (!)  FIXME: check reduncancy --- nts 2002
#ifdef USE_GL  // no non-GL versions
    // GL drawing for debugging output
    static inline void move2(const Point2 &p)
	{
#ifndef NO_DISPLAY
	    ::move2(p.x, p.y);
#endif
	}
    
    static inline void draw2(const Point2 &p)
	{
#ifndef NO_DISPLAY
	    setlinestyle(0);
	    ::draw2(p.x, p.y);
#endif
	}
    
    static inline void dotted_draw2(Point2 &p)
	{
#ifndef NO_DISPLAY
	    // deflinestyle(1, 0xff00);
	    setlinestyle(1);
	    ::draw2(p.x, p.y);
	    setlinestyle(0);
#endif   // #ifndef NO_DISPLAY
	}
    
    static inline void rect(Point2 &p1, Point2 &p2)
	{
#ifndef NO_DISPLAY
	    rectf(p1.x, p1.y, p2.x, p2.y);
#endif
	}
    static inline void circ(Point2 &p, realno r)
	{
#ifndef NO_DISPLAY
	    circf(p.x, p.y, r);
#endif
	}

#endif   // #ifdef USE_GL
    
    // misc virtual functions
    
    // (lrect)read the displayed screen pixels to get an RGB32Image
    virtual RGB32Image *rgb_read_image(RGB32Image *res = NULL);
    
    virtual long display(long window = NULLWIN) = 0;
    
    virtual void clear_border() = 0; 
    
    // crude resample 
    virtual Image *resample(unsigned int xstep, unsigned int ystep, Image *r = NULL) = 0;
    
    // create a physical copy of the image, copying image data, dimensions, time.
    // NB the window handle (in GL, variable glwin) is not copied over!
    virtual Image *copy(Image *r = NULL) const = 0;
    
    // return a new image of same type and dimensons
    virtual Image *copy_type(unsigned int w = 0, unsigned int h = 0) = 0;
    
    // virtual_copy -- returns a new wrapper around the same image data
    // (not a physical copy)
    virtual Image *virtual_copy(Image *res = NULL) const = 0;
    
    ImageType get_image_type() const
	{
	    return image_type;
	}
    
    Image *flip_vertically(Image *r= NULL);
    
    // general image processing functions 
    
    // fcombine - general function of two images
    virtual Image *fcombine(Image *image2, int (*func) (void*, void*),
			    Image *r = NULL);
    
    // difference image (no thresholding)
    virtual Image *difference(Image *image2, Image *r = NULL) = 0;
    
    // quick differencing and thresholding using grid method
    virtual Image *difference(Image *image2, realno threshold, Image *r = NULL) = 0;
    
    // simple differencing and thresholding
    // threshold is always between 0 and 255
    // (the derived class rescales for different image types)
    virtual Image *simple_difference(Image *image2, realno threshold,
				     unsigned int *no_marked, Image *r = NULL) = 0;
    
    // difference image and calculate mean, variance of differences 
    virtual Image *diff_stats(Image *img2, realno &mean, realno &variance,
			      Image *r = NULL);    
    
    // image_blend
    // Result(x,y) = (a * I1(x,y) + b * I2(x,y)) / (a+b)
    virtual Image *image_blend(Image *image2, int a, int b, Image *r = NULL);
    
    // map_intensities
    // use an array to map intensity values
    virtual Image *map_intensities(PntGreyMap intensity_map, 
				   Image *res = NULL);
    
    // convolve with 3x3 integer array (& normalise)
    virtual Image *convolve(Kernel k, Image *r = NULL) = 0;
    
    virtual Image *blur(Image*r = NULL)
	{
	    return convolve(BLUR_KER,r); 
	}
    
    // take n'th of ordered local pixels 
    virtual Image *neighbour_order(unsigned int n, Image *r = NULL) = 0;
    
    // take median of 9 local pixels 
    virtual Image *middle(Image *r = NULL)
	{ 
	    return neighbour_order(5, r);
	}
    
    // take minimum of 9 local pixels 
    virtual Image *minimum(Image *r = NULL)
	{
	    return neighbour_order(1, r);
	}
    
    // take maximum of 9 local pixels 
    virtual Image *maximum(Image *r = NULL)
	{
	    return neighbour_order(9, r);
	}
    
    // fmed - fast middle filter 
    virtual Image *fmed(Image *r = NULL);
    
    // sobel edge detection       
    virtual Image *sobel(unsigned int threshold, Image *r = NULL) = 0;
    
    // sobel filter, don't threshold 
    virtual Image *sobel(Image *r = NULL) = 0;
    
    // threshold image 
    virtual Image *threshold(unsigned int threshold, Image *r = NULL, 
			     unsigned int *no_marked = NULL) = 0;
    
    // halve width, height and blur 
    virtual Image *half_blur( Image *r = NULL);    
    
    // mask image -- mask out image pixels
    virtual Image *mask(Image *mask, Image *r = NULL) = 0;
    
    
    // extract and clear the subimage  - uses top-left as origin 
    virtual Image *extract_subimage(int xmin, int xmax, int ymin, int ymax, 
				    Image *r = NULL);
    
    virtual void paste_subimage(unsigned int xmin, unsigned int xmax, 
				unsigned int ymin, unsigned int ymax, Image *sub);
    
    Image *get_subimage(unsigned int xmin, unsigned int xmax,
			unsigned int ymin, unsigned int ymax, Image *sub = NULL);
    
    virtual Image *to_rgb(Image *r = NULL);
    
    virtual void draw_rectangle(int xmin, int xmax, int ymin, int ymax, int val);
    
    // Transform image (translate, rotate and scale) into a new image.
    // WARNING: Source & destination images must be of the same type.
    // (Added by T Heap)
    
    virtual Image *transform(int centre_x, int centre_y, realno angle,
			     realno scale, Image *r = NULL);
    
    // add noise to image
    // returns noise (square sum)
    
#ifdef _SVID_SOURCE
    // the following uses SVID 48-bit random numbers...
    virtual Image *add_gaussian_noise(realno sd,  realno &noise, Image *r = NULL);
#endif
    
    virtual realno sum_square_pixels(int zero_value = 0);
    virtual realno sum_pixels();
    
    // weird and wonderful ...
    //
    // median_img_array
    // pixelwise "median" over array of images
    // storing result in *this
    virtual void median_img_array(Image**, int );
    
    // plane project - pass the inverse mapping m00 ..., m22
    Image *plane_project(
	const realno m00, const realno m01, const realno m02,
	const realno m10, const realno m11, const realno m12,
	const realno m20, const realno m21, const realno m22,
	Image *res = NULL);
    
    // colour filtering of image to grey levels
    virtual Image *ColourFilter(Image *res = NULL,
				ColourFilteringMethod method = CF_METHOD_Y_709);
    
    // colour distance in HSV space to grey level
    virtual Image *ColourDistance(Image *res = NULL,
				  ColourDistanceMethod = CD_METHOD_V_WEIGHTED_HS);    
    
    
#ifdef HSV
    // convert image to HSV32Image
    virtual Image *Image::to_HSV32(Image *res);    
#endif
    
protected:
    // private helpers
    typedef struct
    {		
	realno x;	
	realno dx;	
	int i;	
    } Edge;
    
    static Point2 *pt;
    
    // 2 comparison routines for qsort
    static int compare_ind(const void *u, const void *v)
	{
	    return pt[*(int*)(u)].y <= pt[*(int*)(v)].y ? -1 : 1;
	}
    static int compare_active(const void *u, const void *v)
	{
	    return ((Edge*)(u))->x <= ((Edge*)(v))->x ? -1 : 1;
	}
    
    void poly_delete(int i, int &nact, Edge *active);
    void poly_insert(int i, int y, int nvert, int &nact, Edge *active);
    
};

} // namespace ReadingPeopleTracker

#endif