www.pudn.com > hbp0.1.zip > classimage.cpp


/*************************************************************************** 
                          classimage.cpp 
 
  Base class for all images 
 
    begin                : Sat Nov 23 2002 
    copyright            : (C) 2002 by Bob Mottram 
    email                : fuzzgun@btinternet.com 
 ***************************************************************************/ 
 
/*************************************************************************** 
 *                                                                         * 
 *   This program is free software; you can redistribute it and/or modify  * 
 *   it under the terms of the GNU General Public License as published by  * 
 *   the Free Software Foundation; either version 2 of the License, or     * 
 *   (at your option) any later version.                                   * 
 *                                                                         * 
 ***************************************************************************/ 
 
#include  
#include  
#include  
#include  
#include "classimage.h" 
 
 
 
//feature detection stuff 
int OptimalNoOfFeatures; 
 
///  
/// Constructor 
///  
classimage::classimage() 
{ 
  initialised=0; 
  reductionFactor_x=1; 
  reductionFactor_y=1; 
  image=NULL; 
  width=0; 
  height=0; 
  rotationLookup=NULL; 
  OptimalNoOfFeatures=0; 
  topFeature=NULL; 
} 
 
 
///  
/// Destructor 
///  
classimage::~classimage() 
{ 
  int x,y; 
 
  if (image!=NULL) 
  { 
    for (x=0;x 
/// create a new image 
///  
/// Width of the image in pixels 
/// Height of the image in pixels 
void classimage::createImage(int wdth, int hght) 
{ 
  int x,y; 
 
  width = wdth; 
  height = hght; 
 
  image = new unsigned char**[width]; 
  Integral = new long**[width]; 
  for (x=0;x 
/// update the integral image 
///  
void classimage::updateIntegralImage() 
{ 
  int i,x,y,v1,v2,tVal; 
  long p[3],p2[3],textureVal; 
   
  textureVal = 0; 
  for (y = 0;y 0) v2 = image[x - 1][y][0]; else v2 = 0; 
      tVal = abs(v1 - v2); 
      if (y > 0) v2 = image[x][y - 1][0]; else v2 = 0; 
      tVal += abs(v1 - v2); 
      textureVal += tVal; 
       
	  for (i=0;i<3;i++) 
	  { 
        p[i] += image[x][y][i]; 
        p2[i] += tVal; 
	  } 
 
      if (y > 0) 
	  { 
        Integral[x][y][0] = p[0] + Integral[x][y - 1][0]; 
        Integral[x][y][1] = p2[0] + Integral[x][y - 1][1]; 
 
        Integral[x][y][2] = p[1] + Integral[x][y - 1][2]; 
        Integral[x][y][3] = p[2] + Integral[x][y - 1][3]; 
	  } 
      else 
	  { 
        Integral[x][y][0] = p[0]; 
        Integral[x][y][1] = p2[0]; 
        Integral[x][y][2] = p[1]; 
        Integral[x][y][3] = p[2]; 
      } 
	 
	} 
  } 
  Texture = textureVal / (width * height); 
 
} 
 
 
 
 
///  
/// Get the total pixel value for the given area 
///  
/// Top left x coordinate 
/// Top left y coordinate 
/// Bottom right x coordinate 
/// Bottom right y coordinate 
/// An index number corresponding to the type of integral 
long classimage::getIntegral(int tx, int ty, int bx, int by, int index) 
{ 
  return(Integral[bx][by][index] + Integral[tx][ty][index] - (Integral[tx][by][index] + Integral[bx][ty][index])); 
} 
 
 
 
///  
/// Detect different types of feature 
///  
/// Top left x coordinate 
/// Top left y coordinate 
/// Width of the feature 
/// Height of the feature 
/// The type of feature to be detected 
long classimage::detectFeature(int x, int y, int wdth, int hght, int featureType) 
{ 
  long area[4]; 
  long v=0; 
   
  switch(featureType) 
  { 
    case 0:  //A 
	{ 
      area[0] = getIntegral(x, y, x + wdth, y + hght + hght, 0); 
      area[1] = getIntegral(x + wdth, y, x + wdth + wdth, y + hght + hght, 0); 
      v = abs(area[0] - area[1]); 
	  break; 
	} 
 
    case 1:  //B 
	{ 
      area[0] = getIntegral(x, y, x + wdth, y + hght, 0); 
      area[1] = getIntegral(x, y + hght, x + wdth, y + hght + hght, 0); 
      v = abs(area[0] - area[1]); 
	  break; 
	} 
 
    case 2:  //C 
	{ 
      area[0] = getIntegral(x, y, x + wdth, y + hght, 0); 
      area[1] = getIntegral(x + wdth, y, x + wdth + wdth, y + hght, 0); 
      area[2] = getIntegral(x + wdth + wdth, y, x + wdth + wdth + wdth, y + hght, 0); 
      v = abs((area[1] * 2) - (area[0] + area[2])); 
	  break; 
	} 
 
    case 3:  //D 
	{ 
      area[0] = getIntegral(x, y, x + wdth, y + hght, 0); 
      area[1] = getIntegral(x + wdth, y, x + wdth + wdth, y + hght, 0); 
      area[2] = getIntegral(x, y + hght, x + wdth, y + hght + hght, 0); 
      area[3] = getIntegral(x + wdth, y + hght, x + wdth + wdth, y + hght + hght, 0); 
      v = abs((area[1] + area[2]) - (area[0] + area[3])); 
	  break; 
	} 
 
	 
    case 4:  //A 
	{ 
      area[0] = getIntegral(x, y, x + wdth, y + hght + hght, 1); 
      area[1] = getIntegral(x + wdth, y, x + wdth + wdth, y + hght + hght, 1); 
      v = abs(area[0] - area[1]); 
	  break; 
	} 
 
    case 5:  //B 
	{ 
      area[0] = getIntegral(x, y, x + wdth, y + hght, 1); 
      area[1] = getIntegral(x, y + hght, x + wdth, y + hght + hght, 1); 
      v = abs(area[0] - area[1]); 
	  break; 
	} 
 
    case 6:  //C 
	{ 
      area[0] = getIntegral(x, y, x + wdth, y + hght, 1); 
      area[1] = getIntegral(x + wdth, y, x + wdth + wdth, y + hght, 1); 
      area[2] = getIntegral(x + wdth + wdth, y, x + wdth + wdth + wdth, y + hght, 1); 
      v = abs((area[1] * 2) - (area[0] + area[2])); 
	  break; 
	} 
 
    case 7:  //D 
	{ 
      area[0] = getIntegral(x, y, x + wdth, y + hght, 1); 
      area[1] = getIntegral(x + wdth, y, x + wdth + wdth, y + hght, 1); 
      area[2] = getIntegral(x, y + hght, x + wdth, y + hght + hght, 1); 
      area[3] = getIntegral(x + wdth, y + hght, x + wdth + wdth, y + hght + hght, 1); 
      v = abs((area[1] + area[2]) - (area[0] + area[3])); 
	  break; 
	} 
 
 
    case 8:   
	{ 
      v = getIntegral(x, y, x + wdth + wdth, y + hght + hght, 0); 
	  break; 
	} 
 
    case 9:   
	{ 
      v = getIntegral(x, y, x + wdth + wdth, y + hght + hght, 1); 
	  break; 
	} 
 
  } 
   
  return(v); 
} 
 
 
 
 
///  
/// Create feature set for the given sub region 
///  
int classimage::createFeatureList(int tx, int ty, int bx, int by, int &threshold, int resolution_x, int resolution_y, long **result, int &cx, int &cy, bool clearTopFeatures) 
{ 
  float x,y,xinc,yinc; 
  int i,j,winner,hits,xx,yy; 
  long v,vmax,p,pmax,pixels,tmp[6]; 
  bool found; 
  static int initFeatureList=0; 
 
  if (initFeatureList==0) 
  { 
    OptimalNoOfFeatures=50; 
	topFeature = new long*[OptimalNoOfFeatures]; 
	for (i=0;ivmax) 
		{ 
		  vmax = v; 
		  winner=i; 
		} 
	  } 
 
	  if (vmax>threshold) 
	  { 
	    result[p][0] = winner+1; 
	    result[p][1] = (vmax*1000)/pixels; 
		hits++; 
		cx += (int)x; 
		cy += (int)y; 
 
		j=0; 
		found=false; 
		while ((j0) 
  { 
    cx/=hits; 
    cy/=hits; 
  } 
 
  //if no threshold has been given then set an appropriate value 
  if (threshold==0) 
  { 
    pmax=p; 
	vmax=99999999; 
    for (i=0;i0) && (topFeature[i][0]topFeature[i][1]) winner=j; 
 
	if (winner!=i) 
	{ 
	  for (j=0;j<6;j++) 
	    tmp[j] = topFeature[i][j]; 
 
	  for (j=0;j<6;j++) 
	  { 
	    topFeature[i][j] = topFeature[winner][j]; 
		topFeature[winner][j] = tmp[j]; 
	  } 
	} 
  } 
 
 
 
  return(hits); 
} 
 
 
 
 
///  
/// This produces an image based on a specified region within another image.  For example extracting the face region from a picture of a person. 
///  
/// Image object 
/// Top left x coordinate 
/// Top left y coordinate 
/// Bottom right x coordinate 
/// Bottom right y coordinate 
void classimage::sampleFromImage(classimage *example_img, int tx, int ty, int bx, int by) 
{ 
  int x,y,xx,yy,dx,dy,c; 
   
  dx = bx - tx; 
  dy = by - ty; 
   
  for (x = 0;ximage[xx][yy][c]; 
    } 
  } 
   
  updateIntegralImage(); 
} 
 
 
 
///  
/// Returns the average colour within the given region 
///  
/// Top left x coordinate 
/// Top left y coordinate 
/// Bottom right x coordinate 
/// Bottom right y coordinate 
/// Returned average red component 
/// Returned average green component 
/// Returned average blue component 
void classimage::averageColour(int tx, int ty, int bx, int by, int &av_r, int &av_g, int &av_b) 
{ 
  int x,y; 
  long r,g,b,pixels,i; 
   
  pixels = (bx-tx)*(by-ty); 
  r=0; 
  g=0; 
  b=0; 
  i=0; 
  for (x = tx;x 
/// Returns the average intensity within the given region 
///  
/// Top left x coordinate 
/// Top left y coordinate 
/// Bottom right x coordinate 
/// Bottom right y coordinate 
/// Average intensity 
int classimage::getAverageIntensity(int tx, int ty, int bx, int by) 
{ 
  int x,y; 
  long pixels,i; 
   
  pixels = (bx-tx)*(by-ty); 
  i=0; 
  for (x = tx;x 
/// Get image from a bitmap 
///  
/// Bitmap image 
/// The format of the bitmap 
/// Width of the bitmap 
/// Height of the bitmap 
void classimage::updateFromBitmap(BYTE *bmp, int RGBformat, int wdth, int hght) 
{ 
  int x,y,xx,yy; 
  unsigned char r,g,b; 
  int p; 
 
  //create a new image array if necessary 
  if (width==0) createImage(wdth/reductionFactor_x,hght/reductionFactor_y); 
 
  //populate the image array from the bitmap 
  p=0; 
  for (y=0;y 
/// Save the image to a bitmap 
///  
/// Bitmap image 
/// The format of the bitmap 
/// Width of the bitmap 
/// Height of the bitmap 
void classimage::saveToBitmap(BYTE *bmp, int RGBformat, int wdth, int hght) 
{ 
  int x,y,xx,yy; 
  unsigned char r,g,b; 
  int p; 
  int factor; 
 
 
  //create a new image array if necessary 
  if (width==0) createImage(wdth/reductionFactor_x,hght/reductionFactor_y); 
 
  factor = wdth/width; 
 
  p=0; 
  for (y=0;ywidth-1) xx = width-1; 
		if (yy>height-1) yy = height-1; 
         
        r = image[xx][yy][0]; 
        g = image[xx][yy][1]; 
        b = image[xx][yy][2]; 
 
	   
  	    if (RGBformat==0)  //pixels in RGB order 
		{ 
	      bmp[p] = (BYTE)r; p++; 
	      bmp[p] = (BYTE)g; p++; 
	      bmp[p] = (BYTE)b; p++; 
		} 
	    else 
		{ //pixels in BGR order 
	      bmp[p] = (BYTE)b; p++; 
	      bmp[p] = (BYTE)g; p++; 
	      bmp[p] = (BYTE)r; p++; 
		} 
 
      } 
    } 
 
 
  //test pattern 
  /* 
  int pixels = width*height; 
  int p2; 
  for (p=0;p100) p2=0; 
  } 
  */ 
 
} 
 
 
 
 
 
 
///  
/// Random number generator 
///  
/// A random number in the range 0.0 to 1.0 
float classimage::Rnd() 
{ 
  return(rand()/(float)RAND_MAX); 
} 
 
 
///  
/// Update from another image object 
///  
/// Image object 
void classimage::updateFromImage(classimage *img) 
{ 
  int x,y,xx,yy,c; 
 
  if (!initialised) 
    { 
    createImage(img->width/reductionFactor_x,img->height/reductionFactor_y); 
    initialised=true; 
    } 
 
  xx=0; 
  for (x=0;xwidth;x+=reductionFactor_x) 
    { 
    yy=0; 
    for (y=0;yheight;y+=reductionFactor_y) 
      { 
      for (c=0;c<3;c++) image[xx][yy][c] = img->image[x][y][c]; 
      yy++; 
      } 
    xx++; 
    } 
 
  updateIntegralImage(); 
} 
 
 
 
 
///  
/// Rotate the image by 90 degrees 
///  
void classimage::Rotate90() 
{ 
  int x,y,c; 
  unsigned char temp; 
   
  for (x=0;x 
/// Draws a green box 
///  
/// Centre x coordinate 
/// Centre y coordinate 
/// Width of the box 
/// Height of the box 
/// Rotation of the box in degrees 
void classimage::DrawBox(int cx, int cy, int boxwidth, int boxheight,int boxrotation) 
{ 
  int halfwidth = boxwidth/2; 
  int halfheight = boxheight/2; 
  int x,y; 
 
 
  for (y=cy - halfheight;y-1) && (y-1) 
	  { 
		image[cx-halfwidth][y][0]=0; 
		image[cx-halfwidth][y][1]=255; 
		image[cx-halfwidth][y][2]=0; 
	  } 
	  if (cx+halfwidth-1) && (x-1) 
	  { 
		image[x][cy-halfheight][0]=0; 
		image[x][cy-halfheight][1]=255; 
		image[x][cy-halfheight][2]=0; 
	  } 
	  if (cy+halfheight 
/// Rotate the image 
///  
/// The sourec image 
/// The rotation angle in degrees 
void classimage::Rotate(classimage *sourceImage, int angle) 
{ 
  float rot,hyp,ang; 
  int cx,cy,x,y,c,xx,yy; 
 
  if (rotationLookup==NULL) 
  { 
    imageRotation = angle; 
 
	//create the lookup table 
    rotationLookup = new int**[width]; 
    for (x=0;xwidth/2; 
    cy = sourceImage->height/2; 
 
    for (x=0;xwidth;x++) 
	{ 
      for (y=0;yheight;y++) 
	  { 
	    hyp = (float)sqrt(((x-cx)*(x-cx))+((y-cy)*(y-cy))); 
		if (hyp>0) 
		{ 
		  ang = (float)acos((y-cy)/hyp); 
		  if (x-cx>0) ang = (float)((2*3.1415927)-ang); 
	      xx = cx + (int)(hyp * sin(rot-ang)); 
	      yy = cy + (int)(hyp * cos(rot-ang)); 
		} 
		else 
		{ 
          xx=x; 
		  yy=y; 
        } 
 
     	if ((xx>=0) && (xx=0) && (yyimage[xx][yy][c]; 
		} 
	  } 
	} 
 
    //recalculate the integral image 
    updateIntegralImage(); 
  } 
 
} 
 
 
 
///  
/// Flood fill from the given point using the given colour 
///  
void classimage::floodFill(int x, int y, int r, int g, int b, int depth, int &tx, int &ty, int &bx, int &by, long &pixels, long &av_r, long &av_g, long &av_b, classimage *sourceImage) 
{ 
  if ((image[x][y][0]==0) && (image[x][y][1]==0) && (image[x][y][2]==0) && (sourceImage->image[x][y][0]>0) && (depth<2000)) 
  { 
    if (xbx) bx=x; 
	if (yby) by=y; 
 
    av_r += sourceImage->image[x][y][0]; 
	av_g += sourceImage->image[x][y][1]; 
	av_b += sourceImage->image[x][y][2]; 
 
	pixels++; 
 
	if ((r==0) && (g==0) && (b==0)) 
	{ 
	  r=1; 
	  g=1; 
	  b=1; 
	} 
 
    image[x][y][0]=r; 
	image[x][y][1]=g; 
	image[x][y][2]=b; 
 
	if (x>0) 
	{ 
      floodFill(x-1,y,r,g,b,depth+1,tx,ty,bx,by,pixels,av_r,av_g,av_b,sourceImage); 
 
	  if (y>0) 
	  { 
        floodFill(x-1,y-1,r,g,b,depth+1,tx,ty,bx,by,pixels,av_r,av_g,av_b,sourceImage); 
 
		if (x0) 
	{ 
      floodFill(x,y-1,r,g,b,depth+1,tx,ty,bx,by,pixels,av_r,av_g,av_b,sourceImage); 
	} 
 
	if (y 
/// replace one colour with another 
///  
/// The red component of the colour to be replaced 
/// The green component of the colour to be replaced 
/// The blue component of the colour to be replaced 
/// The new red component 
/// The new green component 
/// The new blue component 
void classimage::replaceColour(int r, int g, int b, int new_r, int new_g, int new_b) 
{ 
  int x,y; 
 
  if ((new_r==0) && (new_g==0) && (new_b==0)) 
  { 
    new_r=1; 
	new_g=1; 
	new_b=1; 
  } 
   
  for (x=0;x 
/// Replace one colour with another within the given area 
///  
/// The red component of the colour to be replaced 
/// The green component of the colour to be replaced 
/// The blue component of the colour to be replaced 
/// The new red component 
/// The new green component 
/// The new blue component 
/// Top left x coordinate 
/// Top left y coordinate 
/// Bottom right x coordinate 
/// Bottom right y coordinate 
void classimage::replaceColourArea(int r, int g, int b, int new_r, int new_g, int new_b, int tx, int ty, int bx, int by) 
{ 
  int x,y; 
   
  for (x=tx;x 
/// Filter using the given colour 
///  
long classimage::filterColour(classimage *sourceImage, int r, int g, int b, int tollerance, int ¢re_x, int ¢re_y) 
{ 
  int x,y,dr,dg,db,count; 
  long pixels,cx,cy; 
   
  cx=0; 
  cy=0; 
  pixels=0; 
  count=1; 
  for (x=0;ximage[x][y][0] - r); 
	  dg = abs(sourceImage->image[x][y][1] - g); 
	  db = abs(sourceImage->image[x][y][2] - b); 
 
      if ((drimage[x][y][0]; 
	  g = sourceImage->image[x][y][1]; 
	  b = sourceImage->image[x][y][2]; 
 
	  dr = 2*r; 
	  dg = g+b; 
 
      if ((dr-dg>tollerance) && (dr-dg<100)) 
	  { 
        image[x][y][0] = 255; 
        image[x][y][1] = 255; 
        image[x][y][2] = 255; 
		pixels++; 
		cx += x; 
		cy += y; 
		count++; 
      } 
	  else 
	  { 
        image[x][y][0] = 0; 
        image[x][y][1] = 0; 
        image[x][y][2] = 0; 
	  } 
    } 
  } 
 
  centre_x = cx / count; 
  centre_y = cy / count; 
  updateIntegralImage(); 
 
  return(pixels); 
} 
 
 
 
//------------------------------------------------------------------------------------------------------------------------ 
// 
//------------------------------------------------------------------------------------------------------------------------ 
int classimage::relativeThreshold(int value, int tx, int ty, int bx, int by, int &averageWidth) 
{ 
  int av,pixels,NoOfRows; 
  int x,y,min,hits,rowhits,totrowhits,minrowhits; 
   
  pixels = width * height; 
  hits = 0; 
  av = 0; 
  for (x=0;xminrowhits) 
	{ 
      totrowhits+=rowhits; 
	  NoOfRows++; 
	} 
  } 
  totrowhits /= NoOfRows; 
  averageWidth = (((by-ty) - NoOfRows) + totrowhits)/2; 
   
  return((hits * 100) / pixels); 
} 
 
//------------------------------------------------------------------------------------------------------------------------ 
//returns the 'centre of gravity' for the given region relative to the given colour 
//------------------------------------------------------------------------------------------------------------------------ 
void classimage::CG(int tx, int ty, int bx, int by, unsigned char targ_r, unsigned char targ_g, unsigned char targ_b, int &cx, int &cy, int maxval) 
{ 
  int x,y,p[3],c; 
  long tot,tot_x,tot_y,dp; 
   
  tot = 1; 
  tot_x = 0; 
  tot_y = 0; 
  for (x=tx;x