/******************************************************************************/ /* */ /* Tsang & Tsang algorithm to perform multispectral edge detection */ /* */ /******************************************************************************/ #include "VisXV4.h" /* VisX structure include file */ #include "Vutil.h" /* VisX utility header files */ VXparam_t par[] = /* command line structure */ { { "if=", 0, "input file"}, { "of=", 0, "output file"}, { "u=", 0, "upper threshold value"}, { "l=", 0, "lower threshold value"}, { "g=", 0, "gradient threshold"}, { 0, 0, 0} /* list termination */ }; #define IVAL par[0].val #define OVAL par[1].val #define UVAL par[2].val #define LVAL par[3].val #define GVAL par[4].val VisXfile_t *VXin, /* input file structure */ *VXout ; /* output file structure */ VisXelem_t *VXlist, /* VisionX data structure */ *VXptr ; /* VisionX pixel data pointer */ /* global variables */ VisXimage_t h, s, v, /* HSV image structures */ grad ; /* gradient image structure */ /* Function declaration */ void sobelh (int, int) ; void sobelv (int, int) ; main(argc, argv) int argc ; char *argv[] ; { int i, j, /* loop counters */ temp, /* temporarily hold gradient values */ u, l, /* upper, lower threshold */ gt ; /* gradient threshold */ VisXimage_t in, /* input image structure */ r, g, b ; /* RGB image structure */ int xmin ; /* xmin = min (r, g, b) */ int delta ; /* delta = v-x */ VXparse(&argc, &argv, par) ; /* parse the command line */ VXin = VXopen(IVAL, 0) ; /* open input file */ VXout = VXopen(OVAL, 1) ; /* open the output file */ VXlist = VXread(VXin) ; /* read file */ u = (UVAL ? atoi(UVAL) : 200) ; /* read u, default is u=200 */ l = (LVAL ? atoi(LVAL) : 100) ; /* read l, default is l=100 */ gt = (GVAL ? atoi(GVAL) : 50) ; /* read gt, default is gt=50 */ /*************************************************************************** 1) copy image data into array "in" which has 3 times the WIDTH to accommodate R, G, B data. 2) create arrays "r", "g", "b" with dimensions WIDTH * HEIGHT 3) create array "s" with dimentions WIDTH * HEIGHT (float type) 4) create output array "grad" with dimensions WIDTH * HEIGHT 5) create arrays "h", "v" with dimensions WIDTH * HEIGHT and a border of zeros (float type) ***************************************************************************/ if (VXNIL != (VXptr = VXfind(VXlist, VX_PBYTE))) { /* find image */ VXsetimage(&in, VXptr, VXin) ; /* initialize input structure */ VXmakeimage(&r, VX_PBYTE, in.bbx, 1) ; VXmakeimage(&g, VX_PBYTE, in.bbx, 1) ; VXmakeimage(&b, VX_PBYTE, in.bbx, 1) ; VXmakeimage(&s, VX_PFLOAT, in.bbx, 1) ; VXmakeimage(&grad, VX_PBYTE, in.bbx, 1) ; VXembedimage(&h, &s, 1, 1, 1, 1) ; // image structure with border of zeros VXembedimage(&v, &s, 1, 1, 1, 1) ; // image structure with border of zeros /* split data from "in" into the 3 arrays "r", "g", "b" */ for (i = in.ylo ; i <= in.yhi ; i++) { for (j = in.xlo ; j <= in.xhi ; j++) { if (j%3 == 0) r.u[i][j/3] = in.u[i][j] ; if (j%3 == 1) g.u[i][j/3] = in.u[i][j] ; if (j%3 == 2) b.u[i][j/3] = in.u[i][j] ; } } /* loop to calculate HSV values */ for (i = r.ylo ; i <= r.yhi ; i++) { for (j = r.xlo ; j <= r.xhi ; j++) { /* calculate v where v = max (r, g, b) */ v.f[i][j] = r.u[i][j] ; if (g.u[i][j] > v.f[i][j]) v.f[i][j] = g.u[i][j] ; if (b.u[i][j] > v.f[i][j]) v.f[i][j] = b.u[i][j] ; /* calculate xmin where xmin = min (r, g, b) */ xmin = r.u[i][j] ; if (g.u[i][j] < xmin) xmin = g.u[i][j] ; if (b.u[i][j] < xmin) xmin = b.u[i][j] ; delta = v.f[i][j] - xmin ; /* calculate s where s = delta/v */ if (v.f[i][j] == 0.0) s.f[i][j] = 0.0 ; else s.f[i][j] = delta / v.f[i][j] ; /* calculate h */ if (s.f[i][j] == 0.0) h.f[i][j] = 1024 ; else { if ((float)r.u[i][j] == v.f[i][j]) h.f[i][j] = (g.u[i][j] - b.u[i][j]) / delta ; else if ((float)g.u[i][j] == v.f[i][j]) h.f[i][j] = ((b.u[i][j] - r.u[i][j]) / delta) + 2 ; else if ((float)b.u[i][j] == v.f[i][j]) h.f[i][j] = ((r.u[i][j] - g.u[i][j]) / delta) + 4 ; } h.f[i][j] = h.f[i][j] * 511 / 6 ; if (h.f[i][j] < 0) h.f[i][j] = h.f[i][j] + 511 ; } } /* loop to calculate gradient */ for (i = r.ylo ; i <= r.yhi ; i++) { for (j = r.xlo ; j <= r.xhi ; j++) { int index = v.f[i][j] * s.f[i][j] ; if (index > u) sobelh (i, j) ; else if (index < l) sobelv (i, j) ; else { /* use max(v, h) to calculate gradient */ sobelh (i, j) ; temp = grad.u[i][j] ; sobelv (i, j) ; if (temp > grad.u[i][j]) grad.u[i][j] = temp ; } } } /* loop to mark edges, black lines on white background */ for (i = r.ylo ; i <= r.yhi ; i++) { for (j = r.xlo ; j <= r.xhi ; j++) { if (grad.u[i][j] > gt) grad.u[i][j] = 0 ; // black else grad.u[i][j] = 255 ; // white } } VXwrite(VXout, grad.list) ; /* write data */ } else { fprintf(stderr, "no byte image data in input file\n") ; exit(-1) ; } VXclose(VXin); /* close files */ VXclose(VXout); exit(0); } void sobelh (int y, int x) { float sx, sy ; sx = h.f[y+1][x-1]*(-1) + h.f[y][x-1]*(-2) + h.f[y-1][x-1]*(-1) + h.f[y+1][x+1] + h.f[y][x+1]*2 + h.f[y-1][x+1] ; sy = h.f[y+1][x-1] + h.f[y+1][x]*2 + h.f[y+1][x+1] + h.f[y-1][x-1]*(-1) + h.f[y-1][x]*(-2) + h.f[y-1][x+1]*(-1) ; grad.u[y][x] = sqrt (sx * sx + sy * sy) ; } void sobelv (int y, int x) { float sx, sy ; sx = v.f[y+1][x-1]*(-1) + v.f[y][x-1]*(-2) + v.f[y-1][x-1]*(-1) + v.f[y+1][x+1] + v.f[y][x+1]*2 + v.f[y-1][x+1] ; sy = v.f[y+1][x-1] + v.f[y+1][x]*2 + v.f[y+1][x+1] + v.f[y-1][x-1]*(-1) + v.f[y-1][x]*(-2) + v.f[y-1][x+1]*(-1) ; grad.u[y][x] = sqrt (sx * sx + sy * sy) ; }