電容式 指紋識別 android 智慧硬體
阿新 • • 發佈:2019-01-09
目前,各個手機中,都是用的電容式指紋識別模組
公司打卡機,大都是光學指紋模組,相對上者便宜一些;
1.現在陳列一些資料;
基於stm32和fpc1011c2的指紋採集系統
指紋識別的模組,現在主流的是,fpc1011或者1020,好多廠家,為了保護演算法,整合演算法後,開放串列埠,讓你用at指令來操作,就和操作sim900a,或者藍芽hc-06一樣,
但我們這裡不是用這麼簡單的用,我們要自己封裝演算法,用fpc1011採集器+stm32來做;
2.學習充電
對不瞭解,數字影象處理的,請下載:第三版,數字影象處理,岡薩雷斯,中文版;
想用matlab實現的,請下載數字影象處理(matlab版),岡薩雷斯
二者不同,我第一次就買錯了;
教程:
視訊教程:百度雲盤 韓春梅,或者回複評論,我發給你郵箱;
3.學習思路
1.網上一大堆,matlab實現的程式碼,各個流程,我也不多說,確實可以實現,滿足大學生畢設沒問題,但是要想把每一步,都理解透,返回第二步,學習充電;
2.用vc++,或者c++等寫的上位機,來單獨處理指紋圖片;
3.用vc++,或者c++等上位機,處理,fpc1011的spi輸出的資料,檢視對比,充分利用了pc的處理能力;
4,用matlab處理,fpc1011的spi輸出的資料,檢視對比;
5,用stm32、dsp等mcu來和fpc1011直接通訊,處理資料需要擴充套件sram或者外加flash,儲存某些特徵值或者圖片;
4.來看看fpc1011資料手冊
其實,主要還是看看看這些指令;
讀出資料後,就需按照資料影象處理流程來做,具體C語言實現,下面提供幾個檔案;
5.影象增強演算法(c語言):
我的stm32 最終版,程式碼,除錯好了,之後,上傳,請稍後;
/*#############################################################################
* 檔名:imageenhance.c
* 功能: 實現了影象增強演算法
*
#############################################################################*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "imagemanip.h"
/******************************************************************************
** 影象增強部分
**
** 該增強演算法針對指紋影象設計,它標記了指紋影象中沒有使用的區域,而其它的區域
** 在增強後,脊線可以被清晰的分離出來(使用一個閾值)。
**
** 該演算法生成了一個脊線方向圖,一個掩碼圖。
**
** 可參考如下兩篇文章:
** 1 - Fingerprint Enhancement: Lin Hong, Anil Jain, Sharathcha Pankanti,
** and Ruud Bolle. [Hong96]
** 2 - Fingerprint Image Enhancement, Algorithm and Performance Evaluation:
** Lin Hong, Yifei Wan and Anil Jain. [Hong98]
**
** 增強演算法使用了 文獻(2) 中的幾個步驟:
** A - 歸一化
** B - 計算方向圖
** C - 計算頻率
** D - 計算區域掩碼
** E - 濾波
**
******************************************************************************/
#define P(x,y) ((int32_t)p[(x)+(y)*pitch])
/******************************************************************************
** 採用了Gabor方向濾波器,如下:
**
** / 1|x' y' |\
** h(x,y:phi,f) = exp|- -|--- + ---| |.cos(2.PI.f.x')
** \ 2|dx dy |/
**
** x' = x.cos(phi) + y.sin(phi)
** y' = -x.sin(phi) + y.cos(phi)
**
** 定義如下:
** G 歸一化後的影象
** O 方向圖
** F 頻率圖
** R 掩碼影象
** E 增強後的影象
** Wg Gabor濾波器視窗大小
**
** / 255 if R(i,j) = 0
** |
** | Wg/2 Wg/2
** | --- ---
** E(i,j)= | \ \
** | -- -- h(u,v:O(i,j),F(i,j)).G(i-u,j-v) otherwise
** | / /
** \ --- ---
** u=-Wg/2 v=-Wg/2
**
******************************************************************************/
inline FvsFloat_t EnhanceGabor(FvsFloat_t x, FvsFloat_t y, FvsFloat_t phi,
FvsFloat_t f, FvsFloat_t r2)
{
FvsFloat_t dy2 = 1.0/r2;
FvsFloat_t dx2 = 1.0/r2;
FvsFloat_t x2, y2;
phi += M_PI/2;
x2 = -x*sin(phi) + y*cos(phi);
y2 = x*cos(phi) + y*sin(phi);
return exp(-0.5*(x2*x2*dx2 + y2*y2*dy2))*cos(2*M_PI*x2*f);
}
static FvsError_t ImageEnhanceFilter
(
FvsImage_t normalized,
const FvsImage_t mask,
const FvsFloat_t* orientation,
const FvsFloat_t* frequence,
FvsFloat_t radius
)
{
FvsInt_t Wg2 = 8;
FvsInt_t i,j, u,v;
FvsError_t nRet = FvsOK;
FvsImage_t enhanced = NULL;
FvsInt_t w = ImageGetWidth (normalized);
FvsInt_t h = ImageGetHeight(normalized);
FvsInt_t pitchG = ImageGetPitch (normalized);
FvsByte_t* pG = ImageGetBuffer(normalized);
FvsFloat_t sum, f, o;
/* 平方 */
radius = radius*radius;
enhanced = ImageCreate();
if (enhanced==NULL || pG==NULL)
return FvsMemory;
if (nRet==FvsOK)
nRet = ImageSetSize(enhanced, w, h);
if (nRet==FvsOK)
{
FvsInt_t pitchE = ImageGetPitch (enhanced);
FvsByte_t* pE = ImageGetBuffer(enhanced);
if (pE==NULL)
return FvsMemory;
(void)ImageClear(enhanced);
for (j = Wg2; j < h-Wg2; j++)
for (i = Wg2; i < w-Wg2; i++)
{
if (mask==NULL || ImageGetPixel(mask, i, j)!=0)
{
sum = 0.0;
o = orientation[i+j*w];
f = frequence[i+j*w];
for (v = -Wg2; v <= Wg2; v++)
for (u = -Wg2; u <= Wg2; u++)
{
sum += EnhanceGabor
(
(FvsFloat_t)u,
(FvsFloat_t)v,
o,f,radius
)
* pG[(i-u)+(j-v)*pitchG];
}
if (sum>255.0)
sum = 255.0;
if (sum<0.0)
sum = 0.0;
pE[i+j*pitchE] = (uint8_t)sum;
}
}
nRet = ImageCopy(normalized, enhanced);
}
(void)ImageDestroy(enhanced);
return nRet;
}
/* }}} */
/******************************************************************************
* 功能:指紋影象增強演算法
* 該演算法描述起來比較複雜,其後處理的部分是基於Gabor濾波器的,
引數動態計算。影象處理時引數依次改變,所以要做一個原圖的備份。
* 引數:image 指紋影象
* direction 脊線方向,需要事先計算
* frequency 脊線頻率,需要事先計算
* mask 指示指紋的有效區域
* radius 濾波器半徑,大多數情況下,4.0即可。
值越大,噪聲可以受到更大抑制,但會產生更多的偽特徵。
* 返回:錯誤編號
******************************************************************************/
FvsError_t ImageEnhanceGabor(FvsImage_t image, const FvsFloatField_t direction,
const FvsFloatField_t frequency, const FvsImage_t mask,
const FvsFloat_t radius)
{
FvsError_t nRet = FvsOK;
FvsFloat_t * image_orientation = FloatFieldGetBuffer(direction);
FvsFloat_t * image_frequence = FloatFieldGetBuffer(frequency);
if (image_orientation==NULL || image_frequence==NULL)
return FvsMemory;
nRet = ImageEnhanceFilter(image, mask, image_orientation,
image_frequence, radius);
return nRet;
}
6.實現了指紋直方圖的操作
/*#############################################################################
* 檔名:histogram.c
* 功能: 實現了指紋直方圖的操作
*
#############################################################################*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "histogram.h"
/* 直方圖可以快速計算點陣圖的一些資訊,比如均值,方差等 */
typedef struct iFvsHistogram_t
{
FvsUint_t ptable[256]; /* 8點陣圖像的直方圖 */
FvsInt_t ncount; /* 直方圖中的點數 */
FvsInt_t nmean; /* -1 = 還沒有計算 */
FvsInt_t nvariance; /* -1 = 還沒有計算 */
} iFvsHistogram_t;
/******************************************************************************
* 功能:建立一個新的直方圖物件
* 引數:無
* 返回:失敗返回空,否則返回直方圖物件
******************************************************************************/
FvsHistogram_t HistogramCreate()
{
iFvsHistogram_t* p = NULL;
p = (FvsHistogram_t)malloc(sizeof(iFvsHistogram_t));
if (p!=NULL)
{
/* 重置表 */
HistogramReset(p);
}
return (FvsHistogram_t)p;
}
/******************************************************************************
* 功能:破壞一個存在的直方圖物件
* 引數:histogram 直方圖物件指標
* 返回:錯誤編號
******************************************************************************/
void HistogramDestroy(FvsHistogram_t histogram)
{
iFvsHistogram_t* p = NULL;
if (histogram==NULL)
return;
p = histogram;
free(p);
}
/******************************************************************************
* 功能:重置一個存在的直方圖物件為0
* 引數:histogram 直方圖物件指標
* 返回:錯誤編號
******************************************************************************/
FvsError_t HistogramReset(FvsHistogram_t hist)
{
iFvsHistogram_t* histogram = (iFvsHistogram_t*)hist;
int i;
for (i = 0; i < 256; i++)
histogram->ptable[i] = 0;
histogram->ncount = 0;
histogram->nmean = -1;
histogram->nvariance = -1;
return FvsOK;
}
/******************************************************************************
* 功能:計算一個8-bit影象的直方圖
* 引數:histogram 直方圖物件指標
* image 影象指標
* 返回:錯誤編號
******************************************************************************/
FvsError_t HistogramCompute(FvsHistogram_t hist, const FvsImage_t image)
{
iFvsHistogram_t* histogram = (iFvsHistogram_t*)hist;
FvsError_t nRet = FvsOK;
FvsInt_t w = ImageGetWidth(image);
FvsInt_t h = ImageGetHeight(image);
FvsInt_t pitch = ImageGetPitch(image);
uint8_t* p = ImageGetBuffer(image);
FvsInt_t x, y;
if (histogram==NULL || p==NULL)
return FvsMemory;
/* 首先重置直方圖 */
nRet = HistogramReset(hist);
/* 計算 */
if (nRet==FvsOK)
{
FvsInt_t pos;
for (y=0; y<h; y++)
{
pos = pitch*y;
for (x=0; x<w; x++)
{
histogram->ptable[p[pos++]]++;
}
}
histogram->ncount = w*h;
}
return nRet;
}
/******************************************************************************
* 功能:計算一個直方圖物件的均值
* 引數:histogram 直方圖物件指標
* 返回:均值
******************************************************************************/
FvsByte_t HistogramGetMean(const FvsHistogram_t hist)
{
iFvsHistogram_t* histogram = (iFvsHistogram_t*)hist;
FvsInt_t val, i;
val = histogram->nmean;
if (val==-1)
{
val = 0;
for (i = 1; i < 255; i++)
val += i*histogram->ptable[i];
i = histogram->ncount;
if (i>0)
val = val/i;
else
val = 0;
histogram->nmean = val;
}
return (uint8_t)val;
}
/******************************************************************************
* 功能:計算一個直方圖物件的方差
* 引數:histogram 直方圖物件指標
* 返回:方差
******************************************************************************/
FvsUint_t HistogramGetVariance(const FvsHistogram_t hist)
{
iFvsHistogram_t* histogram = (iFvsHistogram_t*)hist;
FvsInt_t val;
FvsInt_t i;
uint8_t mean;
val = histogram->nvariance;
if (val==-1)
{
/* 計算均值 */
mean = HistogramGetMean(hist);
val = 0;
for (i = 0; i < 255; i++)
val += histogram->ptable[i]*(i - mean)*(i - mean);
i = histogram->ncount;
if (i>0)
val = val/i;
else
val = 0;
histogram->nvariance = val;
}
return (FvsUint_t)val;
}
7.實現了主要的影象形態學操作
/*#############################################################################
* 檔名:img_morphology.c
* 功能: 實現了主要的影象形態學操作
*
#############################################################################*/
#include "img_base.h"
#include <string.h>
#define P(x,y) p[(x)+(y)*pitch]
/******************************************************************************
* 功能:影象膨脹演算法
* 引數:image 指紋影象
* 返回:錯誤編號
******************************************************************************/
FvsError_t ImageDilate(FvsImage_t image)
{
FvsInt_t w = ImageGetWidth (image);
FvsInt_t h = ImageGetHeight(image);
FvsInt_t pitch = ImageGetPitch (image);
FvsInt_t size = ImageGetSize (image);
FvsByte_t* p = ImageGetBuffer(image);
FvsInt_t x,y;
if (p==NULL)
return FvsMemory;
for (y=1; y<h-1; y++)
for (x=1; x<w-1; x++)
{
if (P(x,y)==0xFF)
{
P(x-1, y) |= 0x80;
P(x+1, y) |= 0x80;
P(x, y-1) |= 0x80;
P(x, y+1) |= 0x80;
}
}
for (y=0; y<size; y++)
if (p[y])
p[y] = 0xFF;
return FvsOK;
}
/******************************************************************************
* 功能:影象腐蝕演算法
* 引數:image 指紋影象
* 返回:錯誤編號
******************************************************************************/
FvsError_t ImageErode(FvsImage_t image)
{
FvsInt_t w = ImageGetWidth (image);
FvsInt_t h = ImageGetHeight(image);
FvsInt_t pitch = ImageGetPitch (image);
FvsInt_t size = ImageGetSize (image);
FvsByte_t* p = ImageGetBuffer(image);
FvsInt_t x,y;
if (p==NULL)
return FvsMemory;
for (y=1; y<h-1; y++)
for (x=1; x<w-1; x++)
{
if (P(x,y)==0x0)
{
P(x-1, y) &= 0x80;
P(x+1, y) &= 0x80;
P(x, y-1) &= 0x80;
P(x, y+1) &= 0x80;
}
}
for (y=0; y<size; y++)
if (p[y]!=0xFF)
p[y] = 0x0;
return FvsOK;
}
8.實現了影象細化操作
/*#############################################################################
* 檔名:img_thin.c
* 功能: 實現了影象細化操作
*
#############################################################################*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "imagemanip.h"
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif
#define NOT_BK(pos) (image[pos]!=0)
#define IS_BK(pos) (image[pos]==0)
bool_t MatchPattern(uint8_t image[], int x, int y, int w, int h)
{
bool_t nRet = false;
/* 驗證有無出界 */
int lhe = y * w; /* 本行 */
int lup = lhe - w; /* 上一行 */
int ldo = lhe + w; /* 下一行 */
int tl = lup + x - 1; /* 左上 */
int tc = lup + x; /* 中上 */
int tr = lup + x + 1; /* 右上 */
int hl = lhe + x - 1; /* 左 */
int hr = lhe + x + 1; /* 右 */
int bl = ldo + x - 1; /* 左下 */
int bc = ldo + x; /* 中下 */
int br = ldo + x + 1; /* 右下 */
/* 第一模式
? ? ? one not 0
0 1 0
? ? ? one not 0
*/
if ( image[hr]==0 && image[hl]==0 &&
((image[tl]!=0) || (image[tc]!=0) || (image[tr]!=0))&&
((image[bl]!=0) || (image[bc]!=0) || (image[br]!=0))
)
{
nRet = true;
}
/* 同樣的旋轉90度
? 0 ?
? 1 ?
? 0 ?
*/
else
if ( image[tc]==0 && image[bc]==0 &&
((image[bl]!=0) || (image[hl]!=0) || (image[tl]!=0))&&
((image[br]!=0) || (image[hr]!=0) || (image[tr]!=0))
)
{
nRet = true;
}
/*
? ? ?
? 1 0
? 0 1
*/
else
if
(image[br]==0xFF && image[hr]==0 && image[bc]==0 &&
(image[tr]!=0 || image[tc]!=0 ||
image[tl]!=0 || image[hl]!=0 || image[bl]!=0)
)
{
nRet = true;
}
/*
? ? ?
0 1 ?
1 0 ?
*/
else
if
(image[bl]==0xFF && image[hl]==0 && image[bc]==0 &&
(image[br]!=0 || image[hr]!=0 ||
image[tr]!=0 || image[tc]!=0 || image[tl]!=0))
{
nRet = true;
}
/*
1 0 ?
0 1 ?
? ? ?
*/
else
if
(image[tl]==0xFF && image[tc]==0 && image[hl]==0 &&
(image[bl]!=0 || image[bc]!=0 ||
image[br]!=0 || image[hr]!=0 || image[tr]!=0))
{
nRet = true;
}
/*
? 0 1
? 1 0
? ? ?
*/
else
if
(image[tr]==0xFF && image[hr]==0 && image[tc]==0 &&
(image[tl]!=0 || image[hl]!=0 ||
image[bl]!=0 || image[bc]!=0 || image[br]!=0))
{
nRet = true;
}
image[y*w + x] = (nRet==true)?0xFF:0x00;
return nRet;
}
/* 細化影象 */
FvsError_t ImageThin3(Image_t imgf)
{
bool_t Remain;
int temp;
uint8_t* image = ImageGetBuffer(imgf);
register int x, y;
int w = ImageGetWidth(imgf); /* 影象寬度 */
int h = ImageGetHeight(imgf); /* 影象高度 */
int tmp;
int row;
/* 提高細化速度 */
int _lastY;
int _newY;
/* 初始化 */
_lastY = _newY = 1;
/* 標記:全部完成後再處理 */
Remain = true;
while (Remain)
{
_lastY = 1;
_newY = h;
Remain = false;
fprintf(stderr, ".");
temp = false;
for (y = _lastY; y < h-1; y++)
for (x = 1; x < w-1; x++)
{
row = y*w;
tmp = image[row +(x + 1)];
if (image[row + x] == 0xFF && tmp == 0
&& MatchPattern(image, x, y, w, h) == false)
if (temp==false)
{
_newY = min(_newY, y);
Remain = true;
temp = true;
}
}
for (x = w*_lastY; x < w*h; x++)
if (image[x] == 0x00)
image[x] = 0;
temp = false;
for (y = _lastY; y < h-1; y++)
for (x = 1; x < w-1; x++)
{
row = y*w;
tmp = image[(y - 1) * w + x];
if (image[row + x] == 0xFF && tmp == 0
&& MatchPattern(image, x, y, w, h)==false)
if (temp==false)
{
_newY = min(_newY, y);
Remain = true;
temp = true;
}
} /* end for y */
for (x = w*_lastY; x < w*h; x++)
if (image[x] == 0x00)
image[x] = 0;
temp = false;
for (y = _lastY; y < h-1; y++)
for (x = 1; x < w-1; x++)
{
row = y*w;
tmp = image[row +(x - 1)]; /* -> */
if (image[row + x] == 0xFF && tmp == 0
&& MatchPattern(image, x, y, w, h)==false)
if (temp==false)
{
_newY = min(_newY, y);
Remain = true;
temp = true;
}
} /* end for y */
for (x = w*_lastY; x < w*h; x++)
if (image[x] == 0x00)
image[x] = 0;
temp = false;
for (y = _lastY; y < h-1; y++)
for (x = 1; x < w-1; x++)
{
row = y*w;
tmp = image[(y + 1) * w + x];
if (image[row + x] == 0xFF && tmp == 0
&& MatchPattern(image, x, y, w, h)==false)
if (temp==false)
{
_newY = min(_newY, y);
Remain = true;
temp = true;
}
} /* end for y */
for (x = w*_lastY; x < w*h; x++)
if (image[x] == 0x00)
image[x] = 0;
} /* end while */
return FvsOK;
}
9.一些基本的影象操作
/*#############################################################################
* 檔名:img_base.c
* 功能: 一些基本的影象操作
*
#############################################################################*/
#include "img_base.h"
#include "histogram.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
/******************************************************************************
* 功能:影象二值化
* 引數:image 指紋影象
* size 閾值
* 返回:錯誤編號
******************************************************************************/
FvsError_t ImageBinarize(FvsImage_t image, const FvsByte_t limit)
{
FvsInt_t n;
FvsByte_t *pimg = ImageGetBuffer(image);
FvsInt_t size = ImageGetSize(image);
if (pimg==NULL)
return FvsMemory;
/* 迴圈遍歷 */
for (n = 0; n < size; n++, pimg++)
{
/* 閾值化 */
*pimg = (*pimg < limit)?(FvsByte_t)0xFF:(FvsByte_t)0x00;
}
return ImageSetFlag(image, FvsImageBinarized);
}
/******************************************************************************
* 功能:影象翻轉操作
* 引數:image 指紋影象
* 返回:錯誤編號
******************************************************************************/
FvsError_t ImageInvert(FvsImage_t image)
{
FvsByte_t* pimg = ImageGetBuffer(image);
FvsInt_t size = ImageGetSize(image);
FvsInt_t n;
if (pimg==NULL)
return FvsMemory;
for (n = 0; n < size; n++, pimg++)
{
*pimg = 0xFF - *pimg;
}
return FvsOK;
}
/******************************************************************************
* 功能:影象合併操作
* 引數:image1 第一個指紋影象,用於儲存結果
* image2 第二個指紋影象
* 返回:錯誤編號
******************************************************************************/
FvsError_t ImageAverage(FvsImage_t image1, const FvsImage_t image2)
{
FvsByte_t* p1 = ImageGetBuffer(image1);
FvsByte_t* p2 = ImageGetBuffer(image2);
FvsInt_t size1 = ImageGetSize(image1);
FvsInt_t size2 = ImageGetSize(image2);
FvsInt_t i;
if (p1==NULL || p2==NULL)
return FvsMemory;
if (size1!=size2)
return FvsBadParameter;
for (i = 0; i < size1; i++, p1++)
{
*p1 = (*p1+*p2++)>>1;
}
return FvsOK;
}
/******************************************************************************
* 功能:影象邏輯合併操作
* 引數:image1 第一個指紋影象,用於儲存結果
* image2 第二個指紋影象
* 返回:錯誤編號
******************************************************************************/
FvsError_t ImageLogical
(
FvsImage_t image1,
const FvsImage_t image2,
const FvsLogical_t operation
)
{
FvsByte_t* p1 = ImageGetBuffer(image1);
FvsByte_t* p2 = ImageGetBuffer(image2);
FvsInt_t size1 = ImageGetSize(image1);
FvsInt_t i;
if (p1==NULL || p2==NULL)
return FvsMemory;
if (ImageCompareSize(image1, image2)==FvsFalse)
return FvsBadParameter;
switch (operation)
{
case FvsLogicalOr:
for (i = 0; i < size1; i++, p1++)
*p1 = (*p1) | (*p2++);
break;
case FvsLogicalAnd:
for (i = 0; i < size1; i++, p1++)
*p1 = (*p1) & (*p2++);
break;
case FvsLogicalXor:
for (i = 0; i < size1; i++, p1++)
*p1 = (*p1) ^ (*p2++);
break;
case FvsLogicalNAnd:
for (i = 0; i < size1; i++, p1++)
*p1 = ~((*p1) & (*p2++));
break;
case FvsLogicalNOr:
for (i = 0; i < size1; i++, p1++)
*p1 = ~((*p1) | (*p2++));
break;
case FvsLogicalNXor:
for (i = 0; i < size1; i++, p1++)
*p1 = ~((*p1) ^ (*p2++));
break;
}
return FvsOK;
}
/******************************************************************************
* 功能:影象合併操作
* 使用了模計算,0和255的結果是0而不是上一個函式的127。
* 引數:image1 第一個指紋影象,用於儲存結果
* image2 第二個指紋影象
* 返回:錯誤編號
******************************************************************************/
FvsError_t ImageAverageModulo(FvsImage_t image1, const FvsImage_t image2)
{
FvsByte_t* p1 = ImageGetBuffer(image1);
FvsByte_t* p2 = ImageGetBuffer(image2);