📄 imagemanip.c
字号:
{ FvsFloat_t dir = 0.0; FvsFloat_t cosdir = 0.0; FvsFloat_t sindir = 0.0; FvsInt_t peak_pos[BLOCK_L]; /* peak positions */ FvsInt_t peak_cnt; /* peak count */ FvsFloat_t peak_freq; /* peak frequence */ FvsFloat_t Xsig[BLOCK_L]; /* x signature */ FvsFloat_t pmin, pmax; memset(out, 0, size); memset(freq, 0, size); /* 1 - Divide G into blocks of BLOCK_W x BLOCK_W - (16 x 16) */ for (y = BLOCK_L2; y < h-BLOCK_L2; y++) for (x = BLOCK_L2; x < w-BLOCK_L2; x++) { /* 2 - oriented window of size l x w (32 x 16) in the ridge dir */ dir = orientation[(x+BLOCK_W2) + (y+BLOCK_W2)*w]; cosdir = -sin(dir); /* ever > 0 */ sindir = cos(dir); /* -1 ... 1 */ /* 3 - compute the x-signature X[0], X[1], ... X[l-1] */ for (k = 0; k < BLOCK_L; k++) { Xsig[k] = 0.0; for (d = 0; d < BLOCK_W; d++) { u = (FvsInt_t)(x + (d-BLOCK_W2)*cosdir + (k-BLOCK_L2)*sindir); v = (FvsInt_t)(y + (d-BLOCK_W2)*sindir - (k-BLOCK_L2)*cosdir); /* clipping */ if (u<0) u = 0; else if (u>w-1) u = w-1; if (v<0) v = 0; else if (v>h-1) v = h-1; Xsig[k] += p[u + (v*pitchi)]; } Xsig[k] /= BLOCK_W; } /* Let T(i,j) be the avg number of pixels between 2 peaks */ /* find peaks in the x signature */ peak_cnt = 0; /* test if the max - min or peak to peak value too small is, then we ignore this point */ pmax = pmin = Xsig[0]; for (k = 1; k < BLOCK_L; k++) { if (pmin>Xsig[k]) pmin = Xsig[k]; if (pmax<Xsig[k]) pmax = Xsig[k]; } if ((pmax - pmin)>64.0) { for (k = 1; k < BLOCK_L-1; k++) if ((Xsig[k-1] < Xsig[k]) && (Xsig[k] >= Xsig[k+1])) { peak_pos[peak_cnt++] = k; } } /* compute mean value */ peak_freq = 0.0; if (peak_cnt>=2) { for (k = 0; k < peak_cnt-1; k++) peak_freq += peak_pos[k+1]-peak_pos[k]; peak_freq /= peak_cnt-1; } /* 4 - must lie in a certain range [1/25-1/3] */ /* changed to range [1/30-1/2] */ if (peak_freq > 30.0) out[x+y*w] = 0.0; else if (peak_freq < 2.0) out[x+y*w] = 0.0; else out[x+y*w] = 1.0/peak_freq; } /* 5 - interpolated ridge period for the unknown points */ for (y = BLOCK_L2; y < h-BLOCK_L2; y++) for (x = BLOCK_L2; x < w-BLOCK_L2; x++) { if (out[x+y*w]<EPSILON) { if (out[x+(y-1)*w]>EPSILON) { out[x+(y*w)] = out[x+(y-1)*w]; } else { if (out[x-1+(y*w)]>EPSILON) out[x+(y*w)] = out[x-1+(y*w)]; } } } /* 6 - Inter-ridges distance change slowly in a local neighbourhood */ for (y = BLOCK_L2; y < h-BLOCK_L2; y++) for (x = BLOCK_L2; x < w-BLOCK_L2; x++) { k = x + y*w; peak_freq = 0.0; for ( v = -LPSIZE; v <= LPSIZE; v++) for ( u = -LPSIZE; u <= LPSIZE; u++) peak_freq += out[(x+u)+(y+v)*w]; freq[k] = peak_freq*LPFACTOR; } free(out); } return nRet;}/* }}} *//* {{{ Fingerprint mask */FvsError_t FingerprintGetMask(const FvsImage_t image, /*@unused@*/ const FvsFloatField_t direction, const FvsFloatField_t frequency, FvsImage_t mask){ FvsError_t nRet = FvsOK; FvsFloat_t freqmin = 1.0 / 25; FvsFloat_t freqmax = 1.0 / 3; /* width & height of the input image */ FvsInt_t w = ImageGetWidth (image); FvsInt_t h = ImageGetHeight(image); FvsByte_t* out; FvsInt_t pitchout; FvsInt_t pos, posout, x, y; FvsFloat_t* freq = FloatFieldGetBuffer(frequency); if (freq==NULL) return FvsMemory; /* TODO: add sanity checks for the direction and mask */ nRet = ImageSetSize(mask, w, h); if (nRet==FvsOK) nRet = ImageClear(mask); out = ImageGetBuffer(mask); if (out==NULL) return FvsMemory; if (nRet==FvsOK) { pitchout = ImageGetPitch(mask); for (y = 0; y < h; y++) for (x = 0; x < w; x++) { pos = x + y * w; posout = x + y * pitchout; out[posout] = 0; if (freq[pos] >= freqmin && freq[pos] <= freqmax) {/* out[posout] = (uint8_t)(10.0/freq[pos]);*/ out[posout] = 255; } } /* fill in the holes */ for (y = 0; y < 4; y++) (void)ImageDilate(mask); /* remove borders */ for (y = 0; y < 12; y++) (void)ImageErode(mask); } return nRet;}/* }}} *//* {{{ Thinning algorithms *//* {{{ -> Thin: Using connectivity */#undef P#define P(x,y) ((x)+(y)*pitch)#define REMOVE_P { p[P(x,y)]=0x80; changed = FvsTrue; }/*From : Nadeem Ahmed (umahmed@cc.umanitoba.ca)Subject : Thinning AlgorithmNewsgroup: borland.public.cppbuilder.graphicsDate :1998/02/23 Here is that thinning algorithm: 9 2 3 8 1 4 7 5 6For each pixel(#1, above), we have 8 neighbors (#'s 2-8).Step 1:a) Make sure pixel 1, has 2 to 6 (inclusive) neighborsb) starting from 2, go clockwise until 9, and count the number of 0 to 1 transitions. This should be equal to 1.c) 2*4*6=0 (ie either 2,4 ,or 6 is off)d) 4*6*8=0if these conditions hold, remove pixel 1.Do this for the entire image.Step 2a) same as aboveb) same as abovec) 2*6*8=0d) 2*4*8=0if these hold remove pixel 1.*//* defines to facilitate reading */#define P1 p[P(x ,y )]#define P2 p[P(x ,y-1)]#define P3 p[P(x+1,y-1)]#define P4 p[P(x+1,y )]#define P5 p[P(x+1,y+1)]#define P6 p[P(x ,y+1)]#define P7 p[P(x-1,y+1)]#define P8 p[P(x-1,y )]#define P9 p[P(x-1,y-1)]FvsError_t ImageRemoveSpurs(FvsImage_t image){ FvsInt_t w = ImageGetWidth(image); FvsInt_t h = ImageGetHeight(image); FvsInt_t pitch = ImageGetPitch(image); FvsByte_t* p = ImageGetBuffer(image); FvsInt_t x, y, n, t, c; /* Thanks to Tony Xu for contributing this section that improves the quality of the binarized image by getting rid of the extra pixels (spurs) jdh: improvment by using 2 steps, the previous algorithm had the bad habbit to remove completely some lines oriented in a special way... */ c = 0; do { n = 0; for (y=1; y<h-1; y++) for (x=1; x<w-1; x++) { if( p[P(x,y)]==0xFF) { t=0; if (P3==0 && P2!=0 && P4==0) t++; if (P5==0 && P4!=0 && P6==0) t++; if (P7==0 && P6!=0 && P8==0) t++; if (P9==0 && P8!=0 && P2==0) t++; if (P3!=0 && P4==0) t++; if (P5!=0 && P6==0) t++; if (P7!=0 && P8==0) t++; if (P9!=0 && P2==0) t++; if (t==1) { p[P(x,y)] = 0x80; n++; } } } for (y=1; y<h-1; y++) for (x=1; x<w-1; x++) { if( p[P(x,y)]==0x80) p[P(x,y)] = 0; } } while (n>0 && ++c < 5); return FvsOK;}/* a) Make sure it has 2 to 6 neighbours */#define STEP_A n = 0; /* number of neighbours */ \ if (P2!=0) n++; if (P3!=0) n++; if (P4!=0) n++; if (P5!=0) n++; \ if (P6!=0) n++; if (P7!=0) n++; if (P8!=0) n++; if (P9!=0) n++; \ if (n>=2 && n<=6)/* b) count number 0 to 1 transsitions */#define STEP_B t = 0; /* number of transitions */ \ if (P9==0 && P2!=0) t++; if (P2==0 && P3!=0) t++; \ if (P3==0 && P4!=0) t++; if (P4==0 && P5!=0) t++; \ if (P5==0 && P6!=0) t++; if (P6==0 && P7!=0) t++; \ if (P7==0 && P8!=0) t++; if (P8==0 && P9!=0) t++; \ if (t==1) FvsError_t ImageThinConnectivity(FvsImage_t image){ FvsInt_t w = ImageGetWidth(image); FvsInt_t h = ImageGetHeight(image); FvsInt_t pitch = ImageGetPitch(image); FvsByte_t* p = ImageGetBuffer(image); FvsInt_t x, y, n, t; FvsBool_t changed = FvsTrue; if (p==NULL) return FvsMemory; if (ImageGetFlag(image)!=FvsImageBinarized) return FvsBadParameter; while (changed==FvsTrue) { changed = FvsFalse; for (y=1; y<h-1; y++) for (x=1; x<w-1; x++) { if (p[P(x,y)]==0xFF) { STEP_A { STEP_B { /* c) 2*4*6=0 (ie either 2,4 ,or 6 is off) d) 4*6*8=0 */ if (P2*P4*P6==0 && P4*P6*P8==0) REMOVE_P; } } } } for (y=1; y<h-1; y++) for (x=1; x<w-1; x++) if (p[P(x,y)]==0x80) p[P(x,y)] = 0; for (y=1; y<h-1; y++) for (x=1; x<w-1; x++) { if (p[P(x,y)]==0xFF) { STEP_A { STEP_B { /* c) 2*6*8=0 d) 2*4*8=0 */ if (P2*P6*P8==0 && P2*P4*P8==0) REMOVE_P; } } } } for (y=1; y<h-1; y++) for (x=1; x<w-1; x++) if (p[P(x,y)]==0x80) p[P(x,y)] = 0; } ImageRemoveSpurs(image); return ImageSetFlag(image, FvsImageThinned);} /* redefine REMOVE_P */#undef REMOVE_P/* }}} *//* {{{ -> Thin: Hit and miss */#define REMOVE_P { p[P(x,y)]=0x00; changed = FvsTrue; }/*// jdh: Second thinning algorithm based on a Hit and Miss transformation*/FvsError_t ImageThinHitMiss(FvsImage_t image){ FvsInt_t w = ImageGetWidth(image); FvsInt_t h = ImageGetHeight(image); FvsInt_t pitch = ImageGetPitch(image); FvsByte_t* p = ImageGetBuffer(image); /* // Hit and Miss structuring elements for thinning // // this algo has the disadvantage to produce spurious lines resulting // from the skeletonization. These may be eliminated by another algorithm. // postprocessing is then still needed afterwards. // // 0 0 0 0 0 // 1 1 1 0 // 1 1 1 1 // */ FvsInt_t x,y; FvsBool_t changed = FvsTrue; if (p==NULL) return FvsMemory; if (ImageGetFlag(image)!=FvsImageBinarized) return FvsBadParameter; while (changed==FvsTrue) { changed = FvsFalse; for (y=1; y<h-1; y++) for (x=1; x<w-1; x++) { if (p[P(x,y)]==0xFF) { /* // 0 0 0 0 1 1 1 1 1 0 // 1 0 1 1 1 1 1 0 // 1 1 1 0 1 0 0 0 1 0 */ if (p[P(x-1,y-1)]==0 && p[P(x,y-1)]==0 && p[P(x+1,y-1)]==0 && p[P(x-1,y+1)]!=0 && p[P(x,y+1)]!=0 && p[P(x+1,y+1)]!=0) REMOVE_P; if (p[P(x-1,y-1)]!=0 && p[P(x,y-1)]!=0 && p[P(x+1,y-1)]!=0 && p[P(x-1,y+1)]==0 && p[P(x,y+1)]==0 && p[P(x+1,y+1)]==0) REMOVE_P; if (p[P(x-1,y-1)]==0 && p[P(x-1,y)]==0 && p[P(x-1,y+1)]==0 && p[P(x+1,y-1)]!=0 && p[P(x+1,y)]!=0 && p[P(x+1,y+1)]!=0) REMOVE_P; if (p[P(x-1,y-1)]!=0 && p[P(x-1,y)]!=0 && p[P(x-1,y+1)]!=0 && p[P(x+1,y-1)]==0 && p[P(x+1,y)]==0 && p[P(x+1,y+1)]==0) REMOVE_P; /* // 0 0 0 0 1 1 // 1 1 0 0 1 1 0 1 1 1 1 0 // 1 1 0 0 0 0 */ if (p[P(x,y-1)]==0 && p[P(x+1,y-1)]==0 && p[P(x+1,y)]==0 && p[P(x-1,y)]!=0 && p[P(x,y+1)]!=0) REMOVE_P; if (p[P(x-1,y-1)]==0 && p[P(x,y-1)]==0 && p[P(x-1,y)]==0 && p[P(x+1,y)]!=0 && p[P(x,y+1)]!=0) REMOVE_P; if (p[P(x-1,y+1)]==0 && p[P(x-1,y)]==0 && p[P(x,y+1)]==0 && p[P(x+1,y)]!=0 && p[P(x,y-1)]!=0) REMOVE_P; if (p[P(x+1,y+1)]==0 && p[P(x+1,y)]==0 && p[P(x,y+1)]==0 && p[P(x-1,y)]!=0 && p[P(x,y-1)]!=0) REMOVE_P; } } } ImageRemoveSpurs(image); return ImageSetFlag(image, FvsImageThinned);}/* }}} *//* }}} */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -