最近和朋友開發一款在Android平台上的聲紋識別應用程式,前期到完成整整花費了幾個月時間,名稱定義為:SuperLock 中文名稱為:聲紋鎖。
部落格園的朋友們,可以通過:http://code.google.com/p/voiceprint-model-builder-for-superlock/downloads/list下載。
下面讓我簡單介紹一下開始計劃:
問題的提出主要從Android現在作為主流手機作業系統,鎖屏和開屏應用上還是傳統的密碼、焦點啟用、手搖,還有最近4.0才推出的Face Service。而除了moto推出的真正指紋識別外(具備指紋模數器),市場上的指紋識別都是扯談的東西。所以想出了利用聲紋進行識別的應用程式。
而開始遇到最大的問題就是擔心手機處理的速度是否能跟得上,後來實驗了,已經不是問題。但Android手機錄音得出的語音頻率有時候是不一致的,這個是最大的問題,所以在測試有時候會出現不匹配的現像。但大多數情況下還是一致的。
一般說來,每個人的聲音都有各自的特點,於是我們便可以聽聲辨人,即是說是唯一的。
聲音不同,主要是由音質、音色上的差別造成的。人的發聲器官實際上存在著大小、形態及功能上的差異。發聲控制器官包括聲帶、軟顎、舌頭、牙齒、唇等;發聲共鳴器包括咽腔、口腔、鼻腔。這些器官的微小差異都會導致發聲氣流的改變,形成區別。此外,人發聲的習慣亦有快有慢,用力大小不一,就造成了音強、音長的差別。聽聲辨人,不僅是靠音色各異,更要靠人聲學特徵的相對穩定。
但在現實生活中,以聲辨人卻經常出差誤。一個電話打過來,即使來電者是自己的朋友或是親人,我們也沒有百分百的把握從聲音中判斷出對方身份。於是在沒有來電顯示或備存號碼的情況下,我們也時常“張冠李戴”。
我們引用廣東科技報的文章把聲紋與指紋進行對比:
指紋鎖PK聲紋鎖
安全隱患:
指紋採用單一固定的認證方式,存在永久性的失密隱患。
聲紋採用“語意+聲紋”的雙因子認證,其中語意可動態調整,不存在永久性失密隱患。
使用方便性:
指紋必須試用手指接觸,手指太髒、紋路太淺都無法使用,有局限性。
聲紋屬於非接觸式開啟方式,可徹底解放人的雙手,衛生潔淨。
入侵隱蔽性:
指紋很容易殘留,在預先不知的情況下容易被竊取。
聲紋對通道敏感,錄音無用,模仿無效且在被入侵時需發出聲音,有較強的心理震懾作用。
識別速度:
指紋在實際儲存指紋容量過多時,識別速度會變慢。
聲紋演算法獨特識別速度與人數無關,每次識別時間小於1秒。
裝置易損性:
指紋光學式接觸面容易磨損,矽感式接觸面易受靜電破壞,裝置易受惡意破壞且使用維護成本高。
聲紋用聲音不接觸裝置不易受破壞,維護成本低。
可以看出聲紋的獨特之處了吧。
現附上主介面下翻頁後圓點隨著轉換效果代碼:
1 /************************ Copyright (c) 2011 ************************
2
3 作者:
4
5 Cheung.S.kei
6
7 連絡方式:
8
9 SupperLock0@gmail.com
10 QQ:757689594
11
12 修改時間:
13
14 2011-09-03
15
16 功能描述:
17
18 翻面效果圓形表徵圖
19
20 著作權聲明:
21
22 請尊重開發人員勞動,複製或修改本程式內容請註明地址。
23
24 ************************ Copyright (c) 2011 ************************/
25
26 package com.kei.android.superlock.ui;
27
28 import android.content.Context;
29 import android.graphics.Canvas;
30 import android.graphics.Color;
31 import android.graphics.Paint;
32 import android.util.Log;
33 import android.view.View;
34
35 public class CircleView extends View {
36
37 //輸出log顯示狀態
38 private static final String LOG_TAG = "CircleView";
39 private static final boolean DBG = true;
40
41 private Paint mPaint;
42 //寬高
43 private int mBackgroundWidth;
44 private int mBackgroundHeight;
45 private int mScreenHeight;
46 private int mFinalCenter,mFinalHeight;
47 //半徑
48 private int mCircleRadius;
49
50 private boolean isActive=false;
51
52 public CircleView(Context context,int ScreenWidth,int ScreenHeight,boolean isActive) {
53 super(context);
54 mPaint = new Paint();
55 //去鋸齒
56 mPaint.setAntiAlias(true);
57 mScreenHeight=ScreenHeight;
58 mBackgroundHeight=mScreenHeight/36;
59 mBackgroundWidth=mBackgroundHeight*2;
60 mCircleRadius=mBackgroundHeight/2-2;
61 //中心點不變
62 mFinalCenter=mCircleRadius;
63 mFinalHeight=mBackgroundHeight;
64 this.isActive=isActive;
65 }
66
67 @Override
68 protected void onDraw(Canvas canvas) {
69 // TODO Auto-generated method stub
70 super.onDraw(canvas);
71 if(isActive){
72 //繪圓
73 mBackgroundHeight=mScreenHeight/38;
74 mCircleRadius=mBackgroundHeight/2-2;
75 }else{
76 mBackgroundHeight=mScreenHeight/60;
77 mCircleRadius=mBackgroundHeight/2-2;
78 }
79
80 mPaint.setColor(Color.BLACK);
81 canvas.drawCircle(mFinalCenter+1, mFinalCenter+3, mCircleRadius, mPaint);
82 mPaint.setColor(Color.WHITE);
83 canvas.drawCircle(mFinalCenter+2, mFinalCenter+2, mCircleRadius, mPaint);
84 }
85
86 @Override
87 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
88 final int width=mBackgroundWidth;
89 final int height=mFinalHeight;
90 if (DBG) log("- width: " + width+" - height: " + height);
91 setMeasuredDimension(width, height);
92 }
93
94 private void log(String msg) {
95 Log.e(LOG_TAG, msg);
96 }
97
98 public void updateInvalidate(){
99 this.invalidate();
100 }
101
102 public void reset(){
103 isActive=false;
104 this.invalidate();
105 }
106
107 public void active(){
108 isActive=true;
109 this.invalidate();
110 }
111
112 }
以上為程式預覽圖,歡迎各位下載試用。