今天给大家分享的是SpringBoot利用Socket与Python深度学习算法进行通信,并将Python算法处理后的帧图片转化为Base64传给SpringBoot后端,最终在Vue前端显示的三方交互教程。
我这里的算法(video.py)是利用摄像头检测人脸,标出先验框,然后返回标注好的视频帧,其他算法一样的思路。
#-------------------------------------#
# 调用摄像头检测
#-------------------------------------#
from retinaface import Retinaface
from PIL import Image
import numpy as np
import cv2
import time
def facetest():
retinaface = Retinaface()
# 调用摄像头
capture=cv2.VideoCapture(0) # capture=cv2.VideoCapture("1.mp4")
fps = 0.0
t1 = time.time()
# 读取某一帧
ref,frame=capture.read()
# 格式转变,BGRtoRGB
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
# 进行检测
frame = np.array(retinaface.detect_image(frame))
# RGBtoBGR满足opencv显示格式
frame = cv2.cvtColor(frame,cv2.COLOR_RGB2BGR)
fps = ( fps + (1./(time.time()-t1)) ) / 2
print("fps= %.2f"%(fps))
#标注视频帧
frame = cv2.putText(frame, "fps= %.2f"%(fps), (0, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
capture.release()
#返回标注好的视频帧,这里返回的是opencv的类型
return frame
将python脚本写成进程为java提供服务,在java应用程序中调用python进程提供的服务。(这里提一下各种方式读入的图片都可以转成Base64,但是转化方式不同,个人觉得opencv最不容易,因为转换方式不对很可能会导致前端无法正常显示,因此在这里我就以opencv格式来讲解,当然读入图片的方式还有两种,一种是f.read()以二进制读入,很多博客都是以此为例,故不详细讲解。另一种是PIL读入的Image是包含在opencv转化内了。)
#导入深度学习算法
from video import facetest
import cv2
import socket
import threading
from PIL import Image
import base64
import json
from io import BytesIO
def main():
# 创建服务器套接字
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 获取本地主机名称
host = socket.gethostname()
# 设置一个端口
port = 12345
# 将套接字与本地主机和端口绑定
serversocket.bind((host, port))
# 设置监听最大连接数
serversocket.listen(5)
# 获取本地服务器的连接信息
myaddr = serversocket.getsockname()
print("服务器地址:%s" % str(myaddr))
# 循环等待接受客户端信息
while True:
# 获取一个客户端连接
clientsocket, addr = serversocket.accept()
print("连接地址:%s" % str(addr))
try:
t = ServerThreading(clientsocket) # 为每一个请求开启一个处理线程
t.start()
pass
except Exception as identifier:
print(identifier)
pass
pass
serversocket.close()
pass
class ServerThreading(threading.Thread):
# words = text2vec.load_lexicon()
def __init__(self, clientsocket, recvsize=1024 * 1024, encoding="utf-8"):
threading.Thread.__init__(self)
self._socket = clientsocket
self._recvsize = recvsize
self._encoding = encoding
pass
def run(self):
print("开启线程.....")
try:
# 接受Springboot传来的指令数据
msg = ''
while True:
# 读取recvsize个字节
rec = self._socket.recv(self._recvsize)
# 解码
msg += rec.decode(self._encoding)
# 文本接受是否完毕,因为python socket不能自己判断接收数据是否完毕,
# 所以需要自定义协议标志数据接受完毕
if msg.strip().endswith('over'):
break
#调用检测算法,并接收算法返回的视频帧(opencv),将每一帧转化为Image
#如果传回来的帧就是Image则无需转换,所以上面说包含于此
img = Image.fromarray(cv2.cvtColor(facetest(), cv2.COLOR_BGR2RGB))
#创建一个BytesIO()
output_buffer = BytesIO()
#写入output_buffer
img.save(output_buffer,format='JPEG')
#在内存中读取
byte_data = output_buffer.getvalue()
#转化为base64
sendmsg = base64.b64encode(byte_data)
#如果需要传回的数据较多可以构造一个Json
#str(sendmsg)[2:-1]是为了去掉Base64的格式
jsons = json.dumps({
'base64code': str(sendmsg)[2:-1], 'name': 'wuwenjun'}, sort_keys=True, indent=4, separators=(',', ': '))
# 像SpringBoot发送数据
self._socket.send(("%s" % jsons).encode(self._encoding))
pass
except Exception as identifier:
self._socket.send("500".encode(self._encoding))
print(identifier)
pass
finally:
self._socket.close()
print("任务结束.....")
pass
def __del__(self):
pass
if __name__ == "__main__":
main()
这里SpringBoot将接收来自Python算法返回的结果,可以是字符串,也可以是Base64的图片,当然也可以是既包含图片和字符串等的Json。
package com.example.wuwenjun.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.lang.System;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.InputStream;
import com.example.wuwenjun.pojo.ClassNews;
@Controller
public class ClassNewsController {
@CrossOrigin
@GetMapping(value = "/api/getpsv") //前端api接口
@ResponseBody
public StringBuilder GetPSV() {
Socket socket = null;
StringBuilder sb =null;
try {
InetAddress addr = InetAddress.getLocalHost();
String host=addr.getHostName();
//String ip=addr.getHostAddress().toString(); //获取本机ip
//log.info("调用远程接口:host=>"+ip+",port=>"+12345);
// 初始化套接字,设置访问服务的主机和进程端口号,HOST是访问python进程的主机名称,可以是IP地址或者域名,PORT是python进程绑定的端口号
socket = new Socket(host,12345);
// 获取输出流对象
OutputStream os = socket.getOutputStream();
PrintStream out = new PrintStream(os);
// 发送内容
out.print( "star");
// 告诉服务进程,内容发送完毕,可以开始处理
out.print("over");
// 获取服务进程的输入流
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is,"utf-8"));
String tmp = null;
sb = new StringBuilder();
// 读取内容
while((tmp=br.readLine())!=null)
sb.append(tmp).append('\n');
// classNews = JSONArray.parseObject(sb.toString(),ClassNews.class);
// System.out.println(classNews.getBase64code());
// System.out.println(classNews.getName());
System.out.println(sb);
//将算法返回的结果再次返回给Vue前端
return sb;
// 解析结果
//JSONArray res = JSON.parseArray(sb.toString());
} catch (IOException e) {
e.printStackTrace();
return sb;
}finally {
try {
if(socket!=null) socket.close();} catch (IOException e) {
}
System.out.println("远程接口调用结束.");
}
}
}
因为只是测试,所以我的前端写的很简陋,但是不影响功能,大家就当做测试来学习如何跑通Python,JavaWeb,Vue三方即可。这里给第一次尝试前端显示Base64图片的小白们提下,前端显示Base64的图片的src的格式为:
前缀需要人为手动添加,具体方式参照下文:
<template>
<div class="huaweisignup" style="width:1300px;height:1000px;background-color:yellow">
<button @click="getPSV">点击获取算法处理结果</button>
<div style="width:800px;height:800px;background-color:red">
<!-- 图片显示区域 -->
<img :src="base64code" style="margin-top:3%"/>
</div>
</div>
</template>
<script>
export default {
name: 'HuaWeiSignUp',
components: {
},
data () {
return {
base64code: ''
}
},
created () {
this.getPSV()
},
watch: {
},
methods: {
getPSV () {
//向后端发送get请求
this.$axios.get('http://localhost:8443/api/getpsv').then(resp => {
if (resp && resp.status === 200) {
//状态码为200为请求成功
//手动构造base64路径:前缀+返回码
this.base64code = 'data:image/png;base64,' + resp.data.base64code
this.$message({
showClose: true, message: 'ok', type: 'success'})
console.log(this.base64code)
}
})
}
}
}
</script>
以上就是这期Python,SpringBoot,Vue三方交互的全部教程了,如果你耐心的看完了全部,那希望能帮助到勤奋耐心的你。