//***************************************************************************
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h> /* ANSI C standard library routines */
#include <string.h> /* ANSI standard string routines */
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include "image.h"
#include "utils.h"
//***************************************************************************
#define BUF_SIZE 256
//***************************************************************************
GrayImage::GrayImage ( ) // Constructor
{
width = height = numpixels = 0;
for (int i = 0; i < 10; i++)
MaxHist[i] = MinHist[i] = 0;
numMaxHist = numMinHist = 0;
hist = NULL;
mincount = maxcount = 0;
numComponents = 0;
allocateFlag = 0;
}
//***************************************************************************
GrayImage::GrayImage( int h, int w )
{
GrayImage(h, w, 255);
}
//***************************************************************************
GrayImage::GrayImage( int h, int w, int numLev )
{
height = h;
width = w;
numLevels = numLev;
numBits = (int) (log((double) (numLevels+2))/log(2.0));
numpixels = height*width;
for (int i = 0; i < 10; i++)
MaxHist[i] = MinHist[i] = 0;
numMaxHist = numMinHist = 0;
mincount = maxcount = 0;
numComponents = 0;
allocateFlag = 0;
allocateMem( );
}
//***************************************************************************
GrayImage::~GrayImage ( ) // Destructor
{
deAllocateMem( );
}
//***************************************************************************
void GrayImage::deAllocateMem ( )
{
if (!allocateFlag)
return;
if (numpixels)
{
for (int i = 0; i < height; i++)
delete p[i];
delete p;
}
if (hist)
{
delete hist;
hist = NULL;
}
if (numComponents)
{
for (int i = 0; i < numComponents; i++)
delete Phi[i];
delete Phi;
numComponents = 0;
}
allocateFlag = 0;
}
//***************************************************************************
void GrayImage::allocateMem ( )
{
if (allocateFlag)
{
cerr << "allocateMem: Memory already allocated!!" << endl;
return;
}
allocateFlag = 1;
p = new unsigned char *[height];
for (int i = 0; i < height; i++)
{
p[i] = new unsigned char [width];
if (!p[i])
{
cerr << "GrayImage: Not enough memory for allocateMem!!"
<< endl;
exit(-1);
}
for (int j = 0; j < width; j++)
p[i][j] = 0;
}
hist = new int [numLevels+1];
for (int i = 0; i < numLevels+1; i++)
hist[i] = 0;
}
//***************************************************************************
void GrayImage::Init ( )
{
if (!allocateFlag)
allocateMem( );
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
p[i][j] = 0;
for (int i = 0; i < numLevels+1; i++)
hist[i] = 0;
}
//***************************************************************************
void GrayImage::Init (int h, int w, int numLev )
{
if (allocateFlag)
deAllocateMem( );
height = h;
width = w;
numpixels = height*width;
numLevels = numLev;
allocateMem( );
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
p[i][j] = 0;
for (int i = 0; i < numLevels+1; i++)
hist[i] = 0;
}
//***************************************************************************
int GrayImage::isRGB (char *FileName)
{
ifstream inp(FileName);
if (!inp) // Invalid FileName
{
cerr << "Invalid filename: \"" << FileName << "\" does not exist!!"
<< endl;
exit(-1);
}
char a;
inp.read((char *) &a,1);
if (a != 'P') // not a PBM/PGM/PPM image, hence assuming RGB
return 1;
inp.getline(magicNumber,BUF_SIZE);
int flag = 1;
if (!(magicNumber[1] == '6' || magicNumber[1] == '3')) // not RGB image
flag = 0;
return flag;
}
//***************************************************************************
// Read from file in any valid image format recognized by ImageMagick
int GrayImage::ReadFromFile2 (char *FileName)
{
cout << "Reading image from file \"" << FileName << "\":" << endl;
char *tmpfile = convert_image_format(FileName, "ppm");
ReadFromFile(tmpfile);
deleteFile(tmpfile);
return 0;
}
//***************************************************************************
// Read from file in PBM/PGM/PPM format
int GrayImage::ReadFromFile (char *FileName)
{
int i,j;
char buf[BUF_SIZE];
ifstream inp(FileName);
if (!inp) // Invalid FileName
{
cerr << "Invalid filename: \"" << FileName << "\" does not exist!!"
<< endl;
exit(-1);
}
if (!strstr(FileName, "mytmp"))
cout << "Reading image from file \"" << FileName << "\":" << endl;
inp.getline(magicNumber,BUF_SIZE);
inp.getline(buf,BUF_SIZE);
int buflen = strlen(buf);
while (buf[0] == '#' || buflen < 2)
{
inp.getline(buf,BUF_SIZE);
buflen = strlen(buf);
}
width = atoi(buf);
height = atoi(strpbrk(buf, " \t"));
numpixels = height*width;
if (magicNumber[1] == '1' || magicNumber[1] == '4')
numLevels = 1;
else
{
inp.getline(buf,BUF_SIZE);
numLevels = atoi(buf);
}
if (!allocateFlag)
allocateMem( );
numBits = (int) (log((double) (numLevels+2))/log(2.0));
cout << "[" << numBits << "-bit ";
if (magicNumber[1] == '5' || magicNumber[1] == '2') // GrayScale image
{
if (magicNumber[1] == '5') // RAWBITs
{
cout << "GrayScale RAWBITs PGM format]";
for (i = 0; i < height; i++)
inp.read((char *) p[i],width);
}
else // ASCII
{
cout << "GrayScale ASCII PGM format]";
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
{
int pix;
inp >> pix;
p[i][j] = (unsigned char)
(pix / pow( 2, numBits-8 ));
}
}
}
else if (magicNumber[1] == '6' || magicNumber[1] == '3') // RGB image
{
unsigned char rgb[3];
if (magicNumber[1] == '6') // RAWBITs
{
cout << "RGB RAWBITs PPM format]";
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
{
inp.read((char *) rgb,3);
p[i][j] = (unsigned char) (sqrt((double)
(rgb[0]*rgb[0] + rgb[1]*rgb[1]
+ rgb[2]*rgb[2])) /sqrt(3.0));
}
}
else // ASCII
{
cout << "RGB ASCII PPM format]";
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
{
int pix;
for (int k = 0; k < 3; k++)
{
inp >> pix;
rgb[k] = (unsigned char) pix;
}
p[i][j] = (unsigned char) (sqrt((double)
(rgb[0]*rgb[0] + rgb[1]*rgb[1]
+ rgb[2]*rgb[2])) /sqrt(3.0));
}
}
}
else if (magicNumber[1] == '4' || magicNumber[1] == '1') // Binary image
{
if (magicNumber[1] == '4') // RAWBITs
{
cout << "Binary RAWBITs PBM format]";
for (i = 0; i < height; i++)
for (j = 0; j < width; j += 8)
{
unsigned char pix[1];
inp.read((char *) pix,1);
unsigned int x = (int) pix[0];
for (int k = 0; k < 8; k++)
{
int y = x/((int) pow(2,7-k));
if (y)
p[i][j+k] = 0;
else
p[i][j+k] = 255;
x -= y*((int)pow(2,7-k));
}
}
}
else
{
cout << "Binary ASCII PBM format]";
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
{
int pix;
inp >> pix;
if (pix == 0)
p[i][j] = 0;
else
p[i][j] = 255;
}
}
}
inp.close();
cout << endl;
cout << "Width = " << height << endl;
cout << "Height = " << width << endl;
cout << "Numpixels = " << numpixels << endl;
numLevels = 255;
numBits = 8;
magicNumber[1] = '5';
return 0; // No error encountered....successful completion
}
//***************************************************************************
int GrayImage::ReadFromMatrix(Matrix &M)
{
height = M.nx;
width = M.ny;
numpixels = height*width;
numLevels = 255;
numBits = 8;
double minp = 1.0e+300, maxp = -1.0e+300;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
{
if (M.p[i][j] > maxp)
maxp = M.p[i][j];
if (M.p[i][j] < minp)
minp = M.p[i][j];
}
cout << endl;
cout << "Matrix2Image: [Min, Max] for " << height << "x" << width << " matrix = ["
<< minp << "," << maxp << "]" << endl;
cout.flush();
if (!allocateFlag)
allocateMem( );
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
p[i][j] = (unsigned char) (255.0*(M.p[i][j]-minp)/(maxp-minp));
magicNumber[1] = '5';
return 0; // No error encountered....successful completion
}
//***************************************************************************
int GrayImage::WriteToMatrix (Matrix *M)
{
if ((M->nx < height) || (M->ny < width))
{
cerr << "Error: Matrix dimensions [" << M->nx << "x"
<< M->ny
<< "] is not compatible with Image dimension ["
<< height << "x" << width << "] (HxW)!!" << endl;
exit(-1);
}
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
M->p[i][j] = (double) p[i][j];
return 0; // No error encountered....successful completion
}
//***************************************************************************
int GrayImage::WriteToFile(char *FileName, char *fmt)
{
WriteToFile(FileName);
char *tmpfile = convert_image_format(FileName, fmt);
moveFile(tmpfile, FileName);
return 0;
}
//***************************************************************************
int GrayImage::WriteToFile (char *FileName)
{
char buf[BUF_SIZE];
ofstream out(FileName);
if (!out)
return -1; // Invalid Filename
cout << "Writing " << height << "x" << width << " (HxW) image to file \"" <<
FileName << "\"...";
cout.flush();
if (magicNumber[0] == 'P')
out << magicNumber[0] << magicNumber[1] << endl; // For 8-bit GrayScale
else
out << "P5" << endl;
out << "# Created by GrayImage::WriteToFile" << endl;
out << width << " " << height << endl;
out << numLevels << endl;
for (int i = 0; i < height; i++)
out.write((char *) p[i],width);
out.close();
cout << "done!" << endl;
return 0; // No error encountered....successful completion
}
//***************************************************************************
// all pixels above the specified threshold "T" become 255 (white)
void GrayImage::ThresholdWhite (unsigned char T)
{
cout << "Applying threshold for gray level " << (int) T << "....";
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] >= T)
p[i][j] = 255;
cout << "done!" << endl;
}
//***************************************************************************
// all pixels below the specified threshold "T" become 0 (black)
void GrayImage::Threshold (unsigned char T)
{
cout << "Applying threshold for gray level " << (int) T << "....";
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] < T)
p[i][j] = 0;
cout << "done!" << endl;
}
//***************************************************************************
// all pixels below the specified threshold "T1" and above "T2" become 0 (black)
void GrayImage::Threshold (unsigned char T1, unsigned char T2)
{
if (T2 == 0)
T2 = 255;
if (T1 > T2)
{
unsigned char temp = T1;
T1 = T2;
T2 = temp;
}
cout << "Applying threshold for gray levels between " << (int) T1 <<
" and " << (int) T2 << "....";
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] < T1 || p[i][j] > T2)
p[i][j] = 0;
cout << "done!" << endl;
}
//***************************************************************************
void GrayImage::ThresholdBinary (unsigned char T1, unsigned char T2)
{
if (T2 == 0)
T2 = 255;
if (T1 > T2)
{
unsigned char temp = T1;
T1 = T2;
T2 = temp;
}
cout << "Applying binary threshold for gray levels between " << (int) T1 <<
" and " << (int) T2 << "....";
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] < T1 || p[i][j] > T2)
p[i][j] = 0;
else
p[i][j] = 255;
cout << "done!" << endl;
}
//***************************************************************************
void GrayImage::ThresholdBinary (unsigned char T)
{
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] < T)
p[i][j] = 0;
else
p[i][j] = 255;
}
//***************************************************************************
// all pixels above the specified threshold "T" become 0 (black)
void GrayImage::reverseThreshold (unsigned char T)
{
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] >= T)
p[i][j] = 0;
}
//***************************************************************************
// all pixels above the specified threshold "T1" and below "T2" become 0 (black)
void GrayImage::reverseThreshold (unsigned char T1, unsigned char T2)
{
if (T2 == 0)
T2 = 255;
if (T1 > T2)
{
unsigned char temp = T1;
T1 = T2;
T2 = temp;
}
cout << "Applying threshold for all gray levels except those between "
<< (int) T1 << " and " << (int) T2 << "....";
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] >= T1 && p[i][j] <= T2)
p[i][j] = 0;
cout << "done!" << endl;
}
//***************************************************************************
void GrayImage::Histogram ( )
{
cout << "Calculating the histogram.....";
for (int i = 0; i <= numLevels; i++)
hist[i] = 0;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
++hist[p[i][j]];
cout << "done!" << endl;
}
//***************************************************************************
void GrayImage::printHistogram (char *FileName)
{
ofstream out(FileName);
cout << "Writing histogram data for the image to file \""
<< FileName << "\"...";
for (int i = 0; i <= numLevels; i++)
out << i << "\t" << hist[i] << endl;
cout << "done!" << endl;
}
//***************************************************************************
/*
* BEZIER CURVES
* Ref : Mathematical Elements for Computer Graphics
* 2nd Ed. - Rogers and Adams
* pp 295-298.
*
* -Anirudh Modi
*/
//***************************************************************************
void GrayImage::smoothenHistogram ( )
{
int kn, nn, nkn;
double mu, blend, muk, munk;
double *h = new double [numLevels+1];
cout << "Applying Bezier Smoothing to the Histogram...";
cout.flush();
for (int i = 0; i <= numLevels; i++)
{
h[i] = 0.0;
mu = i*1.0/(numLevels+1);
muk = 1.0;
munk = pow( 1.0-mu, numLevels );
for (int k = 0; k <= numLevels; k++)
{
nn = numLevels;
kn = k;
nkn = numLevels - k;
blend = muk * munk;
muk *= mu;
munk /= 1.0 - mu;
while (nn >= 1)
{
blend *= nn;
nn--;
if (kn > 1)
{
blend /= (double) kn;
kn--;
}
if (nkn > 1)
{
blend /= (double) nkn;
nkn--;
}
}
h[i] += hist[k] * blend;
}
hist[i] = (int) h[i];
}
delete h;
cout << "done!" << endl;
cout.flush();
}
//***************************************************************************
void GrayImage::calcHistogramPeaks ( )
{
for (int i = 0; i < 10; i++)
MaxHist[i] = MinHist[i] = 0;
numMaxHist = numMinHist = 0;
mincount = maxcount = 0;
if (hist[0] < hist[1])
MinHist[++numMinHist] = 0;
#define THR 10
for (int i = 1; i < numLevels; i++)
{
if ((hist[i-1] <= hist[i]) && (hist[i+1] < hist[i]))
{
MaxHist[++numMaxHist] = i;
if (numMinHist &&
(MaxHist[numMaxHist] - MinHist[numMinHist] < THR))
--numMinHist;
if (numMaxHist > 1 &&
(MaxHist[numMaxHist] - MaxHist[numMaxHist-1] < THR))
--numMaxHist;
}
else if ((hist[i-1] >= hist[i]) && (hist[i+1] > hist[i]))
{
MinHist[++numMinHist] = i;
if (numMaxHist &&
(MinHist[numMinHist] - MaxHist[numMaxHist] < THR))
--numMaxHist;
if (numMinHist > 1 &&
(MinHist[numMinHist] - MinHist[numMinHist-1] < THR))
--numMinHist;
}
}
if (numLevels - MinHist[numMinHist] > 25)
MinHist[++numMinHist] = numLevels;
int List[20], minmax[20], n = 0, l = 1, m = 1;
while (l <= numMinHist && m <= numMaxHist)
if (MinHist[l] < MaxHist[m])
{
List[n] = MinHist[l++];
minmax[n++] = -1;
}
else
{
List[n] = MaxHist[m++];
minmax[n++] = 1;
}
if (l > numMinHist)
while (m <= numMaxHist)
{
List[n] = MaxHist[m++];
minmax[n++] = 1;
}
else if (m > numMaxHist)
while (l <= numMinHist)
{
List[n] = MinHist[l++];
minmax[n++] = -1;
}
for (int i = 0; i < n-1; i++)
{
if (minmax[i] == minmax[i+1])
{
if (minmax[i] < 0)
List[i+1] = (hist[List[i]] < hist[List[i+1]])
? List[i] : List[i+1];
else
List[i+1] = (hist[List[i]] > hist[List[i+1]])
? List[i] : List[i+1];
minmax[i] = 0;
}
}
numMinHist = numMaxHist = 0;
for (int i = 0; i < n; i++)
if (minmax[i] < 0)
MinHist[++numMinHist] = List[i];
else if (minmax[i] > 0)
MaxHist[++numMaxHist] = List[i];
cout << endl;
for (int i = 1; i <= numMaxHist; i++)
cout << "Maxima " << i << " for histogram is at "
<< MaxHist[i] << " with value of "
<< hist[MaxHist[i]] << endl;
for (int i = 1; i <= numMinHist; i++)
cout << "Minima " << i << " for histogram is at "
<< MinHist[i] << " with value of "
<< hist[MinHist[i]] << endl;
cout << endl;
}
//***************************************************************************
void GrayImage::printHistogramPeaks (char *FileName)
{
ofstream out(FileName);
cout << "Writing histogram peaks for the image to file \""
<< FileName << "\"...";
for (int i = 1; i <= numMinHist; i++)
out << MinHist[i] << "\t" << hist[MinHist[i]] << endl;
out << endl;
for (int i = 1; i <= numMaxHist; i++)
out << MaxHist[i] << "\t" << hist[MaxHist[i]] << endl;
cout << "done!" << endl;
}
//***************************************************************************
int GrayImage::getHistMinima ( )
{
int n;
if (mincount < numMinHist)
n = MinHist[++mincount];
else
n = -1;
return n;
}
//***************************************************************************
int GrayImage::getHistMaxima ( )
{
int n;
if (maxcount < numMaxHist)
n = MaxHist[++maxcount];
else
n = -1;
return n;
}
//***************************************************************************
int GrayImage::getHistMinima ( int i )
{
int n;
if (i <= numMinHist)
n = MinHist[i];
else
n = -1;
return n;
}
//***************************************************************************
int GrayImage::getHistMaxima ( int i )
{
int n;
if (i <= numMaxHist)
n = MaxHist[i];
else
n = -1;
return n;
}
//***************************************************************************
GrayImage &GrayImage::operator= (const GrayImage &I)
{
if (this == &I)
return *this;
height = I.height;
width = I.width;
numpixels = I.numpixels;
numBits = I.numBits;
numLevels = I.numLevels;
mincount = I.mincount;
maxcount = I.maxcount;
numMaxHist = I.numMaxHist;
numMinHist = I.numMinHist;
allocatePhi(I.numComponents);
numComponents = I.numComponents;
for (int i = 0; i < 2; i++)
magicNumber[i] = I.magicNumber[i];
for (int i = 0; i < 10; i++)
{
MaxHist[i] = I.MaxHist[i];
MinHist[i] = I.MinHist[i];
}
if (!allocateFlag)
allocateMem( );
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
p[i][j] = I.p[i][j];
for (int i = 0; i <= numLevels; i++)
hist[i] = I.hist[i];
for (int i = 0; i < numComponents; i++)
for (int j = 0; j < 7; j++)
Phi[i][j] = I.Phi[i][j];
return *this;
}
//***************************************************************************
GrayImage &GrayImage::operator+ (GrayImage &I1)
{
GrayImage *I = new GrayImage;
if ((I1.width == width) && (I1.height == height))
{
*I = I1;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
I->p[i][j] += p[i][j];
for (int i = 0; i <= numLevels; i++)
I->hist[i] += hist[i];
}
else
{
cerr << "operator +: Both images are not of the same size!!" << endl;
exit(-1);
}
return *I;
}
//***************************************************************************
GrayImage &GrayImage::operator- (GrayImage &I1)
{
GrayImage *I = new GrayImage;
if ((I1.width == width) && (I1.height == height))
{
*I = I1;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
I->p[i][j] = p[i][j] - I->p[i][j];
for (int i = 0; i <= numLevels; i++)
{
I->hist[i] = hist[i] - I->hist[i];
if (I->hist[i] < 0)
I->hist[i] = 0;
}
}
else
{
cerr << "operator -: Both images are not of the same size!!" << endl;
exit(-1);
}
return *I;
}
//***************************************************************************
int GrayImage::Perimeter (int F)
//***************************************************************************
// Assumptions:
// Background is 255, foreground is F
// Image does not have any regions of height 1
//***************************************************************************
{
int perimeter = 0;
for (int i = 0; i < height; i++) // checks horizontal borders for
{
if (p[i][0] == F) // foreground pixels
perimeter++;
if (p[i][width-1] == F)
perimeter++;
}
for (int j = 1; j < width-1; j++) // checks vertical borders for
{
if (p[0][j] == F) // foreground pixels
perimeter++; // doesn't double-count corners
if (p[height-1][j] == F)
perimeter++;
}
for (int i = 1; i < height-1; i++) // checks rest of pixels
for (int j = 1; j < width-1; j++) // for borders
{
if ((p[i][j] == F)
&& ((p[i-1][j] == 255) || (p[i+1][j] == 255)
|| (p[i][j-1] == 255) || (p[i][j+1] == 255)))
perimeter++;
}
return perimeter;
}
//***************************************************************************
int GrayImage::LabelComponents ( )
//***************************************************************************
// Assumptions:
// Background is 255, foreground is 0
// Only one region in image
// Image does not have any regions of height 1
//***************************************************************************
{
#define AREA_THRESHOLD 200 // Min area reqd to classify as a component
int num = 0;
cout << "Labeling components....";
// Find connected components
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
if (p[i][j] == 0) // Is this a new component?
{
num++;
p[i][j] = num;
// Assign new label to pixel
FindNeighbors (i,j);
// Recursively find other connected pixels
if (Area(num) < AREA_THRESHOLD)
{
for (int k = 0; k < height; k++)
for (int l = 0; l < width; l++)
if (p[k][l] == num)
p[k][l] = 255;
--num;
}
}
cout << num << " component(s) found....done!" << endl;
for (int k = 1; k <= num; k++)
cout << " Component " << k << ": Area = " << Area(k) <<
", Perimeter = " << Perimeter(k) << endl;
allocatePhi(num);
numComponents = num;
return numComponents;
}
//***************************************************************************
int GrayImage::FindNeighbors (int i, int j)
{
// Check top neighbor
if ((i != 0) && (p[i-1][j] == 0)) // Is top neighbor connected and unmarked?
{
p[i-1][j] = p[i][j]; // If so, mark it
FindNeighbors (i-1,j); // and find its unmarked neighbors
}
// Check bottom neighbor
if ((i != height-1) && (p[i+1][j] == 0)) // Is bottom neighbor
{ // connected and unmarked?
p[i+1][j] = p[i][j]; // If so, mark it
FindNeighbors (i+1,j); // and find its unmarked neighbors
}
// Check left neighbor
if ((j != 0) && (p[i][j-1] == 0)) // Is left neighbor connected and unmarked?
{
p[i][j-1] = p[i][j]; // If so, mark it
FindNeighbors (i,j-1); // and find its unmarked neighbors
}
// Check right neighbor
if ((j != width-1) && (p[i][j+1] == 0)) // Is right neighbor connected
{ // and unmarked?
p[i][j+1] = p[i][j]; // If so, mark it
FindNeighbors (i,j+1); // and find its unmarked neighbors
}
return 0;
}
//***************************************************************************
int GrayImage::Area (int P)
{
int area = 0;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] == P)
++area;
return area;
}
//***************************************************************************
void GrayImage::ConvertToBinary ( )
{
cout << "Converting image to Binary...";
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j])
p[i][j] = 0; // Black foreground
else
p[i][j] = 255; // White background
cout << "done!" << endl;
}
//***************************************************************************
void GrayImage::ReverseBinary ( )
{
cout << "Reversing Binary image...";
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] == 0)
p[i][j] = 255; // Black foreground
else
p[i][j] = 0; // White background
cout << "done!" << endl;
}
//***************************************************************************
int GrayImage::WriteLabelsToFile (char *FileName)
{
char buf[BUF_SIZE];
ofstream out(FileName);
if (!out)
return -1; // Invalid Filename
unsigned int **p2;
p2 = new unsigned int *[height];
for (int i = 0; i < height; i++)
p2[i] = new unsigned int [width];
int interval = 16777215 / numComponents;
// Calculate gray scale gap between objects
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] != 255) // If pixel is labeled,
p2[i][j] = 16777215-p[i][j]*interval;
// then multiply by interval
else
p2[i][j] = 16777215;
cout << "Writing " << height << "x" << width
<< " image to file \"" << FileName << "\"...";
out << "P6" << endl; // For 8-bit GrayScale
out << "# Created by GrayImage::WriteToFile" << endl;
out << height << " " << width << endl;
out << numLevels << endl;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
unsigned char r,g,b;
int P = p2[i][j];
r = P % 256;
g = (P/256) % 256;
b = P / (256*256);
out.write((char *) &r,1);
out.write((char *) &g,1);
out.write((char *) &b,1);
}
delete p2[i];
}
delete p2;
out.close();
cout << "done!" << endl;
return 0; // No error encountered....successful completion
}
//***************************************************************************
double GrayImage::Moment (int x, int y, int P)
{
double moment = 0.0;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] == P)
moment += pow(i,x)*pow(j,y);
return moment;
}
//***************************************************************************
double GrayImage::CentralizedMoment (int x, int y, int P)
{
double moment = 0.0;
double m00 = Moment(0,0,P);
double m10 = Moment(1,0,P);
double m01 = Moment(0,1,P);
int i_c = (int) (m10/m00);
int j_c = (int) (m01/m00);
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] == P)
moment += pow(i-i_c,x)*pow(j-j_c,y);
return moment;
}
//***************************************************************************
double GrayImage::NormalizedCentralMoment (int x, int y, int P)
{
if ((x+y) < 2)
{
cerr << "Normalized Central Moments cannot be computed for p+q < 2!"
<< endl;
exit(-1);
}
double gamma = (x+y)/2.0+1.0;
return CentralizedMoment(x,y,P)/pow(CentralizedMoment(0,0,P),gamma);
}
//***************************************************************************
void GrayImage::InvariantMoments (int P)
{
double n20 = CentralizedMoment(2,0,P);
double n02 = CentralizedMoment(0,2,P);
double n11 = CentralizedMoment(1,1,P);
double n12 = CentralizedMoment(1,2,P);
double n21 = CentralizedMoment(2,1,P);
double n30 = CentralizedMoment(3,0,P);
double n03 = CentralizedMoment(0,3,P);
double phi[8];
phi[1] = n20 + n02;
phi[2] = pow(n20-n02,2) + 4*pow(n11,2);
phi[3] = pow(n30-3*n12,2) + pow(3*n21-n03,2);
phi[4] = pow(n30+n12,2) + pow(n21+n03,2);
phi[5] = (n30-3*n12) * (n30+n12) * (pow(n30+n12,2) - 3*pow(n21+n03,2))
+ (3*n12-n03) * (n21+n03) * (3*pow(n30+n12,2) - pow(n21+n03,2));
phi[6] = (n20-n02) * (pow(n30+n12,2) - pow(n21+n03,2))
+ 4*n11*(n30+n12)*(n21+n03);
phi[7] = (3*n21-n30) * (n30+n12) * (pow(n30+n12,2) - 3*pow(n21+n03,2))
+ (3*n12-n30)*(n21+n03)*(3*pow(n30+n12,2) - pow(n21+n03,2));
for (int i = 1; i <= 7; i++)
phi[i] = log10(fabs(phi[i])+1.0);
cout << "------------------------------------------------" << endl;
cout << "Moment invariants for component " << P << " are:" << endl;
cout << "------------------------------------------------" << endl;
for (int i = 1; i <= 7; i++)
cout << " phi[" << i << "] = " << phi[i] << endl;
cout << "------------------------------------------------" << endl;
for (int i = 0; i < 7; i++)
Phi[P-1][i] = phi[i+1];
}
//***************************************************************************
double GrayImage::getInvariantMoment (int P, int i)
{
return Phi[P-1][i-1];
}
//***************************************************************************
void GrayImage::MinBoundRectangle (int P)
{
int i_min = height, i_max = -1;
int j_min = width, j_max = -1;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] == P)
{
if (i < i_min) i_min = i;
if (i > i_max) i_max = i;
if (j < j_min) j_min = j;
if (j > j_max) j_max = j;
}
cout << " MBR for component " << P
<< " is " << i_max-i_min << "x" << j_max-j_min << " box with area "
<< (i_max-i_min)*(j_max-j_min) << " -> ["
<< i_min << "," << j_min << "] and ["
<< i_max << "," << j_max << "]" << endl;
}
//***************************************************************************
double GrayImage::Elongation (int P)
{
int i_min = height, i_max = -1;
int j_min = width, j_max = -1;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (p[i][j] == P)
{
if (i < i_min) i_min = i;
if (i > i_max) i_max = i;
if (j < j_min) j_min = j;
if (j > j_max) j_max = j;
}
double ratio = (i_max - i_min)*1.0/(j_max-j_min);
if (ratio < 1.0)
ratio = 1.0/ratio;
return ratio;
}
//***************************************************************************
void GrayImage::allocatePhi (int num)
{
if (num == numComponents)
return;
if (numComponents)
{
for (int i = 0; i < numComponents; i++)
delete Phi[i];
delete Phi;
}
Phi = new double *[num];
for (int i = 0; i < num; i++)
Phi[i] = new double [7];
}
//***************************************************************************
void GrayImage::setValue (unsigned char T)
{
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
p[i][j] = T;
}
//***************************************************************************
void WriteMatrixToImageFile(Matrix &M, char *filename)
{
GrayImage img;
img.ReadFromMatrix(M);
img.WriteToFile(filename);
}
//***************************************************************************
void GrayImage::RemoveLonelyPixels(void)
{
for (int i = 1; i < height-1; ++i)
for (int j = 1; j < width-1; ++j)
{
// if all the eight neighbors are unconnected
if (p[i-1][j-1] == 0 && p[i-1][j] == 0 && p[i-1][j+1] == 0
&& p[i+1][j-1] == 0 && p[i+1][j] == 0 && p[i+1][j+1] == 0
&& p[i][j-1] == 0 && p[i][j+1] == 0)
p[i][j] = 0;
}
}
//***************************************************************************
void GrayImage::Zero(void)
{
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
p[i][j] = 0;
}
//***************************************************************************
int GrayImage::isBoundaryPixel(int x, int y)
{
if (p[x][y] == 0)
return 0;
int count = 0;
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
{
int xn = x + i;
int yn = y + j;
if (xn >= 0 && xn < height && yn >=0 && yn < width &&
!(xn == x && yn == y) && p[xn][yn])
++count;
}
if (count == 1)
return 1;
else
return 0;
}
//***************************************************************************