結果
基本實現了識別的功能。基本的界面如下
界面長得比較丑,主要是JavaSwing寫界面比較麻煩,寫個菜單欄都要那么多代碼。目前不打算改了。
實現的思路是:使用opencv中自帶的OpenCVFrameGrabber獲取攝像頭的數據,CanvasFrame來顯示攝像頭捕獲的畫面。
點擊注冊和識別都會在捕獲的視頻流自動抓取一幀圖片,點下面的按鈕可以查看拍攝效果
當輸入想要比對的身份,點擊識別之后,會與注冊保存的數據進行比對
准確率還行。
附上部分代碼
public static void OpenCamera()throws Exception, InterruptedException{ OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);//0表示本機攝像頭 當然這里也可以換成網絡攝像頭地址 grabber.start(); //開始獲取攝像頭數據 CanvasFrame canvas = new CanvasFrame("倒計時5秒自動拍照注冊");//新建一個窗口 canvas.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//窗口關閉時程序運行結束 canvas.setAlwaysOnTop(true); int i=0; while(true){ if(i==30){//窗口是否關閉 System.out.println("已關閉"); grabber.stop();//停止抓取 canvas.dispose(); //System.exit(2);//退出 } canvas.showImage(grabber.grab());//獲取攝像頭圖像並放到窗口上顯示, 這里的Frame frame=grabber.grab(); frame表示一幀視頻圖像 //調用doExecuteFrame()方法,將截取的圖片保存在本地 if(i==1)CatchPhoto(grabber.grabFrame(),"./register"+"/"+ MainWindow.ID +".jpg"); Thread.sleep(50);//50毫秒刷新一次圖像 i++; } }
//人臉檢測 ImageInfo imageInfo = getRGBData(new File(register)); List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>(); errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList); System.out.println(faceInfoList); //特征提取 FaceFeature faceFeature = new FaceFeature(); errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature); System.out.println("特征值大小:" + faceFeature.getFeatureData().length); //人臉檢測2 ImageInfo imageInfo2 = getRGBData(new File(discern)); List<FaceInfo> faceInfoList2 = new ArrayList<FaceInfo>(); errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(),imageInfo.getImageFormat(), faceInfoList2); System.out.println(faceInfoList); //特征提取2 FaceFeature faceFeature2 = new FaceFeature(); errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo.getImageFormat(), faceInfoList2.get(0), faceFeature2); System.out.println("特征值大小:" + faceFeature.getFeatureData().length); //特征比對 FaceFeature targetFaceFeature = new FaceFeature(); targetFaceFeature.setFeatureData(faceFeature.getFeatureData()); FaceFeature sourceFaceFeature = new FaceFeature(); sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData()); FaceSimilar faceSimilar = new FaceSimilar(); errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar); //System.out.println("相似度:" + faceSimilar.getScore()); MainWindow.Similarity.setText("相似度:" + faceSimilar.getScore()); //設置活體測試 errorCode = faceEngine.setLivenessParam(0.5f, 0.7f); //人臉屬性檢測 FunctionConfiguration configuration = new FunctionConfiguration(); configuration.setSupportAge(true); configuration.setSupportFace3dAngle(true); configuration.setSupportGender(true); configuration.setSupportLiveness(true); errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration); //性別檢測 List<GenderInfo> genderInfoList = new ArrayList<GenderInfo>(); errorCode = faceEngine.getGender(genderInfoList); //System.out.println("性別:" + genderInfoList.get(0).getGender()); if(genderInfoList.get(0).getGender()==0){ MainWindow.Sex.setText("性別:男" ); } else if(genderInfoList.get(0).getGender()==1){ MainWindow.Sex.setText("性別:女" ); } else{ MainWindow.Sex.setText("性別:未知" ); } //MainWindow.Sex.setText("性別:" + genderInfoList.get(0).getGender()); //年齡檢測 List<AgeInfo> ageInfoList = new ArrayList<AgeInfo>(); errorCode = faceEngine.getAge(ageInfoList); //System.out.println("年齡:" + ageInfoList.get(0).getAge()); MainWindow.Age.setText("年齡:" + ageInfoList.get(0).getAge()); //3D信息檢測 List<Face3DAngle> face3DAngleList = new ArrayList<Face3DAngle>(); errorCode = faceEngine.getFace3DAngle(face3DAngleList); System.out.println("3D角度:" + face3DAngleList.get(0).getPitch() + "," + face3DAngleList.get(0).getRoll() + "," + face3DAngleList.get(0).getYaw()); MainWindow.Angle.setText("3D角度:" + face3DAngleList.get(0).getPitch() + "," + face3DAngleList.get(0).getRoll() + "," + face3DAngleList.get(0).getYaw()); //活體檢測 List<LivenessInfo> livenessInfoList = new ArrayList<LivenessInfo>(); errorCode = faceEngine.getLiveness(livenessInfoList); //System.out.println("活體:" + livenessInfoList.get(0).getLiveness()); MainWindow.LiVing.setText("活體:" + livenessInfoList.get(0).getLiveness()); //IR屬性處理 ImageInfo imageInfoGray = getGrayData(new File("C:\\Users\\user\\Desktop\\test\\photo\\1.jpg")); List<FaceInfo> faceInfoListGray = new ArrayList<FaceInfo>(); errorCode = faceEngine.detectFaces(imageInfoGray.getImageData(), imageInfoGray.getWidth(), imageInfoGray.getHeight(), imageInfoGray.getImageFormat(), faceInfoListGray); FunctionConfiguration configuration2 = new FunctionConfiguration(); configuration2.setSupportIRLiveness(true); errorCode = faceEngine.processIr(imageInfoGray.getImageData(), imageInfoGray.getWidth(), imageInfoGray.getHeight(), imageInfoGray.getImageFormat(), faceInfoListGray, configuration2); //IR活體檢測 List<IrLivenessInfo> irLivenessInfo = new ArrayList<>(); errorCode = faceEngine.getLivenessIr(irLivenessInfo); System.out.println("IR活體:" + irLivenessInfo.get(0).getLiveness()); ImageInfoEx imageInfoEx = new ImageInfoEx(); imageInfoEx.setHeight(imageInfo.getHeight()); imageInfoEx.setWidth(imageInfo.getWidth()); imageInfoEx.setImageFormat(imageInfo.getImageFormat()); imageInfoEx.setImageDataPlanes(new byte[][]{imageInfo.getImageData()}); imageInfoEx.setImageStrides(new int[]{imageInfo.getWidth() * 3}); List<FaceInfo> faceInfoList1 = new ArrayList<>(); errorCode = faceEngine.detectFaces(imageInfoEx, DetectModel.ASF_DETECT_MODEL_RGB, faceInfoList1); FunctionConfiguration fun = new FunctionConfiguration(); fun.setSupportAge(true); errorCode = faceEngine.process(imageInfoEx, faceInfoList1, functionConfiguration); List<AgeInfo> ageInfoList1 = new ArrayList<>(); int age = faceEngine.getAge(ageInfoList1); System.out.println("年齡:" + ageInfoList1.get(0).getAge()); FaceFeature feature = new FaceFeature(); errorCode = faceEngine.extractFaceFeature(imageInfoEx, faceInfoList1.get(0), feature);
問題記錄
1.捕獲視頻流
網上找到了很多方法,比如JMF、ffmpeg等。JMF以前用過,過於老舊了,而且只支持32位系統,想用的話還得用32位的IDE,所以忽略。然后發現用opencv集成了ffmpeg,通過grabber.grab()方法就可以獲取。很簡單。
2.視頻顯示
一開始的想法,grabber.grab()獲取的是一幀一幀的圖片,那么可以再frame里加一個顯示圖片的label,每過十毫秒刷新一次圖片,這樣就起到了播放視頻的效果。但是遇到了問題
使用java.awt.Image 中的方法無法獲取grabber.grab()中的數據,強制類型轉換無效。后來查看OpenCVFrameGrabber的源碼。最后在Frame.Class里發現image的類型
NIO與IO之間是有一些區別的,NIO要更優秀一點,可惜Java界面沒有
所以轉換思路,沒辦法在主窗口播放,那就在新建一個窗口,看起來有點別扭,但受限於技術水平,還是先把功能實現了。
javacv里有一個簡單的新建窗口方式
CanvasFrame canvas = new CanvasFrame("Camera");//新建一個窗口
通過源碼可以看到CanvasFrame是繼承了javax.swing.JFrame類的。使用這個類主要是它里面的showimage方法
里面有適合的數據類型。
3.窗口問題
使用新建窗口顯示視頻時,關閉視頻播放窗口,主窗口也會關閉。
原來關閉窗口使用的是System.exit(0);這個方法直接終止了虛擬機。后來改成了dispose()方法(需要.setDefaultCloseOperation設置為JFrame.DISPOSE_ON_CLOSE)