Python那么牛逼, 除了能够实现人脸识别, 还能做什么呢? 指纹识别!
说目前市面上有两种指纹识别,分别是光学式和电容式指纹识别。
先说说指纹识别界的明星——电容式指纹识别
电容式指纹识别要比光学式的复杂许多,其原理是将压力感测、电容感测、热感测等感测器整合于一块芯片中,当指纹按压芯片表面时,内部电容感测器会根据指纹波峰与波谷而产生的电荷差(或是温差),形成指纹影像,再通过与手机内部的指纹库进行匹配,从而完成指纹识别。
因为电容式指纹识别技术较为复杂,对技术研发和积累有较高要求,并且涉及大量专利,所以目前全球只有少数公司能在这方面提供领先的技术产品,例如Authen Tec和Validity上。
然后是光学式指纹识别,大家上班常见的指纹考勤机就是光学式指纹识别。
这类光学式指纹识别主要包括4个方面功能
指纹模块负责采集指纹图像。
数字信号处理器主要把采集到的指纹图像转化为数字信号。
微控制器是整个系统的控制单元,在这里将进行指纹的验证以及输出指令。
液晶显示器将输出指纹验证结果。
当我们把手指放在指纹考勤机上时,通过镜面反射原理,指纹模块就会采集指纹图像
接着指纹图像就会被数字信号处理器转换成数字信号
然后通过微控制器将数字信号与指纹库里的指纹进行匹配,匹配结果将通过液晶显示器显示出来。这就是光学式指纹识别的工作原理。
电容式与光学式指纹识别主要在指纹的采集方式上拥有较大差异,而在指纹的验证过程中则基本类似。然而因为电容式指纹识别拥有体积小、适用性广的优点,已经有越来越多的设备采用电容式指纹识别,未来的主流将是电容式指纹识别。
我们手掌及其手指、脚、脚趾内侧表面的皮肤凸凹不平产生的纹路会形成各种各样的图案。这些纹路的存在增加了皮肤表面的摩擦力,使得我们能够用手来抓起重物。人们也注意到,包括指纹在内的这些皮肤的纹路在图案、断点和交叉点上各不相同,也就是说,是唯一的。依靠这种唯一性,我们就可以把一个人同他的指纹对应起来,通过比较他的指纹和预先保存的指纹进行比较,就可以验证他的真实身份。这种依靠人体的身体特征来进行身份验证的技术称为生物识别技术,指纹识别是生物识别技术的一种。
安全性是许多系统要首先考虑的问题,尽管使用者一向都相当讨厌安全检查机制介入他们的工作中,但管理者
指纹识别系统
仍然需要这样的一种检查访问与使用情形的手续与方法。如果没有办法清楚明确的辨认使用者身份的话,那么你也将无法确认是哪位使用者,以及他究竟操作了什么行动。所以使用者会被强迫去进行一些密码机制或硬件标志以帮助我们去追踪究竟是谁做了些什么?
现行的许多计算机系统中,包括许多非常机密的系统,都是使用“用户ID+密码”的方法来进行用户的身份认证和访问控制的。实际上,这种方案隐含着一些问题。例如,密码容易被忘记,也容易被别人窃取。而且,如果用户忘记了他的密码,他就不能进入系统,当然可以通过系统管理员重新设定密码来重新开始工作,但是一旦系统管理员忘记了自己的密码,整个系统也许只有重新安装后才能工作。有关机构的调查表明,因为忘记密码而产生的问题已经成为IT厂商售后服务的最常见问题之一;密码被别人盗取则更是一件可怕的事情,因为用心不良的人可能会进一步窃取公司机密数据、可能会盗用别人的名义做不正当的事情、甚至从银行、ATM终端上提取别人的巨额存款。实际上,密码的盗取比较容易,别人只要留意你在计算机终端前输入口令时的击键动作就可以知道你的密码,甚至可以通过你的生日、年龄、姓名或者其他一些信息猜出你的密码(许多人使用自己的生日作为密码),密码还可以被解破--众所周知,高度机密的美国一些军事机构计算机网络曾不止一次被黑客侵入,黑客们实际上就是解破了这些计算机网络的某一合法用户的密码来开始的。尽管现行系统通过要求用户及时改变他们的口令来防止被盗用的行为,但这种方法不但增加了用户的记忆负担,也不能从根本上解决问题。
随着科技的进步,指纹识别技术已经开始走入了我们的日常生活之中。目前在世界上许多公司和研究机构都在指纹识别技术的研究中取得一些突破性技术,从而推出了许多新产品,这些产品已经开始在许多领域得以运用。BAC公司推出的业界领先的SecureTouch指纹识别机产品,就是非常具有应用价值和前景的。
除了计算机网络及其应用系统外,一些传统的需要进行身份验证的场合,也存在着类似的安全性问题。例如证件的伪造和盗用、不正当的转借等。一些犯罪通过伪造证件进入机密场所以窃取机密信息,有的犯罪伪造签证和护照非法入境或移民,这是因为传统的证件使用了易于伪造、未经加密的纸制证件。另一个例子是考勤机,它的使用方便了企业进行职工的考勤管理,但使领导头疼的是经常有人弄虚作假,代别人打卡。
丢了钥匙不仅打不开门,还要当心坏人拾到你的钥匙盗取你的家财,其他使用钥匙的场合同样也有如此的问题……
这些问题都说明,现行的系统安全性技术已经遭遇严峻的挑战!
指纹识别技术
由于人体的身体特征具有不可复制的特点,人们把目光转向了生物识别技术,希望可以籍此技术来应付现行系统安全所面临的的挑战。要把人体的特证用于身份识别,这些特征必须具有唯一性和稳定性。研究和经验表明,人的指纹、掌纹、面孔、发音、虹膜、视网膜、骨架等都具有唯一性和稳定性的特征,即每个人的这些特征都与别人不同、且终生不变,因此就可以据此识别出人的身份。基于这些特征,人们发展了指纹识别、面部识别、发音识别等多种生物识别技术,许多技术都已经成熟并得以应用,其中的指纹识别技术更是生物识别技术的热点。
指纹识别技术的发展得益于现代电子集成制造技术和快速可靠的算法的研究。尽管指纹只是人体皮肤的一小部分,但用于识别的数据量相当大,对这些数据进行比对也不是简单的相等与不相等的问题,而是使用需要进行大量运算的模糊匹配算法。现代电子集成制造技术使得我们可以制造相当小的指纹图象读取设备,同时飞速发展的个人计算机运算速度提供了在微机甚至单片机上可以进行两个指纹的比对运算的可能。另外,匹配算法可靠性也不断提高,指纹识别技术已经非常实用。
验证和辨识
分类
应用系统利用指纹识别技术可以分为两类,即验证(Verification)和辨识(Identification)。 验证就是通过把一个现场采集到的指纹与一个已经登记的指纹进行一对一的比对(one-to-one matching),来确认身份的过程。作为验证的前提条件,他或她的指纹必须在指纹库中已经注册。指纹以一定的压缩格式存贮,并与其姓名或其标识(ID,PIN)联系起来。随后在比对现场,先验证其标识,然后,利用系统的指纹与现场采集的指纹比对来证明其标识是合法的。验证其实是回答了这样一个问题:"他是他自称的这个人吗?"这是应用系统中使用得较多的方法。
辨识
则是把现场采集到的指纹同指纹数据厍中的指纹逐一对比,从中找出与现场指纹相匹配的指纹。这也叫“一对多匹配(one-to-many matching)”。辨识其实是回答了这样一个问题:“他是谁?”辨识主要应用于犯罪指纹匹配的传统领域中。一个不明身份的人的指纹与指纹库中有犯罪记录的人指纹进行比对,来确定此人是否曾经有过犯罪记录。
应用
除了验证的一对一和辨识的一对多比对方法,在实际应用中还有“一对几个匹配(one-to-few matching)”。一对几个匹配主要应用于只有“几个(few)”用户的系统中,比如一个家庭的成员要进入他们的房子。 “几个”所包含的数目一般为5~20人。一对几个匹配一般使用与一对一匹配相同的方法。
可靠性问题
技术优点
1、指纹是人体独一无二的特征,并且它们的复杂度足以提供用于鉴别的足够特征,德施曼指纹锁就是建立在此特性之上;
2、如果要增加可靠性,只需登记更多的指纹、鉴别更多的手指,最多可以多达十个,而每一个指纹都是独一无二的;
3、扫描指纹的速度很快,使用非常方便;
4、读取指纹时,用户必需将手指与指纹采集头相互接触,与指纹采集头直接;
5、接触是读取人体生物特征最可靠的方法;
6、指纹采集头可以更加小型化,并且价格会更加的低廉;
技术缺点
1、某些人或某些群体的指纹指纹特征少,难成像;
2、过去因为在犯罪记录中使用指纹,使得某些人害怕“将指纹记录在案”。
3、实际上现在的指纹鉴别技术都可以不存储任何含有指纹图像的数据,而只是存储从指纹中得到的加密的指纹特征数据;
4、每一次使用指纹时都会在指纹采集头上留下用户的指纹印痕,而这些指纹痕迹存在被用来复制指纹的可能性。
衡量
由于计算机处理指纹时,只是涉及了指纹的一些有限的信息,而且比对算法并不是精确匹配,其结果也不能保证100%准确。指纹识别系统的特定应用的重要衡量标志是识别率。主要由两部分组成,拒判率(FRR)和误判率(FAR)。我们可以根据不同的用途来调整这两个值。FRR和FAR是成反比的。用0-1.0或百分比来表达这个数。ROC(Receiver Operating Curve)-曲线给出FAR和FRR之间的关系。
级别
尽管指纹识别系统存在着可靠性问题,但其安全性也比相同可靠性级别的“用户ID+密码”方案的安全性高得多。例如采用四位数字密码的系统,不安全概率为0.01%,如果同采用误判率为0.01%指纹识别系统相比,由于不诚实的人可以在一段时间内试用所有可能的密码,因此四位密码并不安全,但是他绝对不可能找到一千个人去为他把所有的手指(十个手指)都试一遍。正因为如此,权威机构认为,在应用中1%的误判率就可以接受。
FRR实际上也是系统易用性的重要指标。由于FRR和FAR是相互矛盾的,这就使得在应用系统的设计中,要权衡易用性和安全性。一个有效的办法是比对两个或更多的指纹,从而在不损失易用性的同时,极大地提高了系统安全性。
应用
利用指纹识别技术的应用系统常见有两种方法,即嵌入式系统和连接PC的桌面应用系统。嵌入式系统是一个相对独立的完整系统,它不需要连接其他设备或计算机就可以独立完成其设计的功能,像指纹门锁、指纹考勤终端就是嵌入式系统。其功能较为单一,应用于完成特定的功能。而连接PC的桌面应用系统具有灵活的系统结构,并且可以多个系统共享指纹识别设备,可以建立大型的数据库应用。当然,由于需要连接计算机才能完成指纹识别的功能,限制了这种系统在许多方面的应用。
当今市场上的指纹识别系统厂商,除了提供完整的指纹识别应用系统及其解决方案外,可以提供从指纹取像设备的OEM产品到完整的指纹识别软件开发包,从而使得无论是系统集成商还是应用系统开发商都可以自行开发自己的增值产品,包括嵌入式的系统和其他应用指纹验证的计算机软件。
指纹识别系统可以分为两类:验证和辨识。验证就是把一个现场采集到的指纹与一个己经登记的指纹进行一对一的比对,来确认身份的过程;辨识则是把现场采集到的指纹同指纹数据库中的指纹逐一对比,从中找出与现场指纹相匹配的指纹。
指纹验证和辨识在比对算法和系统设计上各有特点,例如验证系统一般只考虑对完整的指纹进行比对,而辨识系统要考虑残纹的比对;验证系统对比对算法的速度要求不如辨识系统高,但更强调易用性;另外在辨识系统中,一般要使用分类技术来加快查询的速度。指纹门禁识别系统是指纹应用系统中验证的一种。
指纹门禁识别系统以手指取代传统的钥匙,使用时只需将手指平放在指纹采集仪的采集窗口上,即可完成开锁任务,操作十分简便,避免了其它门禁系统(传统机械锁、密码锁、识别卡等)有可能被伪造、盗用、遗忘、破译等弊端。
指纹门禁识别系统的硬件主要由微处理器、指纹识别模块、液晶显示模块、键盘、实时时钟/日历芯片、电控锁和电源等组成。微处理器作为系统的上位机,控制整个系统。指纹识别模块主要完成指纹特征的采集、比对、存储、删除等功能。液晶显示模块用于显示开门记录、实时时钟和操作提示等信息,和键盘一起组成人机界面。
按系统功能,软件主要由指纹处理模块、液晶显示模块、实时时钟模块和键盘扫描模块等组成。指纹处理模块主要负责微处理器与指纹识别模块之间命令和返回代码的信息处理;液晶显示模块根据液晶显示模块的时序,编写驱动程序,以实现显示汉字、字符的目的;实时时钟模块根据时钟芯片的时序,编写通讯程序.实现对时钟芯片的读写操作;键盘扫描模块就是根据键盘的设计原理编写键盘程序来识别有无按键动作和按下键的键号。
按操作流程,软件主要由指纹开门程序、指纹管理程序、密码管理程序和系统设置程序四部分组成。其中指纹管理、密码管理和系统设置三部分只有管理员才有此权限。指纹管理程序由登记指纹模板程序、删除指纹模板程序、清空指纹模板程序和浏览开门记录程序四部分组成;密码管理程序由密码修改程序和密码开门程序两部分组成;系统设置程序由时间设置程序和日期设置程序两部分组成。
应用实例
指纹识别技术可以通过几种方法应用到许多方面。本文在上面已经介绍的通过使用指纹验证来取代各个计算机应用程序的密码就是最为典型的实例。可以想象如果计算机上的所有系统和应用程序都可以使用指纹验证的话,人们使用计算机就会非常方便和安全,用户不再讨厌必要的安全性检查,而IT开发商的售后服务工作也会减轻许多。IBM公司已经开发成功并广泛应用的Global Sign On软件通过定义唯一的口令,或者使用指纹,就可以在公司整个网络上畅行无阻。 把指纹识别技术同IC卡结合起来,是目前最有前景的一个方向之一。该技术把卡的主人的指纹(加密后)存储在IC卡上,并在IC卡的读卡机上加装指纹识别系统,当读卡机阅读卡上的信息时,一并读入持卡者的指纹,通过比对卡上的指纹与持卡者的指纹就可以确认持卡者的是否卡的真正主人,从而进行下一步的交易。在更加严格的场合,还可以进一步同后端主机系统数据库上的指纹作比较。指纹IC卡可以广泛地运用于许多行业中,例如取代现行的ATM卡、制造防伪证件(签证或护照、公费医疗卡、会员卡、借书卡等)。目前ATM提款机加装指纹识别功能在美国已经开始使用。持卡人可以取消密码 (避免老人和孩子记忆密码的困难)或者仍旧保留密码,在操作上按指纹与密码的时间差不多。
近年来,自动发送信息的互联网络,带给人们的方便与利益,正在快速增长之中,但也因此产生了很多的问题,尤其在信息安全方面。无论是团体或者个人的信息,都害怕在四通八达的网络上传送而发生有损权益的事情。由于指纹特征数据可以通过电子邮件或其他传输方法在计算机网络上进行传输和验证,通过指纹识别技术,限定只有指定的人才能访问相关信息,可以极大地提高网上信息的安全性,这样,包括网上银行、网上贸易、电子商务的一系列网络商业行为,就有了安全性保障。在SFNB(Security First Network Bank安全第一网络银行),就是通过互联网络来进行资金划算的,他们目前正在实施以指纹识别技术为基础的保障安全性的项目,以增强交易的安全性。
在医院里,指纹识别技术可以验证病人身份,例如输血管理。指纹识别技术也有助于证实寻求公共救援、医疗及其他政府福利或者保险金的人的身份确认。在这些应用中,指纹识别系统将会取代或者补充许多大量使用照片和ID的系统。
核心代码一:
package com.zwh.rxfingerprinter; public class MainActivity extends AppCompatActivity { private FingerPrinterView fingerPrinterView; private int fingerErrorNum = 0; // 指纹错误次数 RxFingerPrinter rxfingerPrinter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fingerPrinterView = (FingerPrinterView) findViewById(R.id.fpv); fingerPrinterView.setOnStateChangedListener(new FingerPrinterView.OnStateChangedListener() { @Override public void onChange(int state) { if (state == FingerPrinterView.STATE_CORRECT_PWD) { fingerErrorNum = 0; Toast.makeText(MainActivity.this, "指纹识别成功", Toast.LENGTH_SHORT).show(); } if (state == FingerPrinterView.STATE_WRONG_PWD) { Toast.makeText(MainActivity.this, "指纹识别失败,还剩" + (5-fingerErrorNum) + "次机会", Toast.LENGTH_SHORT).show(); fingerPrinterView.setState(FingerPrinterView.STATE_NO_SCANING); } } }); rxfingerPrinter = new RxFingerPrinter(this); findViewById(R.id.btn_open).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { fingerErrorNum = 0; rxfingerPrinter.unSubscribe(this); Subscription subscription = rxfingerPrinter.begin().subscribe(new Subscriber<Boolean>() { @Override public void onStart() { super.onStart(); if (fingerPrinterView.getState() == FingerPrinterView.STATE_SCANING) { return; } else if (fingerPrinterView.getState() == FingerPrinterView.STATE_CORRECT_PWD || fingerPrinterView.getState() == FingerPrinterView.STATE_WRONG_PWD) { fingerPrinterView.setState(FingerPrinterView.STATE_NO_SCANING); } else { fingerPrinterView.setState(FingerPrinterView.STATE_SCANING); } } @Override public void onCompleted() { } @Override public void onError(Throwable e) { if(e instanceof FPerException){ Toast.makeText(MainActivity.this,((FPerException) e).getDisplayMessage(),Toast.LENGTH_SHORT).show(); } } @Override public void onNext(Boolean aBoolean) { if(aBoolean){ fingerPrinterView.setState(FingerPrinterView.STATE_CORRECT_PWD); }else{ fingerErrorNum++; fingerPrinterView.setState(FingerPrinterView.STATE_WRONG_PWD); } } }); rxfingerPrinter.addSubscription(this,subscription); } }); } @Override protected void onDestroy() { super.onDestroy(); rxfingerPrinter.unSubscribe(this); } }
核心代码二:
package com.zwh.rxfingerprinter; /** * Created by Zhangwh on 2016/12/29 0029. * email:[email protected] */ public class FingerPrinterView extends View{ public final static int STATE_NO_SCANING = 0; public final static int STATE_WRONG_PWD = 1; public final static int STATE_CORRECT_PWD = 2; public final static int STATE_SCANING = 3; public int mCurrentState = STATE_NO_SCANING; private Resources mResources; public static int DEFAULT_DURATION = 700; private Animation mShakeAnim = null; // 抖动的动画 ValueAnimator valueAnimator; private float mFraction = 0f,mFraction2 = 1f; private int scaningCount = 0; float scale =1.0f; private boolean isAnim=true; //判断是否要继续动画 private boolean isScale=false; //判断是否要缩放 private Paint mBitPaint; private Bitmap mFingerRed,mFingerGreen, mFingerGrey; private Rect mSrcRect, mDestRect; private int mBitWidth, mBitHeight; private int mWidth, mHeight; OnStateChangedListener listener; public FingerPrinterView(Context context) { this(context,null); } public FingerPrinterView(Context context, AttributeSet attrs) { this(context, attrs,0); } public FingerPrinterView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mResources = getResources(); //mShakeAnim = AnimationUtils.loadAnimation(context, R.anim.anim_lockpattern_shake_x); initBitmap(); initPaint(); } private void initPaint() { mBitPaint = new Paint(); // 防抖动 mBitPaint.setDither(true); // 开启图像过滤 mBitPaint.setFilterBitmap(true); } private void initBitmap() { mFingerRed = ((BitmapDrawable) mResources.getDrawable(R.drawable.finger_red)).getBitmap(); mFingerGreen = ((BitmapDrawable) mResources.getDrawable(R.drawable.finger_green)).getBitmap(); mFingerGrey = ((BitmapDrawable) mResources.getDrawable(R.drawable.finger_grey)).getBitmap(); mBitWidth = mFingerRed.getWidth(); mBitHeight = mFingerRed.getHeight(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; mFingerRed = setScale(mFingerRed); mFingerGreen = setScale(mFingerGreen); mFingerGrey = setScale(mFingerGrey); mBitWidth = mFingerRed.getWidth(); mBitHeight = mFingerRed.getHeight(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mBitPaint.setAlpha(255); mDestRect = new Rect((int) (mBitHeight*(1-mFraction2)), (int) (mBitHeight*(1-mFraction2)), (int) (mBitHeight*mFraction2), (int) (mBitHeight*mFraction2)); mSrcRect = new Rect(0, 0, mBitWidth, mBitHeight); canvas.drawBitmap(mFingerGrey, mSrcRect, mDestRect, mBitPaint); if(true){ if(scaningCount == 0){ mDestRect = new Rect(0, 0, mBitWidth, (int) (mBitHeight*mFraction)); mSrcRect = new Rect(0, 0, mBitWidth, (int) (mBitHeight*mFraction)); canvas.drawBitmap(mFingerGreen, mSrcRect, mDestRect, mBitPaint); }else if(scaningCount%2==0){ if(mFraction<=0.5){ mBitPaint.setAlpha((int) (255*(1-mFraction))); canvas.drawBitmap(mFingerRed, mSrcRect, mDestRect, mBitPaint); }else{ mBitPaint.setAlpha((int) (255*mFraction)); canvas.drawBitmap(mFingerGreen, mSrcRect, mDestRect, mBitPaint); } }else{ if(mFraction<=0.5){ mBitPaint.setAlpha((int) (255*(1-mFraction))); canvas.drawBitmap(mFingerGreen, mSrcRect, mDestRect, mBitPaint); }else{ mBitPaint.setAlpha((int) (255*mFraction)); canvas.drawBitmap(mFingerRed, mSrcRect, mDestRect, mBitPaint); } } } if(isScale){ if(mCurrentState == STATE_WRONG_PWD){ canvas.drawBitmap(mFingerRed, mSrcRect, mDestRect, mBitPaint); } if(mCurrentState == STATE_CORRECT_PWD){ canvas.drawBitmap(mFingerGreen, mSrcRect, mDestRect, mBitPaint); } } } public void startScaning() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.f, 100.f); valueAnimator.setDuration(DEFAULT_DURATION); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @SuppressLint("NewApi") @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mFraction = valueAnimator.getAnimatedFraction(); invalidate(); } }); valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { if(isScale){ isScale = false; } } @Override public void onAnimationEnd(Animator animator) { mFraction = 0; scaningCount++; if(mCurrentState == STATE_WRONG_PWD&&scaningCount%2==1){ isScale = true; isAnim = false; startScale(); } if(mCurrentState == STATE_CORRECT_PWD&&scaningCount%2==0){ isScale = true; isAnim = false; startScale(); } if(isAnim){ startScaning(); } } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } } private void startScale() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.f, 100.f); valueAnimator.setDuration(500); valueAnimator.setInterpolator(new OvershootInterpolator(1.2f)); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mFraction2 = 0.85f+0.15f*valueAnimator.getAnimatedFraction(); invalidate(); } }); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if(listener!=null){ listener.onChange(mCurrentState); } } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } } private void startReset() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.f, 100.f); valueAnimator.setDuration(DEFAULT_DURATION); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mFraction = 1-valueAnimator.getAnimatedFraction(); invalidate(); } }); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); startScaning(); } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } } public void setState(int state) { mCurrentState = state; switch (state) { case STATE_SCANING: startScaning(); break; case STATE_WRONG_PWD: break; case STATE_CORRECT_PWD: break; case STATE_NO_SCANING: resetConfig(); break; default: break; } } public int getState(){ return mCurrentState; } /** * 处理图片缩放 */ private Bitmap setScale(Bitmap a) { scale = ((float)(mWidth) / mBitWidth); Matrix mMatrix = new Matrix(); mMatrix.postScale(scale, scale); Bitmap bmp = Bitmap.createBitmap(a, 0, 0, a.getWidth(), a.getHeight(), mMatrix, true); return bmp; } public void resetConfig(){ mCurrentState = STATE_NO_SCANING; startReset(); mFraction = 0f; mFraction2 = 1f; scaningCount = 0; scale =1.0f; isAnim=true; isScale=false; } public void setOnStateChangedListener(OnStateChangedListener listener){ this.listener = listener; } public interface OnStateChangedListener { public void onChange(int state); } }
效果图片: