因为项目的原因了解到有一个python的flask框架,查了一下:
关于前端图片上传的canvas:
如下元素
<canvas id="canvas" width="5" height="5"></canvas>
可以用这样的方式获取一个 data-URL
var canvas = document.getElementById("canvas");
var dataURL = canvas.toDataURL();
console.log(dataURL);
// “data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNby
// blAAAADElEQVQImWNgoBMAAABpAAFEI8ARAAAAAElFTkSuQmCC”
设置jpegs图片的质量
var fullQuality = canvas.toDataURL("image/jpeg", 1.0);
// data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...9oADAMBAAIRAxEAPwD/AD/6AP/Z"
var mediumQuality = canvas.toDataURL("image/jpeg", 0.5);
var lowQuality = canvas.toDataURL("image/jpeg", 0.1);
getContext() 方法返回一个用于在画布上绘图的环境。
语法
Canvas.getContext(contextID)
参数
参数 contextID 指定了您想要在画布上绘制的类型。当前唯一的合法值是 “2d”,它指定了二维绘图,并且导致这个方法返回一个环境对象,该对象导出一个二维绘图 API。
提示:在未来,如果 < canvas> 标签扩展到支持 3D 绘图,getContext() 方法可能允许传递一个 “3d” 字符串参数。
返回值
一个 CanvasRenderingContext2D 对象,使用它可以绘制到 Canvas 元素中。
后端:
首先pip install Flask
然后新建文件:
from flask import Flask,make_response, jsonify
from multiprocessing import Process
# 配置全局app
app = Flask(__name__)
# 导入index中定义的所有函数
#from autotrade.server.index import *
def run_index():
# 启动web服务器,使用多线程方式,接收所有http请求
app.run(host='0.0.0.0', port=5000, threaded=True)
def make_new_response(data):
res = make_response(jsonify({'code': 0, 'data': data}))
res.headers['Access-Control-Allow-Origin'] = '*'
res.headers['Access-Control-Allow-Method'] = '*'
res.headers['Access-Control-Allow-Headers'] = '*'
return res
@app.route('/')
def hello_world():
return {'hello': 'world!'}
@app.route("/test")
def test():
res = "{'no':'dddd'}"
return make_new_response(res)
if __name__ == "__main__":
app.run(debug=True)
打开浏览器:
向flask后端发请求接收图片:(点击按钮触发事件)
flask:
from flask import Flask,make_response, jsonify
from flask_cors import CORS
import socket
import threading
import json
import os
from io import BytesIO
from multiprocessing import Process
import io
from PIL import Image
# 配置全局app
app = Flask(__name__)
# 导入index中定义的所有函数
#from autotrade.server.index import *
def main():
# 创建服务器套接字
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 获取本地主机名称
host = socket.gethostname()
# 设置一个端口
port = 5000
# 将套接字与本地主机和端口绑定
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
def run_index():
# 启动web服务器,使用多线程方式,接收所有http请求
app.run(host='0.0.0.0', port=5000, threaded=True)
CORS(app, resources=r'/*', supports_credentials=True)
basedir = os.path.abspath(os.path.dirname(__file__))
@app.route('/getPic',methods=['GET', 'POST'])
def findpic():
img_url = basedir+'/data/tt/b/b_1.png'
print(img_url)
with open(img_url, 'rb') as f:
a = f.read()
'''对读取的图片进行处理'''
img_stream = io.BytesIO(a)
img = Image.open(img_stream)
imgByteArr = io.BytesIO()
img.save(imgByteArr,format='PNG')
imgByteArr = imgByteArr.getvalue()
print(imgByteArr)
return imgByteArr
if __name__ == "__main__":
app.run(debug=True)
注意:Python在内存中读写数据,用到的模块是StringIO和BytesIO,当为StringIO时getvalue()方法用于获得写入后的str。StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。可以用一个bytes初始化BytesIO,然后,像读文件一样读取:
>>> from io import BytesIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87'
BytesIO实现了在内存中读写bytes。
vue代码:
<button @click="getPic">获取图片</button>
<img :src="picurl" alt="beachball" />
data () {
return {
picurl: "",}
},
methods: {
getPic() {
var that = this;
this.$axios.get('http://127.0.0.1:5000/getPic',{responseType: "arraybuffer",}).then(function (response) {
that.picurl =
"data:image/jpeg;base64," + that.arrayBufferToBase64(response.data);
});
},
arrayBufferToBase64(buffer) {
//第一步,将ArrayBuffer转为二进制字符串
var binary = "";
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
//将二进制字符串转为base64字符串
return window.btoa(binary);
},
}
点击按钮后:
后端的显示:
图片传给后端
捣鼓了半天终于把图片传给后端了,不过暂时用的java测试。中途遇到无数次cannot read property xxx xxx is not defined,怀疑是自己哪些代码莫名出了问题,因为canvas是getelementbyid,所以如果写的是ref的话是获取不到的,然后注释掉了一堆代码,结果:
后端的响应:
flask获取图片数据:
flask获取参数方式:
request.form.get(“key”, type=str, default=None) 获取表单数据
request.args.get(“key”) 获取get请求参数
request.values.get(“key”) 获取所有参数
import base64
img1='E:/nsfw_tensorflow/corpus/weibocore_WBC_IMAGE_DATA_SOURCE_6521.jpg'
pimg=open(img1, 'rb').read()
print(pimg)
# base64图片加密
result = base64.b64encode(pimg)
print(result)
# 再把加密后的结果解码
temp = base64.b64decode(result)
print(temp)
现在出现一个问题,从前端发送图片之后后端接收到的data一直是str类型,不知道怎么取出来:
@app.route('/getpic', methods=['POST'])
def getpic():
data = flask.request.get_data().decode('utf-8')
data = json.loads(data)
data_b64 = data["data"]
print(type(data_b64))
修改:
def getpic():
data = json.loads(flask.request.get_data("data"))
data_64 = str.encode(data['data'])
print(type(data_64))
print(data_64)
得到类型为bytes.
前端去掉base64前面的前缀:
var image = this.thisCancas.toDataURL("image/png").split('base64,')[1];
搞了好久试了好多方法终于把前端的图片base码解出来了!!!!!!激动
后端的代码:
def decode_base64(data):
"""Decode base64, padding being optional.
:param data: Base64 data as an ASCII byte string
:returns: The decoded byte string.
"""
missing_padding = len(data) % 4
if missing_padding != 0:
data += b'='* (4 - missing_padding)
# return base64.decodestring(data)
return base64.b64decode(data)
#上面这个函数用来解码base64字符串
@app.route('/getpic', methods=['POST'])
def getpic():
data = json.loads(flask.request.get_data("data"))
data_64 = str.encode(data['data'])
print(type(data_64))
#print(data_64)
print('------------------------')
print(str(data_64, 'utf8')) #用这个方法去掉base64码前面b'xxx'的b
imgdata = decode_base64(data_64)
file = open('1.jpg', 'wb')
file.write(imgdata)
file.close()
其中注意前端发送的数据也经过了处理,使得去掉了img/jpeg前缀
现在载入模型进行拍照预测:
附上关键的代码:
import torch
from torchvision import transforms
def run_index():
# 启动web服务器,使用多线程方式,接收所有http请求
app.run(host='0.0.0.0', port=5000, threaded=True)
def decode_base64(data):
"""Decode base64, padding being optional.
:param data: Base64 data as an ASCII byte string
:returns: The decoded byte string.
"""
missing_padding = len(data) % 4
if missing_padding != 0:
data += b'='* (4 - missing_padding)
# return base64.decodestring(data)
return base64.b64decode(data)
transform=transforms.Compose([
transforms.Resize(224),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485,0.456,0.406],
std=[0.229,0.224,0.225])
])
CORS(app, resources=r'/*', supports_credentials=True)
@app.route('/getpic', methods=['POST'])
def getpic():
data = json.loads(flask.request.get_data("data"))
data_64 = str.encode(data['data'])
print(type(data_64))
#print(data_64)
print('------------------------')
print(str(data_64, 'utf8'))
imgdata = decode_base64(data_64)
file = open('1.jpg', 'wb')
file.write(imgdata)
file.close()
image = Image.open(r"1.jpg").convert('RGB')
image = transform(image).unsqueeze(0)
modelme = torch.load('modefresnet.pkl')
modelme.eval()
outputs = modelme(image)
_, predict = torch.max(outputs.data, 1)
for j in range(image.size()[0]):
print('predicted: {}'.format(class_names[predict[j]]))
return class_names[predict[j]]
if __name__ == "__main__":
app.run(debug=True)
试了好多次,几乎都与预测结果相符。
哈哈哈哈哈花了两天弄这个,之前关于图片解码编码一直没弄出来,现在成功了还是挺开心的。