14 changed files with 742 additions and 242 deletions
@ -1,75 +0,0 @@ |
|||
import torch |
|||
from flask import Flask, request |
|||
import torch.nn as nn |
|||
import pickle |
|||
import jieba |
|||
|
|||
app = Flask(__name__) |
|||
# 初始化模型 |
|||
result = "" |
|||
|
|||
|
|||
class Model(nn.Module): |
|||
def __init__(self): |
|||
super(Model, self).__init__() |
|||
self.embedding = nn.Embedding(10002, 300, padding_idx=10001) |
|||
self.lstm = nn.LSTM(300, 128, 2, bidirectional=True, batch_first=True, dropout=0.5) |
|||
self.fc = nn.Linear(128 * 2, 2) |
|||
|
|||
def forward(self, x): |
|||
x, _ = x |
|||
out = self.embedding(x) # [batch_size, seq_len, embeding]=[128, 32, 300] |
|||
out, _ = self.lstm(out) |
|||
out = self.fc(out[:, -1, :]) # 句子最后时刻的 hidden state |
|||
return out |
|||
|
|||
|
|||
model = Model() |
|||
model.load_state_dict(torch.load('./THUCNews/saved_dict/TextRNN.ckpt', map_location=torch.device("cpu"))) |
|||
model.eval() |
|||
stopwords = open('./THUCNews/data/hit_stopwords.txt', encoding='utf8').read().split('\n')[:-1] |
|||
|
|||
vocab = pickle.load(open('./THUCNews/data/vocab.pkl', 'rb')) |
|||
classes = ['negative', 'positive'] |
|||
|
|||
s = '空调吵,住在电梯旁,电梯门口放垃圾箱,极臭,布草间没关门,也臭,臭到房间里,门下塞毛巾也挡不住臭味,开窗外面吵,关窗空调吵,楼下早餐桌子上摆满垃圾没人整理,不能再差的体验了' |
|||
|
|||
|
|||
# s = '东东还算不错。重装系统时,网上查不到怎么修改BIOS,才能安装?问题请帮忙解决!' |
|||
|
|||
|
|||
@app.route('/api/content', methods=["POST"]) |
|||
def content(): |
|||
get_json = request.get_json() |
|||
global model |
|||
global result |
|||
global classes |
|||
result = "" |
|||
s = get_json.get("content")[0] |
|||
print(6777, s) |
|||
try: |
|||
s = list(jieba.lcut(s)) |
|||
s = [i for i in s if i not in stopwords] |
|||
s = [vocab.get(i, 10000) for i in s] |
|||
if len(s) > 64: |
|||
s = s[:64] |
|||
else: |
|||
for i in range(64 - len(s)): |
|||
s.append(vocab['<PAD>']) |
|||
|
|||
outputs = model((torch.LongTensor(s).unsqueeze(0), None)) |
|||
print(torch.argmax(outputs)) |
|||
result = classes[torch.argmax(outputs)] |
|||
except Exception as e: # 未捕获到异常,程序直接报错 |
|||
result = e |
|||
return "pridicting" |
|||
|
|||
|
|||
@app.route('/api/model_res', methods=['GET']) |
|||
def model_res(): |
|||
global result |
|||
return str(result) |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
app.run(host="127.0.0.1", port=8006) |
@ -0,0 +1,226 @@ |
|||
<template> |
|||
<div class="bgimg"> |
|||
<el-row class="inputClass"> |
|||
<el-col :span="8"> |
|||
<span>IoU阈值:</span> |
|||
<el-input-number v-model="iou" :min="0.01" :max="1" :step="0.01" :disabled="checkLoading"> |
|||
<template #decrease-icon> |
|||
<el-icon> |
|||
<ArrowDown /> |
|||
</el-icon> |
|||
</template> |
|||
<template #increase-icon> |
|||
<el-icon> |
|||
<ArrowUp /> |
|||
</el-icon> |
|||
</template> |
|||
</el-input-number> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<span>置信度阈值:</span> |
|||
<el-input-number v-model="conf" :min="0.01" :max="1" :step="0.01" :disabled="checkLoading"> |
|||
<template #decrease-icon> |
|||
<el-icon> |
|||
<ArrowDown /> |
|||
</el-icon> |
|||
</template> |
|||
<template #increase-icon> |
|||
<el-icon> |
|||
<ArrowUp /> |
|||
</el-icon> |
|||
</template> |
|||
</el-input-number> |
|||
</el-col> |
|||
<el-col :span="4"> |
|||
<el-upload :show-file-list="false" :before-upload="beforeAvatarUpload" :http-request="successSubmit" |
|||
accept=".png,.jpg,.jpeg"> |
|||
<el-button type="success" :disabled="checkLoading"> |
|||
<span>上传图片</span> |
|||
</el-button> |
|||
</el-upload> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row class="outClass"> |
|||
<el-col> |
|||
<el-descriptions direction="vertical" :column="3" border> |
|||
<template #title> |
|||
<span class="spanClass">检测结果:</span> |
|||
</template> |
|||
<el-descriptions-item label="毛囊群数" align="center"> |
|||
<template v-if="_.isEmpty(resResult)"><el-tag type="info">暂无数据</el-tag></template> |
|||
<template v-else> |
|||
<el-tag type="success">{{ resResult.num_follicle_groups }}</el-tag> |
|||
</template> |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="大毛囊群" align="center"> |
|||
<template v-if="_.isEmpty(resResult)"><el-tag type="info">暂无数据</el-tag></template> |
|||
<template v-else> |
|||
<el-tag type="success">{{ resResult.num_big_follicles }}</el-tag> |
|||
</template> |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="小毛囊群" align="center"> |
|||
<template v-if="_.isEmpty(resResult)"><el-tag type="info">暂无数据</el-tag></template> |
|||
<template v-else> |
|||
<el-tag type="success">{{ resResult.num_small_follicles }}</el-tag> |
|||
</template> |
|||
</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row class="imgClass"> |
|||
<el-col :span="8"> |
|||
<div> |
|||
<template v-if="_.isEmpty(resResult)"><span class="noDataClass">暂无数据</span></template> |
|||
<template v-else> |
|||
<el-image style="width: 500px; height: 500px" |
|||
:src="`${baseUrl}/api/getPng/${_.split(resResult.originalImgPath, '/')[1]}`" :zoom-rate="1.2" |
|||
:max-scale="7" :min-scale="0.2" fit="cover" /> |
|||
</template> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div> |
|||
<template v-if="_.isEmpty(resResult)"><span class="noDataClass">暂无数据</span></template> |
|||
<template v-else> |
|||
<el-image style="width: 500px; height: 500px" |
|||
:src="`${baseUrl}/api/getPng/${_.split(resResult.result1Path, '/')[1]}`" :zoom-rate="1.2" :max-scale="7" |
|||
:min-scale="0.2" fit="cover" /> |
|||
</template> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div> |
|||
<template v-if="_.isEmpty(resResult)"><span class="noDataClass">暂无数据</span></template> |
|||
<template v-else> |
|||
<el-image style="width: 500px; height: 500px" |
|||
:src="`${baseUrl}/api/getPng/${_.split(resResult.result2Path, '/')[1]}`" :zoom-rate="1.2" :max-scale="7" |
|||
:min-scale="0.2" fit="cover" /> |
|||
</template> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import _ from "lodash"; |
|||
import dayjs from "dayjs"; |
|||
import axios from "axios"; |
|||
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue' |
|||
import NProgress from "nprogress"; |
|||
import "nprogress/nprogress.css"; |
|||
import { ElMessage } from 'element-plus' |
|||
export default { |
|||
name: "app", |
|||
components: { ArrowDown, ArrowUp }, |
|||
data() { |
|||
return { |
|||
_: _, |
|||
dayjs: dayjs, |
|||
iou: 0.1, |
|||
conf: 0.25, |
|||
checkLoading: false, |
|||
resResult: {}, |
|||
baseUrl: "http://127.0.0.1:8006", |
|||
}; |
|||
}, |
|||
methods: { |
|||
/** |
|||
* 上传检查图片 |
|||
*/ |
|||
beforeAvatarUpload(rawFile) { |
|||
let imgList = ["image/jpeg", "image/png"] |
|||
if (imgList.indexOf(rawFile.type) === -1) { |
|||
this.$msgbox.alert('请上传.png,.jpg,.jpeg格式的图片!') |
|||
return false |
|||
} else if (rawFile.size / 1024 / 1024 > 50) { |
|||
this.$msgbox.alert('图片文件的大小为小于50MB,过大时会处理过慢') |
|||
return true |
|||
} |
|||
return true |
|||
}, |
|||
//上传图片检测 |
|||
async successSubmit(opts) { |
|||
ElMessage({ |
|||
showClose: true, |
|||
duration: 0, |
|||
type: "success", |
|||
message: '正在检测,请耐心等待后,稍后查看结果', |
|||
}) |
|||
this.resResult = {} |
|||
NProgress.configure({ showSpinner: false }); |
|||
NProgress.configure({ parent: '.bgimg' }); |
|||
this.checkLoading = true |
|||
NProgress.start(); |
|||
NProgress.inc(); |
|||
let that = this |
|||
let file = opts.file |
|||
let fileReader = new FileReader() |
|||
fileReader.onload = async function (e) { |
|||
let formData = new FormData(); |
|||
formData.append('file', file); |
|||
formData.append('iou', that.iou); |
|||
formData.append('conf', that.conf); |
|||
let res = await axios.post('http://127.0.0.1:8006/api/checkPng', formData, { |
|||
headers: { 'content-type': 'multipart/form-data' }, |
|||
}) |
|||
that.resResult = res.data |
|||
that.checkLoading = false |
|||
ElMessage.closeAll() |
|||
NProgress.done(); |
|||
} |
|||
fileReader.onerror = function (error) { |
|||
console.error('Error reading file:', error) |
|||
} |
|||
fileReader.readAsArrayBuffer(file) |
|||
}, |
|||
//上传成功 |
|||
handlePictureCardPreview(file) { |
|||
console.log(7777, file) |
|||
}, |
|||
// 毛囊检测请求 |
|||
async checkPng() { |
|||
let res = await axios.get('http://127.0.0.1:8006/api/checkResult') |
|||
console.log(8977, res) |
|||
} |
|||
}, |
|||
async mounted() { |
|||
|
|||
}, |
|||
watch: {}, |
|||
computed: {}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.bgimg { |
|||
height: calc(100vh - 20px); |
|||
width: calc(100vw - 16px); |
|||
padding: 12px 8px 8px 8px; |
|||
background-color: #ecf5ff; |
|||
} |
|||
|
|||
.inputClass { |
|||
text-align: center; |
|||
margin: 60px 0 20px 0; |
|||
} |
|||
|
|||
.outClass { |
|||
text-align: center; |
|||
margin: 20px 0; |
|||
} |
|||
|
|||
.imgClass { |
|||
margin: 20px; |
|||
text-align: center; |
|||
} |
|||
|
|||
.spanClass { |
|||
font-size: 3em; |
|||
} |
|||
|
|||
.noDataClass { |
|||
font-size: 2em; |
|||
color: #909399; |
|||
} |
|||
</style> |
@ -1,6 +0,0 @@ |
|||
[ |
|||
{ |
|||
"label": "f1-score", |
|||
"path": "assets/imgs/bilstm/1.png" |
|||
} |
|||
] |
Before Width: | Height: | Size: 19 KiB |
Binary file not shown.
@ -0,0 +1,161 @@ |
|||
import cv2 |
|||
import torch |
|||
import numpy as np |
|||
from PIL import Image |
|||
from ultralytics import YOLO |
|||
from flask import Flask, request, send_file, make_response |
|||
from flask_cors import CORS |
|||
import time |
|||
from io import BytesIO |
|||
|
|||
# 3个输入参数 |
|||
img_path = "img0002.jpg" |
|||
iou = 0.1 |
|||
conf = 0.25 |
|||
originalImgPath = "" |
|||
result1Path = "" |
|||
result2Path = "" |
|||
|
|||
app = Flask(__name__) |
|||
# 解决跨域问题 |
|||
cors = CORS( |
|||
app, |
|||
resources={ |
|||
r"/api/*": { |
|||
"origins": ["http://localhost:5173"], |
|||
"methods": ["GET", "POST"], |
|||
} |
|||
}, |
|||
) |
|||
# 初始化模型 |
|||
resResult = "" |
|||
|
|||
|
|||
def split_image(img_path, size=(800, 800)): |
|||
img = cv2.imread(img_path) |
|||
height, width = img.shape[:2] |
|||
rows = (height + size[1] - 1) // size[1] |
|||
cols = (width + size[0] - 1) // size[0] |
|||
img_list = [] |
|||
indexes = [] |
|||
for r in range(rows): |
|||
for c in range(cols): |
|||
y1 = r * size[1] |
|||
y2 = min((r + 1) * size[1], height) |
|||
x1 = c * size[0] |
|||
x2 = min((c + 1) * size[0], width) |
|||
split = img[y1:y2, x1:x2] |
|||
img_list.append(split) |
|||
indexes.append((r, c)) |
|||
return img_list, indexes, (height, width) |
|||
|
|||
|
|||
def combine_images(pred_imgs, indexes, size=(800, 800), img_shape=(3000, 4000)): |
|||
combined_img = np.zeros((img_shape[0], img_shape[1], 3), dtype=np.uint8) |
|||
for idx, (r, c) in enumerate(indexes): |
|||
y1 = r * size[1] |
|||
y2 = min((r + 1) * size[1], img_shape[0]) |
|||
x1 = c * size[0] |
|||
x2 = min((c + 1) * size[0], img_shape[1]) |
|||
combined_img[y1:y2, x1:x2] = pred_imgs[idx][: y2 - y1, : x2 - x1] |
|||
return combined_img |
|||
|
|||
|
|||
follicle_groups_detector = YOLO("follicle_groups.pt") |
|||
follicles_detector = YOLO("follicles.pt") |
|||
|
|||
|
|||
# 保存检测图片 |
|||
@app.route("/api/checkPng", methods=["POST"]) |
|||
def checkPng(): |
|||
global follicle_groups_detector |
|||
global follicles_detector |
|||
global originalImgPath |
|||
global result1Path |
|||
global result2Path |
|||
global resResult |
|||
pngFile = request.files["file"] |
|||
img = Image.open(pngFile.stream) |
|||
iou = request.form.get("iou") |
|||
iou = float(iou) |
|||
conf = request.form.get("conf") |
|||
conf = float(conf) |
|||
nowtime1 = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime(time.time())) |
|||
originalImgPath = "images/original" + str(nowtime1) + ".png" |
|||
result1Path = "images/result1" + str(nowtime1) + ".png" |
|||
result2Path = "images/result2" + str(nowtime1) + ".png" |
|||
img.save(originalImgPath) |
|||
results = follicle_groups_detector(originalImgPath, iou=iou, conf=conf) |
|||
for r in results: |
|||
num_follicle_groups = len(r.boxes) |
|||
im_array = r.plot() |
|||
im = Image.fromarray(im_array[..., ::-1]) |
|||
im.save(result1Path) # 输出结果图1 |
|||
|
|||
img_list, indexes, (height, width) = split_image(result1Path) |
|||
print(f"Number of image blocks: {len(img_list)}") |
|||
num_small_follicles = 0 |
|||
num_big_follicles = 0 |
|||
pred_imgs = [] |
|||
for img in img_list: |
|||
results = follicles_detector(img, iou=iou, conf=conf) |
|||
for r in results: |
|||
num_small_follicles += torch.sum(r.boxes.cls == 0).item() |
|||
num_big_follicles += torch.sum(r.boxes.cls == 1).item() |
|||
im_array = r.plot() |
|||
pred_imgs.append(im_array) |
|||
|
|||
# 输出的3个结果文本 |
|||
print("毛囊群数量:", num_follicle_groups) |
|||
print("大毛囊数量:", num_big_follicles) |
|||
print("小毛囊数量:", num_small_follicles) |
|||
|
|||
combined_img = combine_images( |
|||
pred_imgs, indexes, size=(800, 800), img_shape=(height, width) |
|||
) |
|||
combined_image_pil = Image.fromarray(combined_img[..., ::-1]) |
|||
combined_image_pil.save(result2Path) # 输出结果图2 |
|||
resResult = { |
|||
"hasError": False, |
|||
"num_follicle_groups": num_follicle_groups, |
|||
"num_big_follicles": num_big_follicles, |
|||
"num_small_follicles": num_small_follicles, |
|||
"originalImgPath": originalImgPath, |
|||
"result1Path": result1Path, |
|||
"result2Path": result2Path, |
|||
} |
|||
return resResult |
|||
|
|||
|
|||
# 检测结果返回 |
|||
@app.route("/api/checkResult", methods=["GET"]) |
|||
def checkResult(): |
|||
global resResult |
|||
return resResult |
|||
|
|||
|
|||
# 图片查询 |
|||
@app.route("/api/getPng/<pngPath>", methods=["GET"]) |
|||
def getPng(pngPath): |
|||
# 打开或处理图像 |
|||
img = Image.open("images/" + pngPath) |
|||
# 对图像进行处理,例如调整大小 |
|||
img = img.resize((800, 600)) |
|||
# 创建一个 BytesIO 对象来保存图像数据 |
|||
img_byte_arr = BytesIO() |
|||
img.save(img_byte_arr, format="PNG") |
|||
img_byte_arr.seek(0) |
|||
|
|||
# 使用 send_file 返回图像数据 |
|||
# return send_file(img_byte_arr, mimetype='image/jpeg') |
|||
|
|||
# 或者使用 make_response 来创建一个响应对象 |
|||
response = make_response(img_byte_arr.getvalue()) |
|||
response.headers.set("Content-Type", "image/jpeg") |
|||
response.headers.set("Content-Disposition", "attachment", filename=pngPath) |
|||
|
|||
return response |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
app.run(host="127.0.0.1", port=8006, debug=True) |
Before Width: | Height: | Size: 481 KiB |
Before Width: | Height: | Size: 723 KiB |
Loading…
Reference in new issue