/**************************************************************************************/ /* */ /* PROGRAM OBJECT LOCATE */ /* */ /**************************************************************************************/ /* */ /* David A. Hess CS455 Assignment 2 File : obj_locate.c March 17, 1992 */ /* */ /* This program locates and marks up to ten objects within the camera field of view. */ /* Object area, centroid, and angle of least inertia, are stored for each located */ /* object. This data is also displayed to the user terminal and video display. When */ /* viewing the display, objects are numbered top to bottom, left to right. */ /* */ /**************************************************************************************/ #include #include typedef struct { int minx,maxx,miny,maxy; /* object locaters */ int xavg,yavg; /* object centroid */ int area; /* object area */ float theta; /* object AOLI */ } objdata; main() { int result,i; int j,x,y,number,neg,LUTarray[256]; int x1 = 50; /* valid view area */ int x2 = 590; int y1 = 50; int y2 = 430; int bkgnd = 150; /* grey level for binarized image background. Set for approx 2/3 bright white. */ int trace = 255; /* grey level for boarder trace & lines. Set for max white. Note: For program to function properly, bkgnd must be set > 0 and trace must be set at least 5 > bkgnd. Objects are stored as 0 grey level. */ int objcnt; /* number of objects located in valid view area */ int threshold; /* binary threshold level returned by binary_thresh */ objdata object[10]; /* array of up to 10 objects, each having data described in type objdata */ char *header = "Object Area Centroid AOLI"; char *underscore = "------ ---- --------- ------"; char data[29]; /* string to print object data */ char *noobject = "No Objects Found"; VIS$OPEN(); VIS$INIT_FB(); setcamera(0); VIS$INIT_LUTS(); VIS$VIEW(); VIS$FREEZE(); threshold = VIS$OPTIMAL_THRESHOLD(x1,y1,x2,y2,0,trace,5); if (threshold < 120) binarize_inLUT(1,threshold,bkgnd); else { printf("%s\n","Image could not be binarized. Terminating program."); text(180,240,0,2,1536,noobject); VIS$VMASK(3840); VIS$DYNAMIC_OUTLUT(1); VIS$VIEW(); return; } VIS$SELECT_LUT(0,1); VIS$VIEW(); VIS$FREEZE(); VIS$DRAW_BOX(x1,y1,x2,y2,trace,1); result = locate_objects(x1,x2,y1,y2,object,&objcnt,trace,bkgnd); if (result) { for (i=1;i<=objcnt;i++) { printf("%s\n%s\n","Object Area Xavg Yavg Theta", "------ ---- ---- ---- ------"); printf("%4d%7d%5d%5d%7.2f\n\n",i,object[i].area,object[i].xavg, object[i].yavg,object[i].theta); } x = 30; y = 20; for (j=1;j<=objcnt;j++) { /* routine to convert numeric data to ASCII char string */ data[28] = '\0'; i = 27; neg = 0; number = object[j].theta * 100; if (number < 0) { number *= (-1); neg = 1; } while (i > 22) { data[i] = (number % 10) + 48; number /= 10; i--; if (i == 25) { data[i] = '.'; i--; } } if (neg) data[i] = '-'; else data[i] = ' '; i--; data[i] = ' '; i--; data[i] = ')'; i--; number = object[j].yavg; while (i > 16) { data[i] = (number % 10) + 48; number /= 10; i--; } data[i] = ','; i--; number = object[j].xavg; while (i > 12) { data[i] = (number % 10) + 48; number /= 10; i--; } data[i] = '('; i--; data[i] = ' '; i--; number = object[j].area; while (number != 0) { data[i] = (number % 10) + 48; number /= 10; i--; } while (i > 3) { data[i] = ' '; i--; } number = j; while (number != 0) { data[i] = (number % 10) + 48; number /= 10; i--; } while (i >= 0) { data[i] = ' '; i--; } text(x,y,0,1,1792,header); y += 7; text(x,y,0,1,1792,underscore); y += 10; text(x,y,0,1,1792,data); y += 15; } VIS$VMASK(3840); VIS$DYNAMIC_OUTLUT(1); printf("%s","Pausing for inspection of display. Enter to continue."); while (getchar() != '\n'); VIS$VIEW(); } else printf("%s\n","No objects found within valid view area."); } /* end main */ /********************************************************************************/ /* binarize_ inLUT : Routine to binarize input LUT selected by "member". */ /* Object grey level is set to 0. */ /* Background grey level is set to "bkgnd" which should */ /* be set greater than 0 and at least 5 less than trace */ /* for proper operation of "locate_objects" routine. */ /********************************************************************************/ int binarize_inLUT(member,threshold,bkgnd) int member,threshold,bkgnd; { int i; int LUTarray[255]; for (i=0;i<=255;i++) { if (i <= threshold) LUTarray[i] = 0; else LUTarray[i] = bkgnd; } VIS$LOAD_LUT(0,member,LUTarray); } /* end binarize_inLUT */ /*******************************************************************************/ /* locate_objects : Routine to locate multiple objects within the valid */ /* camera view area. Scans from left to right, top to */ /* bottom. When an object is found, Critical data is */ /* calculated and stored, and the object is "boxed" and */ /* scan is resumed. The vertical sides of the box */ /* are drawn at level "trace" - 1. When the scan en- */ /* counters this level, "inbox" flag is toggled, thereby */ /* causing the scan to ignore previously located objects. */ /* */ /* calls : VIS$TRACE_CONTOUR, box_object, centroid_aoi. */ /*******************************************************************************/ int locate_objects(x1,x2,y1,y2,object,objcnt,trace,bkgnd) int x1,x2,y1,y2,*objcnt,trace,bkgnd; objdata *object; { int x,y,dx,result,vert_box_line,inbox,i,xtrace[1000],ytrace[1000]; int boardersize = 4; int found = 0; int parim; unsigned char linepix[640]; *objcnt = 1; dx = x2 - x1; vert_box_line = trace - 1; for (y=y1;y object[*objcnt].maxx) object[*objcnt].maxx = xtrace[i]; else if (xtrace[i] < object[*objcnt].minx) object[*objcnt].minx = xtrace[i]; if (ytrace[i] > object[*objcnt].maxy) object[*objcnt].maxy = ytrace[i]; else if (ytrace[i] < object[*objcnt].miny) object[*objcnt].miny = ytrace[i]; } centroid_aoi(object,objcnt,trace,bkgnd); box_object(object,objcnt,trace,boardersize); *objcnt += 1; found = 1; if (*objcnt == 11) { *objcnt -= 1; return(found); } inbox = 1; brhline(x1,y,dx,linepix); } } } } *objcnt -= 1; return(found); } /* end locate_objects */ /*********************************************************************************/ /* box_object : Routine to draw a box around a located object to exclude the */ /* object from the search. Called by locate_objects. */ /*********************************************************************************/ int box_object(object,objcnt,trace,boardersize) int *objcnt,trace,boardersize; objdata *object; { int length,x1,x2,y1,y2; x1 = object[*objcnt].minx - boardersize; x2 = object[*objcnt].maxx + boardersize; y1 = object[*objcnt].miny - boardersize; y2 = object[*objcnt].maxy + boardersize; length = (object[*objcnt].maxx - object[*objcnt].minx) + 1 + 2 * boardersize; hlclear(x1,y1,length,trace); hlclear(x1,y2,length,trace); length = (object[*objcnt].maxy - object[*objcnt].miny) + 1 + 2 * boardersize; vlclear(x1,y1,length,trace-1); vlclear(x2,y1,length,trace-1); } /* end box_object */ /*********************************************************************************/ /* centroid_aoi : Routine to calculate area, centroid, and angle of least */ /* inertia of a located object. Draws a line through the */ /* centroid on axis of least inertia, and a line through the */ /* centroid perpendicular to axis of least inertia. */ /* Called by locate_objects. */ /*********************************************************************************/ int centroid_aoi(object,objcnt,trace,bkgnd) int *objcnt,trace,bkgnd; objdata *object; { int hsums[480]; int vsums[640]; unsigned char linepix[640]; int x,y,z,dx,dy,xprime,yprime,deltax,deltay,a,b,c,minx,miny,maxx,maxy; float pi = 3.1415927; double a_minus_c,bsquared; minx = object[*objcnt].minx; maxx = object[*objcnt].maxx; miny = object[*objcnt].miny; maxy = object[*objcnt].maxy; a = b = c = 0; dx = (maxx - minx) + 1; dy = (maxy - miny) + 1; object[*objcnt].xavg = object[*objcnt].yavg = object[*objcnt].area = 0; for (y=1;y<=dy;y++) /* calculate hsums[y], y centroid & object area */ { brhline(minx,y+miny-1,dx,linepix); hsums[y] = 0; for (x=1;x<=dx;x++) if (linepix[x-1]!=bkgnd) hsums[y]++; object[*objcnt].yavg += y * hsums[y]; object[*objcnt].area += hsums[y]; } object[*objcnt].yavg /= object[*objcnt].area; for (x=1;x<=dx;x++) /* calculate vsums[x] & x centroid */ { brvline(x+minx-1,miny,dy,linepix); vsums[x] = 0; for (y=1;y<=dy;y++) if (linepix[y-1]!=bkgnd) vsums[x]++; object[*objcnt].xavg += x * vsums[x]; } object[*objcnt].xavg /= object[*objcnt].area; for (x=1;x<=dx;x++) { /* calculate a parameter */ xprime = x - object[*objcnt].xavg; a += xprime * xprime * vsums[x]; } for (y=1;y<=dy;y++) { /* calculate c parameter */ yprime = y - object[*objcnt].yavg; c += yprime * yprime * hsums[y]; } for (y=1;y<=dy;y++) { /* calculate b parameter */ yprime = y - object[*objcnt].yavg; brhline(minx,y+miny-1,dx,linepix); for (x=1;x<=dx;x++) b += (linepix[x-1]!=bkgnd) * (x - object[*objcnt].xavg) * yprime; } b *= 2; object[*objcnt].xavg += object[*objcnt].minx; object[*objcnt].yavg += object[*objcnt].miny; bsquared = (double)b * (double)b; /* calculate AOI from params a,b,c */ a_minus_c = (double)a - (double)c; object[*objcnt].theta = acos(a_minus_c / sqrt(bsquared + a_minus_c * a_minus_c)) / 2; if (b > 0) object[*objcnt].theta *= (-1); z = (dx<=dy) ? dy+50 : dx+50; for (x=0;x<=z;x++) vsums[x] = trace; deltax = (dx / 2 + 20) * cos(object[*objcnt].theta); /* mark AOI */ deltay = (dx / 2 + 20) * sin(object[*objcnt].theta); wline(object[*objcnt].xavg-deltax,object[*objcnt].yavg+deltay, object[*objcnt].xavg+deltax,object[*objcnt].yavg-deltay,vsums); deltax = (dy / 2 + 5) * cos(object[*objcnt].theta - pi / 2); deltay = (dy / 2 + 5) * sin(object[*objcnt].theta - pi / 2); wline(object[*objcnt].xavg-deltax,object[*objcnt].yavg+deltay, object[*objcnt].xavg+deltax,object[*objcnt].yavg-deltay,vsums); VIS$CROSS_HAIR(object[*objcnt].xavg,object[*objcnt].yavg,trace,10); object[*objcnt].theta *= 180 / pi; } /* end centroid_aoi */