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