Sunteți pe pagina 1din 23

/*****************************************************

Program name: coins_detect


Description:
read an input image and find US coins in this
image, count this coins
Usage:
coins_detect
To compile (on a Sun workstation):
g++ -Wall -o coins_detect coins_detect.c -ltiff
*****************************************************/
#include
#include
#include
#include
#include

<stdio.h>
<string.h>
<math.h>
<stdlib.h>
<tiffio.h>

#define d1
n in pixels
#define d5
n in pixels
#define d10
in in pixels
#define d25
in in pixels
#define t1
oin
#define t5
oin
#define t10
coin
#define t25
coin
#define size_connect
regions_connect
#define size_search
search_maximum
#define sig
canny edge detector
#define th
edge detector
#define tl
edge detector
#define GV
#define pi
struct edge
nd direction
{
double mag;
int dr, dc;
};

169

// diameter of the 1 cent coi

185

// diameter of the 5 cent coi

153

// diameter of the 10 cent co

205

// diameter of the 25 cent co

80

// threshold for the 1 cent c

90

// threshold for the 5 cent c

80

// threshold for the 10 cent

90

// threshold for the 25 cent

// 1/2 of size of squares for

20

// 1/2 of size of squares for


2

// sigma for the

100

// higher threshold for canny

40

// lower threshold for canny

256
3.141592654

// number of gray values


// value of pi
// struct to hold magnitude a
// of edges

void canny_edge_detect (unsigned char *in_image, double *out_image, float sigma,


float tlow,
float thigh, uint32 rows, uint32
columns);
void print_error (char *err_message);
void gaussian_filtering (unsigned char *in, double *out, float sigma, uint32 row

s,
void
void
void
ns);
void
nt32

