home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
vis-ftp.cs.umass.edu
/
vis-ftp.cs.umass.edu.tar
/
vis-ftp.cs.umass.edu
/
pub
/
Software
/
ASCENDER
/
umass_foa.tar
/
mdt_NEW
/
foa
/
foa.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-21
|
16KB
|
510 lines
/* =============================================================
foa: Classifies a color (RGB) image based on the
multivariate decision tree represented in the lookup table.
The result is a binary image with the 'target' regions,
along with the coordinates for those regions.
Usage is as follows:
foa lookup_table_file(input) color_image(input) result_image(output)
Shashi Buluswar
Computer Vision Laboratory
Dept of Computer Science
University of Massachusetts
Amherst, MA 01003
Copyright 1995, University of Massachusetts - Amherst
=============================================================== */
#define MAIN
#include <foa.h>
/* ====================================================================
Morphological operations on binary image. Eight-neighbor expansion/
contraction, based on NUM_NEIGH_EXP, NUM_NEIGH_CON, which define the
number of neighbors that have to be on or off for the pixel to be
turned on or off. NOTE: the corner neighbors have been commented out.
Feel free to add them back if it helps in the imagery being used.
==================================================================== */
void ImgMorph (int flag, char *img_arr)
{
int i, j, num_pos_neighbors;
for (i=1; i<(imgNumR-1); i++) {
for (j=1; j<(imgNumC-1); j++) {
num_pos_neighbors = 0;
/*if (img_arr[(((i-1)*imgNumC)+(j-1))] == BIT_ON) num_pos_neighbors ++;*/
if (img_arr[(((i-1)*imgNumC)+j)] == BIT_ON) num_pos_neighbors ++;
/*if (img_arr[(((i-1)*imgNumC)+(j+1))] == BIT_ON) num_pos_neighbors ++;*/
if (img_arr[(((i)*imgNumC)+(j-1))] == BIT_ON) num_pos_neighbors ++;
if (img_arr[(((i)*imgNumC)+(j+1))] == BIT_ON) num_pos_neighbors ++;
/*if (img_arr[(((i+1)*imgNumC)+(j-1))] == BIT_ON) num_pos_neighbors ++;*/
if (img_arr[(((i+1)*imgNumC)+(j))] == BIT_ON) num_pos_neighbors ++;
/*if (img_arr[(((i+1)*imgNumC)+(j+1))] == BIT_ON) num_pos_neighbors ++;*/
if (flag == 1) {
if (num_pos_neighbors > NUM_NEIGH_EXP)img_arr[((i*imgNumC)+j)]=BIT_ON;
}
else if (flag == 0){
if (num_pos_neighbors < NUM_NEIGH_CON)img_arr[((i*imgNumC)+j)]=BIT_OFF;
}
}
}
}
/* ====================================================
BEGIN: code for extracting bounding rectangle
==================================================== */
int left_bound (int i, int j, char *img_arr)
{
if ((img_arr[(i*imgNumC)+j]==BIT_ON) &&
(img_arr[(i*imgNumC)+(j+1)]==BIT_ON) &&
(img_arr[(i*imgNumC)+(j-1)]==BIT_OFF))
return (1);
else return (0);
}
int right_bound (int i, int j, char *img_arr)
{
if ((img_arr[(i*imgNumC)+j]==BIT_ON) &&
(img_arr[(i*imgNumC)+(j+1)]==BIT_OFF) &&
(img_arr[(i*imgNumC)+(j-1)]==BIT_ON))
return (1);
else return (0);
}
int top_bound (int i, int j, char *img_arr)
{
if ((img_arr[(i*imgNumC)+j]==BIT_ON) &&
(img_arr[((i-1)*imgNumC)+j]==BIT_OFF) &&
(img_arr[((i+1)*imgNumC)+j]==BIT_ON))
return (1);
else return (0);
}
int bott_bound (int i, int j, char *img_arr)
{
if ((img_arr[(i*imgNumC)+j]==BIT_ON) &&
(img_arr[((i-1)*imgNumC)+j]==BIT_ON) &&
(img_arr[((i+1)*imgNumC)+j]==BIT_OFF))
return (1);
else return (0);
}
int bound_pixel (int i, int j, char *img_arr)
{
if ((left_bound(i,j,img_arr)==1)||
(right_bound(i,j,img_arr)==1)||
(top_bound(i,j,img_arr)==1)||
(bott_bound(i,j,img_arr)==1))
return (1);
else return (0);
}
void extend_rect (int i, int j,
short int *beg_r, short int *beg_c,
short int *end_r, short int *end_c,
int num_regions)
{
/*=== if previous boundary of region can be extended, do so ===*/
if (beg_r[num_regions] > i) beg_r[num_regions] = i;
if (beg_c[num_regions] > j) beg_c[num_regions] = j;
if (end_r[num_regions] < i) end_r[num_regions] = i;
if (end_c[num_regions] < j) end_c[num_regions] = j;
}
int col_overlap(int i, int j,
short int *beg_c, short int *end_c)
{
if ((end_c[i]>end_c[j]) && (end_c[j]>beg_c[i]))
return (1);
else return(0);
}
int row_overlap(int i, int j,
short int *beg_r, short int *end_r)
{
if ((end_r[i]>end_r[j]) && (end_r[j]>beg_r[i]))
return (1);
else return(0);
}
void ExtractBoundRect (char *img_arr,
short int *beg_r, short int *beg_c,
short int *end_r, short int *end_c)
{
int num_regions=0; /* # regions in the binary classified image */
int i, j, tmp_i, tmp_j, x, y, reg_area;
int trace_done;
short int bound_pix_list_i[1000], pix_ctr_i=0, bound_pix_list_j[1000], pix_ctr_j=0;
char *pix_proc_LUT; /* LUT for marking processed pixels in boundary extraction
if LUT[x][y] == 0, then [x][y] done,
else not */
num_regions = 0; /* init # regions found */
int SIZE=20, GROW=20; /* for malloc & realloc */
short int *tmp_beg_r, *tmp_beg_c, *tmp_end_r, *tmp_end_c, ctr_tmp;
pix_proc_LUT = (char *)malloc(sizeof(char)*imgNumC*imgNumR);
beg_r = (short int *) malloc(sizeof(short int)*GROW);
beg_c = (short int *) malloc(sizeof(short int)*GROW);
end_r = (short int *) malloc(sizeof(short int)*GROW);
end_c = (short int *) malloc(sizeof(short int)*GROW);
SIZE = GROW;
for (i=0; i<imgNumR; i++)
for (j=0; j<imgNumC; j++) {
if ((bound_pixel(i,j,img_arr)==1)&&
(pix_proc_LUT[(i*imgNumC)+j]!=DONE)) { /* found a boundary pixel -- start trace */
tmp_i=i; tmp_j=j;
pix_proc_LUT[(tmp_i*imgNumC)+tmp_j]=DONE;
trace_done=0;
beg_r[num_regions]=tmp_i;
beg_c[num_regions]=tmp_j;
end_r[num_regions]=tmp_i;
end_c[num_regions]=tmp_j;
while (trace_done != 1) {
for (x=tmp_i-1; x<=tmp_i+1; x++) /* list of unexplored boundary pixels*/
for (y=tmp_j-1; y<=tmp_j+1; y++) {
if (pix_proc_LUT[(x*imgNumC)+y]!=DONE)
if (bound_pixel(x,y,img_arr)==1) {
bound_pix_list_i[pix_ctr_i]=x;
bound_pix_list_j[pix_ctr_i]=y;
pix_ctr_i++; pix_ctr_j++;
}
}
if (pix_ctr_i==0) trace_done=1; /* if no unexplored bound-pixels, then done */
else {
pix_ctr_i--; tmp_i=bound_pix_list_i[pix_ctr_i];
pix_ctr_j--; tmp_j=bound_pix_list_j[pix_ctr_j];
pix_proc_LUT[(tmp_i*imgNumC)+tmp_j]=DONE;
extend_rect(tmp_i, tmp_j, beg_r, beg_c, end_r, end_c, num_regions);
}
}
reg_area = ((end_r[num_regions]-beg_r[num_regions])*
(end_c[num_regions]-beg_c[num_regions]));
if ((reg_area > MIN_REG_SIZE)&&(reg_area < MAX_REG_SIZE) &&
((end_r[num_regions]-beg_r[num_regions])>MIN_REG_X) &&
((end_c[num_regions]-beg_c[num_regions])>MIN_REG_Y) &&
((end_r[num_regions]-beg_r[num_regions])<MAX_REG_X) &&
((end_c[num_regions]-beg_c[num_regions])<MAX_REG_Y)) {
num_regions++;
if (num_regions >SIZE) {
beg_r = (short int *) realloc(beg_r, sizeof(short int)*(SIZE+GROW));
beg_c = (short int *) realloc(beg_c, sizeof(short int)*(SIZE+GROW));
end_r = (short int *) realloc(end_r, sizeof(short int)*(SIZE+GROW));
end_c = (short int *) realloc(end_c, sizeof(short int)*(SIZE+GROW));
SIZE += GROW;
}
}
}
}
free((void *)(pix_proc_LUT));
free((void *)(beg_r)); free((void *)(beg_c)); free((void *)(end_r)); free((void *)(end_c));
/* print coordinates of bounding rectangle after inverting them */
for (x=0; x<num_regions; x++) {
reg_area = ((end_r[x]-beg_r[x])*(end_c[x]-beg_c[x]));
beg_r[x]=imgNumR-beg_r[x];
end_r[x]=imgNumR-end_r[x];
beg_c[x]=imgNumC-beg_c[x];
end_c[x]=imgNumC-end_c[x];
/* ATTN: IF USING TIFF IMAGES, DO NOT USE THE NEXT FOUR LINES */
beg_r[x]=imgNumR-beg_r[x];
end_r[x]=imgNumR-end_r[x];
beg_c[x]=imgNumC-beg_c[x];
end_c[x]=imgNumC-end_c[x];
printf ("region#%d: %dx%d - %dx%d; area: %d\n",
x, beg_c[x], beg_r[x], end_c[x], end_r[x], reg_area);
}
printf ("\nchecking for overlapping regions...\n");
for (i=0; i<num_regions; i++) {
for (j=0; j<num_regions; j++) {
if ((col_overlap(i, j, beg_c, end_c) && row_overlap(i, j, beg_r, end_r)) ||
(col_overlap(i, j, beg_c, end_c) && row_overlap(j, i, beg_r, end_r)) ||
(col_overlap(j, i, beg_c, end_c) && row_overlap(i, j, beg_r, end_r)) ||
(col_overlap(j, i, beg_c, end_c) && row_overlap(j, i, beg_r, end_r))) {
printf ("regions %d & %d overlap\n", i, j);
if (beg_c[i] < beg_c[j]) beg_c[j]=0;
else {
beg_c[i]=beg_c[j];
beg_c[j]=0;
}
if (end_c[i] > end_c[j]) end_c[j]=0;
else {
end_c[i]=end_c[j];
end_c[j]=0;
}
if (beg_r[i] < beg_r[j]) beg_r[j]=0;
else {
beg_r[i]=beg_r[j];
beg_r[j]=0;
}
if (end_r[i] > end_r[j]) end_r[j]=0;
else {
end_r[i]=end_r[j];
end_r[j]=0;
}
}
}
}
tmp_beg_r = (short int *) malloc(sizeof(short int)*num_regions);
tmp_beg_c = (short int *) malloc(sizeof(short int)*num_regions);
tmp_end_r = (short int *) malloc(sizeof(short int)*num_regions);
tmp_end_c = (short int *) malloc(sizeof(short int)*num_regions);
/* remove zeroed out regions */
ctr_tmp=0;
for (x=0; x<num_regions; x++) {
if (((end_r[x]-beg_r[x])*(end_c[x]-beg_c[x])) != 0) {
tmp_beg_r[ctr_tmp]=beg_r[x];
tmp_beg_c[ctr_tmp]=beg_c[x];
tmp_end_r[ctr_tmp]=end_r[x];
tmp_end_c[ctr_tmp]=end_c[x];
ctr_tmp++;
}
}
beg_r=tmp_beg_r; beg_c=tmp_beg_c; end_r=tmp_end_r; end_c=tmp_end_c;
printf ("\nfinal regions...\n");
for (x=0; x<ctr_tmp; x++)
printf ("region#%d: %dx%d - %dx%d\n",
x, beg_c[x], beg_r[x], end_c[x], end_r[x]);
}
/* ====================================================
Load images from corresponding files
==================================================== */
int ReadImages(char *RGB_IMG)
{
TokenIStream RGBStream; /* ISR RGB input stream */
Token *rgb; /* ISR RGB token */
RGBStream.MatchFormatToFilename(RGB_IMG);
RGBStream.open(RGB_IMG);
if (!RGBStream) {
printf ("unable to open file %s\n", RGB_IMG);
return (-1);
}
rgb = RGBStream.read_token_ptr();
if (strcmp(rgb->name(), "ColorImage") != 0) {
printf ("ERROR - %s is not a color image...\n", RGB_IMG);
return (-2);
}
else {
RImg = (BytePlane *) ((ColorImage*)rgb)->red();
GImg = (BytePlane *) ((ColorImage*)rgb)->green();
BImg = (BytePlane *) ((ColorImage*)rgb)->blue();
return (0);
}
}
/* =====================================================
dec2bin: convert a decimal number to binary: for
unpacking bytes read from LUT-file
===================================================== */
void dec2bin (int ascDec, int bitArr[CHAR_SIZE])
{
int i;
int tmpNum;
tmpNum=ascDec;
for (i=CHAR_SIZE-1; i>=0; i--) {
bitArr[i] = tmpNum%2;
tmpNum = tmpNum/2;
}
}
/* =====================================================
Load a color image
Pixelwise classify it
Store the result as a BytePlane
===================================================== */
int ReadAndClassifyImage (char *RGB_IMG, char *RESULT_IMG)
{
TokenOStream OStream; /* ISR output stream */
int i, j, iR, iG, iB, PixClass, irow, icol, byte_idx;
unsigned char LUT_char;
int LUT_dec, bitArr[CHAR_SIZE];
char *img_arr;
int StartCol, StartRow, EndCol, EndRow; /* image coordinates */
short int *beg_r, *beg_c, *end_r, *end_c; /* coordiates for target regions */
int posCount=0;
printf ("Reading input image...\n");
if (ReadImages(RGB_IMG)!=0) printf ("ERROR reading images\n");
printf ("DONE reading input image...\n");
/* open and initialize output stream */
OStream.MatchFormatToFilename(RESULT_IMG);
OStream.open(RESULT_IMG);
if (!OStream) {
printf ("unable to open file %s\n", RESULT_IMG);
return(-1);
}
((BytePlane *)RImg)->GetMinMax (StartCol, EndCol, StartRow, EndRow);
imgNumR = (EndRow-StartRow+1);
imgNumC = (EndCol-StartCol+1);
printf ("Image min-max: %d-%d x %d-%d, size: %d x %d\n",
StartRow, EndRow, StartCol, EndCol, imgNumR, imgNumC);
img_arr = (char *)malloc(sizeof(char)*imgNumC*imgNumR);
result = new BytePlane(*RImg);
printf ("Starting pixel classification...\n");
/* ========================================================
get pixel RGB
if it's outside the range, class = 0
if it's within range, look it up.
======================================================== */
for (i=StartRow, irow=0; i<=EndRow; i++, irow++) {
for (j=StartCol, icol=0; j<=EndCol; j++, icol++) {
iR = RImg->pixel(j,i);
iG = GImg->pixel(j,i);
iB = BImg->pixel(j,i);
if ((iR<=RGB_min)||(iR>=RGB_max)||
(iG<=RGB_min)||(iG>=RGB_max)||
(iB<=RGB_min)||(iB>=RGB_max))
PixClass = 0;
else {
iR=iR-RGB_min; iG=iG-RGB_min; iB=iB-RGB_min;
byte_idx = (((iR*iRange*iRange) + (iG*iRange) + iB)/CHAR_SIZE);
LUT_char = LUT[byte_idx];
LUT_dec = (int)LUT_char;
if (LUT_dec==0) PixClass = 0;
else {
if (LUT_dec==255) PixClass = 1;
else {
dec2bin(LUT_dec, bitArr);
PixClass = bitArr[byte_idx%CHAR_SIZE];
}
}
}
img_arr[(irow*imgNumC)+icol] = PixClass;
if (PixClass ==1) posCount++;
}
}
printf ("DONE with pixel classification\n");
printf ("Total target pixels: %d\n", posCount);
/* =====================================================================
series of morph operations -- sequence/number of ops is arbitrary --
for the Ft. Carson images, the following sequence seemed to work
best.
===================================================================== */
printf ("Starting morphological operations...\n");
ImgMorph (1, img_arr);
ImgMorph (1, img_arr);
ImgMorph (1, img_arr);
ImgMorph (0, img_arr);
ImgMorph (0, img_arr);
printf ("DONE performing morphological operations...\n");
printf ("Writing output image...\n");
for (i=StartRow, irow=0; i<=EndRow; i++, irow++) {
for (j=StartCol, icol=0; j<=EndCol; j++, icol++) {
result->pixel(j, i) = img_arr [(irow*imgNumC)+icol]*255;
}
}
OStream << result;
printf ("DONE writing output image...\n");
/* === extract the bounding rectangles for target regions === */
printf ("Extracting bounding rectangles\n");
ExtractBoundRect (img_arr, beg_r, beg_c, end_r, end_c);
printf ("ALL DONE...\n");
free ((void *) img_arr);
return (0);
}
/* =========================================================
Load the lookup table from LUT_file and store in LUT[][][]
========================================================== */
int read_LUT_from_file (char *file_name)
{
FILE *LUT_file_ptr;
if ((LUT_file_ptr = fopen (file_name, "rb")) == NULL) {
printf ("fopen error; exiting...\n");
return (-1);
}
else {
fread (LUT, sizeof(char), ARR_SIZE, LUT_file_ptr);
return(0);
}
}
main (int argc, char *argv[])
{
char *RGB_IMG, *RESULT_IMG; /* image filenames */
/* === show usage === */
if (argc != 4) {
fprintf(stdout, "\nusage: foa LUT_file RGBImage ResultImage\n");
return (-1);
}
/* === load lookup table === */
printf ("Reading LUT from file: %s...\n", argv[1]);
if (read_LUT_from_file (argv[1]) != 0) {
printf ("ERROR reading LUT\n");
return (-2);
}else printf ("DONE reading input LUT\n");
RGB_IMG = argv[2];
RESULT_IMG = argv[3];
/* === load a color image from disk and classify it === */
if (ReadAndClassifyImage(RGB_IMG, RESULT_IMG) != 0) {
printf ("ERROR in classification...bailed out!\n");
return (-3);
}
}