Springboot實(shí)現(xiàn)人臉識(shí)別與WebSocket長連接的實(shí)現(xiàn)代碼
0.什么是WebSocket,由于普通的請(qǐng)求是間斷式發(fā)送的,如果要同一時(shí)間發(fā)生大量的請(qǐng)求,必然導(dǎo)致響應(yīng)速度慢(因?yàn)楦鶕?jù)tcp協(xié)議要經(jīng)過三層握手,如果不持續(xù)發(fā)送,就會(huì)導(dǎo)致n多次握手,關(guān)閉連接,打開連接)
1.業(yè)務(wù)需求: 由于我需要使用java來處理視頻的問題,視頻其實(shí)就是圖片,相當(dāng)于每張圖片就是幀,不停發(fā)送幀去實(shí)現(xiàn)人臉失敗,然后返回處理結(jié)果,(支付寶刷臉支付也是同樣的道理)
2.前端建立WebSocket()對(duì)象,onMessage函數(shù)監(jiān)聽返回的結(jié)果
<!DOCTYPE html> <html> <head> <title>視頻幀捕獲</title> </head> <body> <video id="videoElement" autoplay></video> <canvas id="canvasElement" style="display: none;"></canvas> <script> //如果是https協(xié)議的話,就需要改為 wss var socket = new WebSocket("ws://localhost:8080/facedetect"); const video = document.getElementById('videoElement'); const canvas = document.getElementById('canvasElement'); const context = canvas.getContext('2d'); socket.onopen = function() { console.log("xxxx"); // 每1秒發(fā)送一次視頻幀數(shù)據(jù),必須要在這里寫定時(shí)器,因?yàn)榇蜷_連接后才能發(fā)送請(qǐng)求,不然每次都會(huì)報(bào)Websocket close的錯(cuò)誤 setInterval(captureFrame,10000) }; socket.onmessage = function(event) { var result = event.data; // 處理服務(wù)器返回的結(jié)果 console.log(result);//打印出結(jié)果 }; socket.onclose = function(event) { console.log("WebSocket已關(guān)閉"); }; socket.onerror = function(event) { console.error('WebSocket錯(cuò)誤:', event); }; navigator.mediaDevices.getUserMedia({ video: true }) .then(stream => { video.srcObject = stream; }) .catch(error => { console.error('無法訪問攝像頭:', error); }); function captureFrame() { context.drawImage(video, 0, 0, canvas.width, canvas.height); const imageDataUrl = canvas.toDataURL('image/jpeg', 0.5); console.log(imageDataUrl) socket.send(imageDataUrl); // 將數(shù)據(jù)URL發(fā)送到WebSocket服務(wù)器 } // 每隔一段時(shí)間捕獲一幀并發(fā)送到Servlet </script> </body> </html>
3.后端寫配置類,配置websocket的路徑
@Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //錄入人臉數(shù)據(jù)頁面 registry.addHandler(myHandler(), "/face").setAllowedOrigins("*"); //人臉識(shí)別頁面 registry.addHandler(myHandler1(), "/facedetect").setAllowedOrigins("*"); } @Bean public WebSocketHandler myHandler() { return new FaceController(); } @Bean public WebSocketHandler myHandler1() { return new FaceController1(); } }
4.寫controller
//人臉錄入的controller @Controller @RequestMapping("/face") @CrossOrigin public class FaceController extends TextWebSocketHandler { private WebSocketSession session; // 處理WebSocket連接請(qǐng)求 @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { System.out.println("WebSocket連接已建立"); // 保存WebSocket會(huì)話 this.session = session; } // 處理WebSocket文本消息 @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { String text = message.getPayload(); System.out.println(text); text = text.replaceFirst("^data:image/[^;]+;base64,?\\s*", ""); text = text.replaceAll("[^A-Za-z0-9+/=]", ""); System.out.println(text); byte[] imageBytes = Base64.getDecoder().decode(text); if (imageBytes != null) { try { // 讀取字節(jié)數(shù)組并返回BufferedImage對(duì)象 ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes); BufferedImage bufferedImage = ImageIO.read(bis); if (bufferedImage != null) { // 示例:顯示圖像寬度和高度 int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); System.out.println("圖像寬度:" + width); System.out.println("圖像高度:" + height); //錄入人臉 Employee e1 = HRService.addEmp(UUID.randomUUID().toString().substring(0,10), bufferedImage); ImageService.saveFaceImage(bufferedImage, e1.getCode());// 保存員工照片文件 System.out.println(e1.getCode()); // 在這里可以對(duì)BufferedImage對(duì)象進(jìn)行其他操作 } else { System.out.println("無法讀取圖像"); } } catch (Exception e) { e.printStackTrace(); } } else { System.out.println("無效的base64數(shù)據(jù)"); } } // 根據(jù)接收到的文本消息進(jìn)行相應(yīng)的處理 }
//人臉檢測的控制器 @Controller @RequestMapping("/facedetect") @CrossOrigin public class FaceController1 extends TextWebSocketHandler { private WebSocketSession session; // 處理WebSocket連接請(qǐng)求 @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { System.out.println("WebSocket連接已建立"); // 保存WebSocket會(huì)話 this.session = session; } // 處理WebSocket文本消息 @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { System.out.println("detect"); String text = message.getPayload(); System.out.println(text); text = text.replaceFirst("^data:image/[^;]+;base64,?\\s*", ""); text = text.replaceAll("[^A-Za-z0-9+/=]", ""); System.out.println(text); byte[] imageBytes = Base64.getDecoder().decode(text); if (imageBytes != null) { try { // 讀取字節(jié)數(shù)組并返回BufferedImage對(duì)象 ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes); BufferedImage bufferedImage = ImageIO.read(bis); if (bufferedImage != null) { FaceEngineService.loadAllFaceFeature(); FaceFeature faceFeature = FaceEngineService.getFaceFeature(bufferedImage); // 獲取當(dāng)前幀中出現(xiàn)的人臉對(duì)應(yīng)的特征碼 String code = FaceEngineService.detectFace(faceFeature); System.out.println(code); if (code != null) {// 如果特征碼不為null,表明畫面中存在某員工的人臉 Employee e = HRService.getEmp(code);// 根據(jù)特征碼獲取員工對(duì)象 HRService.addClockInRecord(e);// 為此員工添加打卡記錄 // 文本域添加提示信息 session.sendMessage(new TextMessage("打卡成功")); } // 在這里可以對(duì)BufferedImage對(duì)象進(jìn)行其他操作 } else { session.sendMessage(new TextMessage("打卡成功")); } } catch (Exception e) { e.printStackTrace(); } } else { System.out.println("無效的base64數(shù)據(jù)"); } } // 根據(jù)接收到的文本消息進(jìn)行相應(yīng)的處理 }
到此這篇關(guān)于Springboot實(shí)現(xiàn)人臉識(shí)別與WebSocket長連接的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Springboot WebSocket長連接內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java+selenium 網(wǎng)易云音樂刷累計(jì)聽歌數(shù)的方法
這篇文章主要介紹了java+selenium 網(wǎng)易云音樂刷累計(jì)聽歌數(shù)的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06mybatis的xml中使用@符號(hào)調(diào)用類方法示例
這篇文章主要為大家介紹了mybatis的xml中使用@符號(hào)調(diào)用類方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12java.lang.AbstractMethodError: org.apache.xerces.dom.Documen
這篇文章主要介紹了java.lang.AbstractMethodError: org.apache.xerces.dom.DocumentImpl.setXmlVersion問題解決方法,導(dǎo)致本文問題的原因是缺少一個(gè)xerces.jar jar包,需要的朋友可以參考下2015-03-03java利用delayedQueue實(shí)現(xiàn)本地的延遲隊(duì)列
這篇文章主要給大家介紹了java利用delayedQueue實(shí)現(xiàn)本地的延遲隊(duì)列的相關(guān)資料,文中介紹的非常詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。2017-04-04java控制臺(tái)實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java控制臺(tái)實(shí)現(xiàn)學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02關(guān)于springboot使用rocketmq?RocketMQMessageListener參數(shù)問題
這篇文章主要介紹了springboot使用rocketmq?RocketMQMessageListener參數(shù)問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值需要的朋友可以參考下2022-11-11