uint32 columns);
roberts (double *in, struct edge *out, uint32 rows, uint32 columns);
scale (struct edge *in, uint32 rows, uint32 columns);
suppress_nonmaxima (struct edge *in, double *out, uint32 rows, uint32 colum

follow_edge (uint32 er, uint32 ec, double *in, double *out, uint32 rows, ui
columns,
float tlow);
void hough_transform_circles (double *in, int *hough_space, uint32 rows, uint32
columns);
void hough_threshold (int *hough_space, uint32 rows, uint32 columns);
void regions_connect (int *hough_space, int *hough_connect, uint32 rows, uint32
columns);
void hough_label (int *hough_space, int *hough_connect, int label, int *sum, dou
ble *rc,
double *cc, int *n, uint32 r, uint32 c, int i,
uint32 rows, uint32 columns);
void search_maximum (int *hough_space, uint32 rows, uint32 columns);
float count_coins (int *hough_space, uint32 rows, uint32 columns);
void generate_output_image(unsigned char *in_image, unsigned char *out_image, in
t *hough_space, uint32 rows, uint32 columns);
int main()
{
uint32 r;
uint32 c;
uint32 rows;
image
uint32 columns;
mage
uint16 BitsPerSample;
mage
uint16 SamplesPerPixel;
uint16 PhotoMetric;
le image
unsigned char *in_image;
ray
unsigned char *out_image;
rray
TIFF *in_filep;
mage file
TIFF *out_filep;
int check_io;
char input[20];
char in_name[24];
char out_name[28];
char mess[55];
double *tmp1_image;
int *hough_space;
ugh transform
int *hough_connect;
e Hough space
int label;
applied
int sum;
ough space

// row index
// column index
// number of rows in
// number of columns in i
// normally 8 for grayscale i
// normally 1 for grayscale image
// normally 1 for graysca
// pointer for input image ar
// pointer for output image a
// handle for input i
// handle for output image file
// status of I/O operation
// input string
// input file name
// output file name
// error message
// holds temporary image 1
// parameter space for the Ho
// holds the components of th
// belonging together
// holds the next label to be
// to a connected component
// sum of the values in the H

int n;
to one component
int i;
in the Hough space
double rc, cc;
e centroid
uint32 r_centroid, c_centroid;
e centroid
float coins;
s

// input of the input file name


printf("Input file name (without .tif):
scanf("%s", input);
strcpy(in_name, input);
strcat(in_name, ".tif");
strcpy(out_name, input);
strcat(out_name, "_out.tif");

// belonging to one component


// number of pixels belonging
// parameter for the diameter
// row and column index of th
// row and column index of th
// value of the detected coin

");

// Open input image file


in_filep = TIFFOpen(in_name, "r");
if (in_filep == NULL)
{
strcpy(mess, "Could not open input file ");
strcat(mess, in_name);
print_error (mess);
}
// Open output image file
out_filep = TIFFOpen (out_name, "w");
if (out_filep == NULL)
{
strcpy(mess, "Could not open output file ");
strcat(mess, out_name);
print_error (mess);
}
// Determine the size of the input image
TIFFGetField(in_filep, TIFFTAG_IMAGELENGTH, &rows);
TIFFGetField(in_filep, TIFFTAG_IMAGEWIDTH, &columns);
TIFFGetField(in_filep, TIFFTAG_BITSPERSAMPLE, &BitsPerSample);
TIFFGetField(in_filep, TIFFTAG_SAMPLESPERPIXEL, &SamplesPerPixel);
TIFFGetField(in_filep, TIFFTAG_PHOTOMETRIC, &PhotoMetric);
// Specify TIFF header fields for output image
TIFFSetField(out_filep, TIFFTAG_IMAGELENGTH, rows);
TIFFSetField(out_filep, TIFFTAG_IMAGEWIDTH, columns);
TIFFSetField(out_filep, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(out_filep, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(out_filep, TIFFTAG_PHOTOMETRIC, 1);
TIFFSetField(out_filep, TIFFTAG_PLANARCONFIG, 1);
// Allocate memory to hold image arrays

in_image = (unsigned char *) _TIFFmalloc(rows*columns);


if (in_image == NULL)
print_error ("Could not allocate memory!");
out_image = (unsigned char *) _TIFFmalloc(rows*columns);
if (out_image == NULL)
print_error ("Could not allocate memory!");
tmp1_image = (double *) calloc(rows*columns, sizeof(double));
if(tmp1_image == NULL)
print_error ("Could not allocate memory!");
// Allocate memory to hold Hough spaces
hough_space = (int *) calloc(4*rows*columns, sizeof(int));
if(hough_space == NULL)
print_error ("Could not allocate memory!");
hough_connect = (int *) calloc(4*rows*columns, sizeof(int));
if(hough_connect == NULL)
print_error ("Could not allocate memory!");
// Read image pixel values from file, row by row
for (r = 0; r < rows; r++)
{
check_io = TIFFReadScanline(in_filep, &in_image[r*columns], r, 1);
if (check_io != 1)
print_error ("Could not read image from file!");
}
///////////////////////
// Process the image //
///////////////////////
// detect edges using a canny edge detector
canny_edge_detect (in_image, tmp1_image, sig, tl, th, rows, columns);
// applying the Hough transform for circles
hough_transform_circles (tmp1_image, hough_space, rows, columns);
// set values less than or equal to the threshold to 0
hough_threshold (hough_space, rows, columns);
// connect the regions in the Hough space
regions_connect (hough_space, hough_connect, rows, columns);
// label the regions and compute centroid and add the values
// in the Hough space belonging to these region
printf("labeling\n");
label = 0;
for (i = 0; i < 4; i++)
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
if (hough_connect[i*rows*columns+r*columns+c] ==
-1)
{
label++;
rc = 0;
cc = 0;
sum = 0;
n = 0;
hough_label (hough_space, hough_connect,
label, &sum, &rc, &cc, &n,

r, c, i, rows, columns)
;
r_centroid = rc;
c_centroid = cc;
hough_space[i*rows*columns+r_centroid*co
lumns+c_centroid] = sum;
}
// search for maximum
search_maximum (hough_space, rows, columns);
// count coins
coins = count_coins (hough_space, rows, columns);
printf("\n");
printf("detected value:
printf("\n");

%.2f $\n", coins);

// generate output image


generate_output_image(in_image, out_image, hough_space, rows, columns);
// Write output image to file, row by row
for (r = 0; r < rows; r++)
{
check_io = TIFFWriteScanline(out_filep, &out_image[r*columns], r, 1);
if (check_io != 1)
print_error ("Could not write image to file!");
}
// Deallocate the image memory, close file streams, and exit
_TIFFfree(in_image);
_TIFFfree(out_image);
free(tmp1_image);
free(hough_space);
free(hough_connect);
TIFFClose(in_filep);
TIFFClose(out_filep);
printf("ready\n");
exit (0);
return 0;
}

/*****************************************************
Function name: canny_edge_detect
Description:
detects edges in an input image using a Canny edge
detector and stores the result in an output image
Input parameters:
in_image
-- pointer to input image
out_image
-- pointer to output image
rows
-- number of rows
columns
-- number of columns
Returned value:
none

*****************************************************/
void canny_edge_detect (unsigned char *in_image, double *out_image, float sigma,
float tlow,
float thigh, uint32 rows, uint32
columns)
{
uint32 r;
// row index
uint32 c;
// column index
double *tmp1_image;
// holds temporary image 1
struct edge *tmp2_image;
// holds temporary image 2
// allocate memory to hold temporary images
tmp1_image = (double *) calloc(rows*columns, sizeof(double));
if(tmp1_image == NULL)
print_error ("Could not allocate memory!");
tmp2_image = (struct edge *) calloc(rows*columns, sizeof(struct edge));
if(tmp2_image == NULL)
print_error ("Could not allocate memory!");
// initialize output image
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
out_image[r*columns+c] = 0;
// applying of the Gaussian mask to the image
gaussian_filtering (in_image, tmp1_image, sigma, rows, columns);
// computing of magnitude and direction of edges using the Roberts operator
roberts (tmp1_image, tmp2_image, rows, columns);
// scale the temporary image
scale (tmp2_image, rows, columns);
// suppress nonmaxima
suppress_nonmaxima (tmp2_image, tmp1_image, rows, columns);
// edge detect
printf("edge detect\n");
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
if(tmp1_image[r*columns+c] >= thigh)
// if pixel val
ue over the higher threshold,
follow_edge(r, c, tmp1_image, out_image, rows, c
olumns, tlow); // follow the edge
// deallocate the memory
free(tmp1_image);
free(tmp2_image);
}
/*****************************************************
Function name: print_error
Description:
Print an error message, and exit the program.
Input parameters:
err_message -- pointer to string to be printed
Returned value:
none

*****************************************************/
void print_error (char *err_message)
{
fprintf(stderr, "Error: %s\n", err_message);
exit (1);
}
/*****************************************************
Function name: gaussian_filtering
Description:
applies a Gaussian filter to an image
Input parameters:
in
-- pointer to input image
out
-- pointer to output image
sigma
-- sigma of the gaussian mask
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void gaussian_filtering (unsigned char *in, double *out, float sigma, uint32 row
s,
uint32 columns)
{
uint32 r;
// row index
uint32 c;
// column index
int hr, hc;
// holds the indexes used for the
computation
float sum;
// result of the Gaussian fil
ter at one pixel
int s;
// size of the Gaussian filter
int x;
// coordinate for Gaussian ma
sk
int gc;
// column index of the Gaussi
an mask
double *g_filter;
// holds the mask for the Gaussia
n filter
double *tmpg_image;
// holds temporary image
// calculate the size of the for the Gaussian filter
s = 8*sqrt(2)*sigma;
if (div(s,2).rem == 0)
s = s+1;
if (((s+1)/2 > 2*rows) || ((s+1)/2 > 2*columns))
print_error ("Gaussian mask too large!");
printf("size of the Gaussian filter:

%d X %d\n", s, s);

// allocate memory
tmpg_image = (double *) calloc(rows*columns, sizeof(double));
if(tmpg_image == NULL)
print_error ("Could not allocate memory!");
g_filter = (double *) calloc(s, sizeof(double));
if(g_filter == NULL)
print_error ("Could not allocate memory!");
printf("computing the Gaussian mask\n");

// compute the mask for the Gaussian filter


for (gc = 0; gc < s; gc++)
{
x = gc - (s-1)/2;
g_filter[gc]= 1/(sqrt(2*pi) * sigma) * exp(-pow(x,2) / (2*pow(sigma,
2)));
}
printf("applying the Gaussian mask\n");
// applying of the Gaussian mask to the image
// horizontal
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
{
sum = 0;
for (gc = 0; gc < s; gc++)
{
hc = c + gc - (s-1)/2;

// in

if (hc < 0)

// if

dex of the input image


the index is not in the input
hc = -hc -1;

/ image, reflect the image (virtually)


if (hc > (columns - 1))
hc = columns -(hc-columns) -1;
sum += g_filter[gc] * in[r*columns+hc];

// result of the

Gaussian
}
// mask at one pixel
tmpg_image[r*columns+c] = sum;
result to an temporary image
}

// storing the

// vertical
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
{
sum = 0;
for (gc = 0; gc < s; gc++)
{
hr = r + gc - (s-1)/2;
if (hr < 0)

// if

the index is not in the input


hr = -hr -1;

/ image, reflect the image (virtually)


if (hr > (rows - 1))
hr = rows -(hr-rows) -1;
sum += g_filter[gc] * tmpg_image[hr*columns+c]; // result o
f the Gaussian
}

// mask at one pixel


out[r*columns+c] = sum;
result to the output image
}

// storing the

// deallocate memory
free(tmpg_image);
free(g_filter);
}
/*****************************************************
Function name: roberts
Description:
applies Roberts operator to an image and stores
the magnitude and dirction in an output image
Input parameters:
in
-- pointer to input image
out
-- pointer to output image
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void roberts (double *in, struct edge *out, uint32 rows, uint32 columns)
{
uint32 r;
// row index
uint32 c;
// column index
int hr, hc;
// holds the indexes used for the
computation
float sum1, sum2;
// result of the Roberts oper
ator at one pixel
double alpha;
// holds the angle
int rr, rc;
// row and column index of th
e Roberts operator
const int roberts1[2][2]
// holds the 1. Roberts operator
= {{1,0},{0,-1}};
const int roberts2[2][2]
// holds the 2. Roberts operator
= {{0,-1},{1,0}};
printf("computing magnitude and direction\n");
// computing of magnitude and direction of edges using the Roberts operator
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
{
sum1 = 0;
sum2 = 0;
for (rr = 0; rr < 2; rr++)

// indexes

of the Roberts operator


for (rc = 0; rc < 2; rc++)
{
hc = c + rc;
indexes of the temporary image
hr = r + rr;
if (hc > (columns -1))

//

hc = columns - 1;
if (hr > (rows -1))
hr = rows - 1;
sum1 += roberts1[rr][rc] * in[hr*columns
+hc]; // results of applying
sum2 += roberts2[rr][rc] * in[hr*columns
+hc]; // the Roberts operators
}
out[r*columns+c].mag = sqrt(pow(sum1,2)+pow(sum2,2)); /
/ storing the magnitude
// to tempora
ry image 2
if (sum2 != 0)

// calculation of t

he direction
alpha = atan(sum1/sum2);
else
alpha = pi/2;
if ((alpha < -3*pi/8) || (alpha >= 3*pi/8)) // storing
the direction to temporary
{
// image 2
in terms of +1, 0, -1
out[r*columns+c].dr = 1;
// for rows and c
olumns
out[r*columns+c].dc = 1;
// => 4 direction
s between -pi/2 and +pi/2
}
if ((alpha >= -3*pi/8) && (alpha < -pi/8))
{
out[r*columns+c].dr = 1;
out[r*columns+c].dc = 0;
}
if ((alpha >= -pi/8) && (alpha < pi/8))
{
out[r*columns+c].dr = 1;
out[r*columns+c].dc = -1;
}
if ((alpha >= pi/8) && (alpha < 3*pi/8))
{
out[r*columns+c].dr = 0;
out[r*columns+c].dc = -1;
}
}
}
/*****************************************************
Function name: scale
Description:
scales an image
Input parameters:
in
-- pointer to input image
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void scale (struct edge *in, uint32 rows, uint32 columns)

{
uint32 r;
uint32 c;
double scale_factor;
double max_val;
temporary images

// row index
// column index
// scaling factor
// hold the maximal value of the

printf("scaling\n");
// scale the temporary image
max_val = 0;

// initialization of maximum value

for (r = 0; r < rows; r++)


// calcultion of the maximum value
for (c = 0; c < columns; c++)
if (in[r*columns+c].mag > max_val)
max_val = in[r*columns+c].mag;
scale_factor = (GV - 1)/max_val;
for (r = 0; r < rows; r++)
// scaling of the tempo
rary image 2
for (c = 0; c < columns; c++)
in[r*columns+c].mag = in[r*columns+c].mag * scale_factor
;
}
/*****************************************************
Function name: suppress_nonmaxima
Description:
suppresses the non maximum values
Input parameters:
in
-- pointer to input image
out
-- pointer to output image
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void suppress_nonmaxima (struct edge *in, double *out, uint32 rows, uint32 colum
ns)
{
uint32 r;
// row index
uint32 c;
// column index
int hr, hc;
// holds the indexes used for the
computation
printf("suppress nonmaxima\n");
// suppress nonmaxima
for (r = 0; r < rows; r++)
ary images
for (c = 0; c < columns; c++)
{
hc = c + in[r*columns+c].dc;
in the direction
hr = r + in[r*columns+c].dr;
if (hc < 0)

// indexes of the tempor

// indexes of the pixel


// of the gradient

hc = 0;
if (hc > (columns -1))
hc = columns - 1;
if (hr < 0)
hr = 0;
if (hr > (rows -1))
hr = rows - 1;
if (in[r*columns+c].mag <= in[hr*columns+hc].mag) // su
ppress nonmaxima
out[r*columns+c] = 0;
else
out[r*columns+c] = in[r*columns+c].mag;
hc = c - in[r*columns+c].dc;

// indexes of the pixel

hr = r - in[r*columns+c].dr;

// of the gradient

in the directon
if (hc < 0)
hc = 0;
if (hc > (columns -1))
hc = columns - 1;
if (hr < 0)
hr = 0;
if (hr > (rows -1))
hr = rows - 1;
if (in[r*columns+c].mag <= in[hr*columns+hc].mag) // su
ppress nonmaxima
out[r*columns+c] = 0;
}
}
/*****************************************************
Function name: follow_edge
Description:
follows an edge in an input image and prints
this edge to an output image (has to be initialized)
Input parameters:
er
-- row
ec
-- column
in
-- pointer to input image
out
-- pointer to output image
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void follow_edge (uint32 er, uint32 ec, double *in, double *out, uint32 rows, ui
nt32 columns,
float tlow)
{
int hr, hc;
// row and column index
out[er*columns+ec] = GV-1;
hr = er + 1;

// Pixel gets highest value

if (hr < rows)


// test all neigbors, if their values are over t
he threshold,
{
// then follow this edge
hc = ec + 1;
if (hc < columns)
if ((in[hr*columns+hc] >= tlow) && (out[hr*columns+hc] !
= GV-1))
follow_edge (hr, hc, in, out, rows, columns, tlo
w);
hc = ec;
if ((in[hr*columns+hc] >= tlow) && (out[hr*columns+hc] != GV-1))
follow_edge (hr, hc, in, out, rows, columns, tlow);
hc = ec - 1;
if (hc >= 0)
if ((in[hr*columns+hc] >= tlow) && (out[hr*columns+hc] !
= GV-1))
follow_edge (hr, hc, in, out, rows, columns, tlo
w);
}
hr = er - 1;
if (hr >= 0)
{
hc = ec + 1;
if (hc < columns)
if ((in[hr*columns+hc] >= tlow) && (out[hr*columns+hc] !
= GV-1))
follow_edge (hr, hc, in, out, rows, columns, tlo
w);
hc = ec;
if ((in[hr*columns+hc] >= tlow) && (out[hr*columns+hc] != GV-1))
follow_edge (hr, hc, in, out, rows, columns, tlow);
hc = ec - 1;
if (hc >= 0)
if ((in[hr*columns+hc] >= tlow) && (out[hr*columns+hc] !
= GV-1))
follow_edge (hr, hc, in, out, rows, columns, tlo
w);
}
hr = er;
hc = ec + 1;
if (hc < columns)
if ((in[hr*columns+hc] >= tlow) && (out[hr*columns+hc] != GV-1))
follow_edge (hr, hc, in, out, rows, columns, tlow);
hc = ec - 1;
if (hc >= 0)
if ((in[hr*columns+hc] >= tlow) && (out[hr*columns+hc] != GV-1))
follow_edge (hr, hc, in, out, rows, columns, tlow);
}
/*****************************************************
Function name: hough_transform_circles
Description:

applies the Hough transform for circles on an


image and stores the result in a 3D array
holding the
Hough space
Input parameters:
in
-- pointer to input image
hough_space -- pointer to the 3D array holding
the Hough space
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void hough_transform_circles (double *in, int *hough_space, uint32 rows, uint32
columns)
{
int r;
// row index
int c;
// column index
int rh;
// row index of the Hough spa
ce
int ch;
// column index of the Hough
space
int i;
// diameter index of the Houg
h space
int chmin, chmax;
// minimum and maximum values
of the column value
// in the Hough space
const int d[4] = {d10, d1, d5, d25};

// array holding the diameter

s
printf("performing the Hough transform\n");
// initialize the Hough space
for (rh = 0; rh < rows; rh++)
for (ch = 0; ch < columns; ch++)
for (i = 0; i < 4; i++)
hough_space[i*rows*columns+rh*columns+ch] = 0;
// perform the Hough transform
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
if (in[r*columns+c] == (GV-1))
// compute a circle
for every pixel in the
for (i = 0; i < 4; i++)
// edge image
{
chmin = c - d[i]/2;
// minimum c
olumn value of the circle
chmax = c + d[i]/2;
// maximum c
olumn value of the circle
if (chmin < 0)

// column va

lues of the circle must


chmin = 0;

// lie i

nside the Hough space


if (chmax >= columns)
chmax = columns - 1;
for (ch = chmin; ch <= chmax; ch++)
/ compute the circle

{
if (((ch-c) <= d[i]/2) && ((c-ch
) <= d[i]/2))
{
rh = r + sqrt(pow(d[i]/2
, 2) - pow(ch-c, 2));
if (rh < rows)
hough_space[i*ro
ws*columns+rh*columns+ch]
= hough_spac
e[i*rows*columns+rh*columns+ch] +1;
rh = r - sqrt(pow(d[i]/2
, 2) - pow(ch-c, 2));
if (rh >= 0)
hough_space[i*ro
ws*columns+rh*columns+ch]
= hough_spac
e[i*rows*columns+rh*columns+ch] +1;
}
}
}
}
/*****************************************************
Function name: hough_threshold
Describtion:
sets the values less than or equal to
the threshold to 0
Input parameters:
hough_space -- pointer to the 3D array holding
the Hough space
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void hough_threshold (int *hough_space, uint32 rows, uint32 columns)
{
uint32 r;
// row index
uint32 c;
// column index
int i;
// index for the diameters of the circles
const int t[4] = {t10, t1, t5, t25};
// holds the different threshold
s for the
// different diameters
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
for (i = 0; i < 4; i++)
if (hough_space[i*rows*columns+r*columns+c] <= t
[i])
hough_space[i*rows*columns+r*columns+c]
= 0;
}

/*****************************************************
Function name: regions_connect
Description:
connect the regions in the Hough space by placing
a square labeled -1 over every pixel in the
Hough space being larger than 0, the result is
stored in hough_connect
Input parameters:
hough_space -- pointer to the 3D array holding
the Hough space
hough_connect -- pointer to the 3D array holding
the conncted Hough space
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void regions_connect (int *hough_space, int *hough_connect, uint32 rows, uint32
columns)
{
uint32 r;
// row index
uint32 c;
// column index
int i;
// index for the diameters of the circles
uint32 rs, cs;
// row a
nd column index of the squares
uint32 rs_min, rs_max;
// minimum and m
aximum index (row)
uint32 cs_min, cs_max;
// minimum and m
aximum index (column)
const int size = size_connect;
// 1/2 of size of the sq
uares
printf("connect regions\n");
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
for (i = 0; i < 4; i++)
if (hough_space[i*rows*columns+r*columns+c] != 0
)
{
rs_min = r - size;
quare must lie inside the Hough space
if (rs_min < 0)
rs_min = 0;
rs_max = r + size;
if (rs_max >= rows)
rs_max = rows - 1;
cs_min = c - size;
if (cs_min < 0)
cs_min = 0;
cs_max = c + size;
if (cs_max >= columns)
cs_max = columns - 1;

// the s

for (rs = rs_min; rs <= rs_max; rs++)


for (cs = cs_min; cs <= cs_max;
cs++)
hough_connect[i*rows*col
umns+rs*columns+cs] = -1;
}
}
/*****************************************************
Function name: hough_label
Description:
label the connected regions in hough_connect,
add the values in the Hough space belonging to
these regions, compute the centroid of each region
and write the value to the centroids of these
regions
Input parameters:
hough_space -- pointer to the 3D array holding
the Hough space
hough_connect -- pointer to the 3D array holding
the conncted Hough space
label
-- label to apply to the region
r
-- row index of the current pixel
c
-- column index of the current pixel
i
-- diameter index of the current
pixel
rows
-- number of rows
columns
-- number of columns
Returned values:
*sum
-- sum of the values in the
Hough space belonging to the
region
*rc
-- row index of the centroid
*cc
-- column index of teh centroid
*n
-- number of pixels belonging to
region
*****************************************************/
void hough_label (int *hough_space, int *hough_connect, int label, int *sum, dou
ble *rc,
double *cc, int *n, uint32 r, uint32 c, int i,
uint32 rows, uint32 columns)
{
uint32 rh, ch;
// row a
nd column index
hough_connect[i*rows*columns+r*columns+c] = label;
the label
*sum = *sum + hough_space[i*rows*columns+r*columns+c]; //
um
*rc = (*rc**n+r)/(*n+1);
// compute
of the centroid
*cc = (*cc**n+c)/(*n+1);
// compute
dex of the centroid
*n = *n+1;
te the number of pixels belonging to that region
hough_space[i*rows*columns+r*columns+c] = 0; // set used pixel
space to 0

// apply
compute the s
the row index
the column in
// compu
in the Hough

//
//
rh
ch
if

look at the 4-neighbors


if neighbor belongs to the region, then call function again
= r;
= c+1;
(ch >= columns)
ch = columns-1;
if (hough_connect[i*rows*columns+rh*columns+ch] == -1)
hough_label (hough_space, hough_connect, label, &*sum, &*rc, &*c
c, &*n, rh, ch, i,
rows, columns);
ch = c-1;
if (ch < 0)
ch = 0;
if (hough_connect[i*rows*columns+rh*columns+ch] == -1)
hough_label (hough_space, hough_connect, label, &*sum, &*rc, &*c
c, &*n, rh, ch, i,
rows, columns);
ch = c;
rh = rh+1;
if (rh >= rows)
rows = rows-1;
if (hough_connect[i*rows*columns+rh*columns+ch] == -1)
hough_label (hough_space, hough_connect, label, &*sum, &*rc, &*c
c, &*n, rh, ch, i,
rows, columns);
rh = rh-1;
if (rh < 0)
rows = 0;
if (hough_connect[i*rows*columns+rh*columns+ch] == -1)
hough_label (hough_space, hough_connect, label, &*sum, &*rc, &*c
c, &*n, rh, ch, i,
rows, columns);
}
/*****************************************************
Function name: search_maximum
Description:
compares the value at one layer in the Hough space
with the values nearby in the other layers by
comparing the value with the values in a square
region around this pixel in the other layers,
non maximum values are deleted
Input parameters:
hough_space -- pointer to the 3D array holding
the Hough space
rows
-- number of rows
columns
-- number of columns
Returned value:
none
*****************************************************/
void search_maximum (int *hough_space, uint32 rows, uint32 columns)
{
uint32 r;
// row index
uint32 c;
// column index

int i;
// index for the diameter (layer)
int j;
// index for the diameters
uint32 rs, cs;
nd column indexes of the square region
uint32 rs_min, rs_max;
square region
uint32 cs_min, cs_max;
square region
const int size = size_search;
uare region

// row a
// border of the
// border of the
// 1/2 of size of the sq

printf("searching for maximum\n");


for (i = 0; i < 4; i++)
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
if (hough_space[i*rows*columns+r*columns+c] != 0
)
{
rs_min = r - size;

// squar

e region must lie inside the Hough space


if (rs_min < 0)
rs_min = 0;
rs_max = r + size;
if (rs_max >= rows)
rs_max = rows - 1;
cs_min = c - size;
if (cs_min < 0)
cs_min = 0;
cs_max = c + size;
if (cs_max >= columns)
cs_max = columns - 1;
for (rs = rs_min; rs <= rs_max; rs++)
// search in the region
for (cs = cs_min; cs <= cs_max;
cs++)
for (j = i+1; j < 4; j++
)
if (hough_space[
i*rows*columns+r*columns+c]
< hough_
space[j*rows*columns+rs*columns+cs])
hough_sp
ace[i*rows*columns+r*columns+c] = 0;
else
hough_sp
ace[j*rows*columns+rs*columns+cs] = 0;
}
}
/*****************************************************
Function name: count_coins
Description:
counts the coins detected in the Hough space
Input parameters:

hough_space

-- pointer to the 3D array holding


the Hough space
-- number of rows
-- number of columns

rows
columns
Returned value:
value of the detected coins
*****************************************************/
float count_coins (int *hough_space, uint32 rows, uint32 columns)
{
uint32 r;
// row index
uint32 c;
// column index
int i;
// index of the diameters
int n;
// number of coins
float count;
// detected value
const float value[4] = {0.10, 0.01, 0.05, 0.25}; // holds the values of
the different coins
printf("counting coins\n");
printf("\n");
count = 0;
// search in Hough space
// if coin detected, add value to count
for (i = 0; i < 4; i++)
{
n = 0;
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
if (hough_space[i*rows*columns+r*columns+c] != 0
)
n++;
count += n * value[i];
printf("number of coins %.2f $:

%d\n", value[i], n);

}
printf("\n");
return count;
}
/*****************************************************
Function name: generate_output_image
Description:
counts the coins detected in the Hough space
Input parameters:
in_image
-- pointer to the input image
out_image
-- pointer to the output image
hough_space -- pointer to the 3D array holding
the Hough space
rows
-- number of rows
columns
-- number of columns

Returned value:
none
*****************************************************/
void generate_output_image(unsigned char *in_image, unsigned char *out_image, in
t *hough_space, uint32 rows, uint32 columns)
{
uint32 r;
// row index
uint32 c;
// column index
int i;
// index of the diameters
uint32 hr, hc;
// indexes for the template
uint32 hr_min, hc_min;
// maxim
al and minimum values for the template
const int number[4][24][26]
// holds
the templates for the numbers
= {{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1},
{1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,1,1,1},
{1,1,1,1,1,0,0,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,1,1,1},
{1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1},
{1,1,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}},
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}},
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}},
{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1},
{1,1,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1},
{1,1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1},
{1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1},
{1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1},
{1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1},
{1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1},
{1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1},
{1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,1,1,1,1},
{1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1},
{1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}};
// write input image in output image

for (r = 0; r < rows; r++)


for (c = 0; c < columns; c++)
out_image[r*columns+c] = in_image[r*columns+c];
// write value numbers belonging to detected coins in output image
for (i = 0; i < 4; i++)
for (r = 0; r < rows; r++)
for (c = 0; c < columns; c++)
{
if (hough_space[i*rows*columns+r*columns+c] != 0
)
{
hr_min = r - 12;
hc_min = c - 13;
if (hr_min >= rows)
hr_min = rows - 25;
if (hr_min < 0)
hr_min = 0;
if (hc_min >= columns)
hr_min = columns - 27;
if (hc_min < 0)
hc_min = 0;
for (hr = hr_min; hr < hr_min+24; hr++)
for (hc = hc_min; hc < hc_min+26
; hc++)
if((hr >= 0) && (hr < ro
ws) && (hc >= 0) && (hc < columns))
out_image[hr*col
umns+hc] = (GV-1) * number[i][hr-r+12][hc-c+13];
}
}
}

S-ar putea să vă placă și