/******************************************************************************/ /* feature: extract features from image sequence */ /******************************************************************************/ /* /* input file: image sequence of signature samples file containing authenticity of image sequence (0 = forgery; 1 = authentic) 0/1 followed by newlines. input file: If used in batch processing mode, the image is only 1 frame, and the target result can be specified with t= */ #include "VisXV4.h" /* VisX structure include file */ #include "Vutil.h" /* VisX utility header files */ VXparam_t par[] = { { "if=", 0, " input file : sequence of signatures"}, { "tf=", 0, " target output file"}, { "of=", 0, " output file. Input file to NN program "}, { "-d", 0, " DEBUG mode "}, { "n=", 0, " Size of set (# of frames.) default=1 "}, { "t=", 0, " Target if n=1 and no file specified "}, { "-h", 0, " put the vnet header into output file"}, { 0, 0, 0} }; #define IVAL par[0].val #define TVAL par[1].val #define OVAL par[2].val #define DEBUG par[3].val #define NVAL par[4].val #define TARVAL par[5].val #define HEADVAL par[6].val #define AUTH 1 #define FORGE 0 /*D is the dimension of the feature vector*/ #define D 98 /*MAXSTROKES limits the number of strokes found, for large signatures, there are many strokes, and the feature vector will get too large for current computational limitations */ #define MAXSTROKES 15 typedef struct features{ unsigned int height; unsigned int width; unsigned int area; struct com { float x; float y; }com; unsigned int edgepts; unsigned int crosspts; unsigned int loops; float length[MAXSTROKES]; int bot_x[MAXSTROKES]; int bot_y[MAXSTROKES]; int top_x[MAXSTROKES]; int top_y[MAXSTROKES]; float slope[MAXSTROKES]; int grid[12][8]; } features; VisXfile_t *VXin; /* input file structure */ FILE *ofile , /* output file structure */ *tfile; /* target file structure */ VisXelem_t *vxlist,*VXpt; /* VisX data structure */ VisXimage_t im; VisXimage_t tm; features f; void inline extract_height(void); void inline extract_width(void); void inline extract_area_and_com(void); void inline extract_slope(); void inline extract_edge_and_cross(void); void inline write_features(FILE*); void inline write_targets(int,FILE*); void print_features(); void write_tfile_header(FILE*, int, int, int); void extract_strokes(); void label_stroke_up(int,int,int); void label_stroke_down(int,int,int); main(argc, argv) int argc; char *argv[]; { int t,n,i,j,k; /* index counters */ VXparse(&argc, &argv, par); /* parse the command line */ VXin = VXopen(IVAL, 0); /* open input file */ ofile = fopen(OVAL, "w"); /* open the output file */ if(TVAL) tfile = fopen(TVAL, "r"); /* open target file */ if(NVAL) n = atoi(NVAL); else n = 1; if(TARVAL) t = atoi(TARVAL); else t = 99; if(HEADVAL) write_tfile_header(ofile, D, 1, n); while ((vxlist = VXreadframe(VXin) ) != VXNIL) { VXsetimage(&im, vxlist, VXin); VXembedimage(&tm,&im,1,1,1,1); /* image structure with border */ /********************* Application specific section ***************************/ /*initialize grid*/ for(i = 0; i < 12; i++) for(j = 0; j < 8; j++) f.grid[i][j] = -1; /* extract features, and fill features structure f */ /*Global Features*/ extract_height(); extract_width(); extract_area_and_com(); /* extract_slope(); */ extract_edge_and_cross(); /*strokes features */ extract_strokes(); /** Write to files and update **/ if(DEBUG) print_features(); write_features(ofile); if((TVAL != NULL) | (TARVAL != NULL)) { if(!TARVAL) { fscanf(tfile,"%d",t); } write_targets(t,ofile); } else { fprintf(ofile, "\n"); } VXdellist(vxlist); /******************************/ /******************* End of the Application specific section ******************/ } /* end of every frame section */ VXclose(VXin); /* close files */ fclose(ofile); fclose(tfile); exit(0); } /*Since the input images are in a bounding box, computing height is simple*/ void inline extract_height() { f.height = im.yhi - im.ylo + 1; } /*since the input images are in a bounding box, computing width is simple*/ void inline extract_width() { f.width = im.xhi - im.xlo + 1; } /*Go through the image and calculate the area, and center of mass*/ void inline extract_area_and_com() { int i,j,xc,yc,a; a = 0; xc = 0; yc = 0; for(i = im.ylo; i <= im.yhi; i++) { for(j = im.xlo; j <= im.xhi; j++) { if(im.u[i][j] != 0) { if(f.grid[j*11/im.xhi][i*7/im.yhi] != -1) f.grid[j*11/im.xhi][i*7/im.yhi]++; else f.grid[j*11/im.xhi][i*7/im.yhi] = 1; a++; xc += j; yc += i; } } } f.area = a; f.com.x = ((float) xc)/((float)a) ; f.com.y = ((float) yc)/((float)a) ; } /*extract edge and cross points*/ /*edge points = EP = points that have only 1 8-neighbor */ /*cross points = points that have 3 or more 8-neighbors */ /*closed loops = CL = 1 + (EL-EP)/2 */ /*EL = sum over all cross points (#8-neighbors for current cross point - 2) */ void inline extract_edge_and_cross() { int i,j,ep,cp,el,neighbors; ep = 0; cp = 0; el = 0; for(i = im.ylo; i <= im.yhi; i++) { for(j = im.xlo; j <= im.xhi; j++) { if(tm.u[i][j] != 0) { neighbors = 0; if(tm.u[i+1][j+1] != 0) neighbors++; if(tm.u[i+1][j] != 0) neighbors++; if(tm.u[i+1][j-1] != 0) neighbors++; if(tm.u[i][j+1] != 0) neighbors++; if(tm.u[i][j-1] != 0) neighbors++; if(tm.u[i-1][j+1] != 0) neighbors++; if(tm.u[i-1][j] != 0) neighbors++; if(tm.u[i-1][j-1] != 0) neighbors++; if(neighbors == 1) ep++; if(neighbors >= 3) { cp++; el += neighbors-2; } } } } f.edgepts = ep; f.crosspts = cp; f.loops = 1 + ((el - ep)/2); } /* DEBUG routine for displaying contents of a features struct */ void print_features() { int i; printf("Features\n"); printf("heightxwidth = %d x %d\n",f.height,f.width); printf("Area = %d\n",f.area); printf("Center of mass = %f x %f\n", f.com.x, f.com.y); printf("Edge pts: %d\nCross pts: %d\nClosed Loops:%d\n",f.edgepts, f.crosspts, f.loops); for(i = 0; i= MAXSTROKES) break; f.length[i] = length[i]; f.bot_x[i] = bot_x[i]; f.bot_y[i] = bot_y[i]; f.top_x[i] = top_x[i]; f.top_y[i] = top_y[i]; f.slope[i] = slope[i]; } for(;i < MAXSTROKES; i++) { f.length[i] = 0; f.bot_x[i] = 0; f.bot_y[i] = 0; f.top_x[i] = 0; f.top_y[i] = 0; f.slope[i] = 0; } } /*to extract strokes, scan the image for an un-labeled pixel. Then mark the pixel, and the stroke going up and down for one complete stroke */ void extract_strokes() { int i,j,label; label = 2; for(j = im.xlo; j <= im.xhi; j++) { for(i = im.ylo; i <= im.yhi; i++) { if(tm.u[i][j] == 1) { label_stroke_up(label, j, i); label_stroke_down(label, j, i); label++; } } } extract_stroke_features(label-1); } /*A pixel is part of the current up-stroke if it is above the current pixel (or immediately right of it) */ void label_stroke_up(int l, int x, int y) { tm.u[y][x] = l; /*printf("L=%d x=%d y=%d\n",l,x,y);*/ if(tm.u[y][x+1] == 1) { label_stroke_up(l,x+1,y); } else if(tm.u[y+1][x-1] == 1) { label_stroke_up(l,x-1,y+1); } else if(tm.u[y+1][x] == 1) { label_stroke_up(l,x,y+1); } else if(tm.u[y+1][x+1] == 1) { label_stroke_up(l,x+1,y+1); } } /*A pixel is part of the current down-stroke if it is below the current pixel*/ void label_stroke_down(int l, int x, int y) { tm.u[y][x] = l; /*printf("L=%d x=%d y=%d\n",l,x,y);*/ if(tm.u[y][x-1] == 1) { label_stroke_down(l,x-1,y); } else if(tm.u[y-1][x-1] == 1) { label_stroke_down(l,x-1,y-1); } else if(tm.u[y-1][x] == 1) { label_stroke_down(l,x,y-1); } else if(tm.u[y-1][x+1] == 1) { label_stroke_down(l,x+1,y-1); } } /*utilities for writing the feature vector information*/ #define write_strokes(of,i) {fprintf(of,"%f %d %d %d %d %f ",f.length[i],f.top_x[i],f.top_y[i],f.bot_x[i],f.bot_y[i],f.slope[i]);} void write_features(FILE* out_file) { int i,j; fprintf(out_file, "%d %d %d %f %f %d %d %d ", f.height, f.width, f.area, f.com.x, f.com.y, f.edgepts, f.crosspts, f.loops); /*for(i = 0; i < MAXSTROKES; i++) write_strokes(out_file,i);*/ for(i = 0; i < 12; i++) for(j = 0; j < 8; j++) fprintf(out_file,"%d ",f.grid[i][j]); } void write_targets(int t, FILE* out_file) { fprintf(out_file, "%d\n", t); } void write_tfile_header(FILE* out_file, int d, int sf, int n) { fprintf(out_file, "%d %d %d\n", d, sf, n); }