Browse Source

1233

master
lichong 9 months ago
parent
commit
a5cb2e08bc
  1. 75
      app.py
  2. 7
      front/package-lock.json
  3. 2
      front/package.json
  4. 226
      front/src/App copy.vue
  5. 311
      front/src/App.vue
  6. 6
      front/src/assets/config/imgconf.json
  7. BIN
      front/src/assets/imgs/bilstm/1.png
  8. 2
      front/src/main.js
  9. 17
      front/src/style.css
  10. BIN
      front/vite600.zip
  11. 161
      inference copy.py
  12. 135
      inference.py
  13. BIN
      results_1.jpg
  14. BIN
      results_2.jpg

75
app.py

@ -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)

7
front/package-lock.json

@ -9,8 +9,10 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"axios": "^1.6.8", "axios": "^1.6.8",
"dayjs": "^1.11.11",
"element-plus": "^2.7.2", "element-plus": "^2.7.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"nprogress": "^0.2.0",
"vue": "^3.4.21" "vue": "^3.4.21"
}, },
"devDependencies": { "devDependencies": {
@ -1522,6 +1524,11 @@
"resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
"integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
}, },
"node_modules/nprogress": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz",
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
},
"node_modules/path-parse": { "node_modules/path-parse": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",

2
front/package.json

@ -10,8 +10,10 @@
}, },
"dependencies": { "dependencies": {
"axios": "^1.6.8", "axios": "^1.6.8",
"dayjs": "^1.11.11",
"element-plus": "^2.7.2", "element-plus": "^2.7.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"nprogress": "^0.2.0",
"vue": "^3.4.21" "vue": "^3.4.21"
}, },
"devDependencies": { "devDependencies": {

226
front/src/App copy.vue

@ -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>

311
front/src/App.vue

@ -1,50 +1,106 @@
<template> <template>
<div class="bgimg"> <div class="bgimg">
<el-row class="pa-2"> <el-row class="inputClass">
<el-col :span="8" class="text-align"> <el-col :span="4">
<div> <el-upload :show-file-list="false" :before-upload="beforeAvatarUpload" :http-request="successSubmit"
<el-input class="opacitybg" v-model="content" :rows="15" type="textarea" placeholder="请输入文本进行预测" /> accept=".png,.jpg,.jpeg">
</div> <el-button :disabled="checkLoading" type="primary">
<div class="pa-2"> <span>上传图片</span>
<el-button type="success" @click="sendData" :disabled="loading" :loading="loading">
开始预测
</el-button> </el-button>
</div> </el-upload>
</el-col>
<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>
<el-col :span="16" class="sendButton text-align"> <el-col :span="8">
<div v-if="result"> <span>置信度阈值</span>
<el-tag type="success" v-if="result === 'positive'" class="tagClass"> <el-input-number v-model="conf" :min="0.01" :max="1" :step="0.01" :disabled="checkLoading">
预测结果{{ classZh[result] }} <template #decrease-icon>
<el-icon style="width: 48px;font-size: 1.6em;position: relative;top: 20px;"> <el-icon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <ArrowDown />
<path
d="M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20M13,9.94L14.06,11L15.12,9.94L16.18,11L17.24,9.94L15.12,7.82L13,9.94M8.88,9.94L9.94,11L11,9.94L8.88,7.82L6.76,9.94L7.82,11L8.88,9.94M12,17.5C14.33,17.5 16.31,16.04 17.11,14H6.89C7.69,16.04 9.67,17.5 12,17.5Z" />
</svg>
</el-icon> </el-icon>
</el-tag> </template>
<el-tag type="danger" v-else-if="result === 'negative'" class="tagClass"> <template #increase-icon>
预测结果{{ classZh[result] }} <el-icon>
<el-icon style="width: 48px;font-size: 1.6em;position: relative;top: 20px;"> <ArrowUp />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z" />
</svg>
</el-icon> </el-icon>
</el-tag> </template>
</el-input-number>
</el-col>
<el-col :span="4">
<el-button type="success" :disabled="checkLoading" @click="checkMaonang">
<span>提取毛囊</span>
</el-button>
</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(savePngResult)"><span class="noDataClass">暂无数据</span></template>
<template v-else>
<el-image style="width: 500px; height: 500px"
:src="`${baseUrl}/api/getPng/${_.split(savePngResult.originalImgPath, '/')[1]}`" :zoom-rate="1.2"
:max-scale="7" :min-scale="0.2" fit="cover" />
</template>
</div> </div>
<div v-else> </el-col>
<el-progress class="opacitybg" :percentage="percentage" :stroke-width="15" :striped="percentage !== 100" <el-col :span="8">
:striped-flow="percentage !== 100" :duration="duration" :status="percentage === 100 ? 'success' : ''" <div>
type="circle" /> <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> </div>
</el-col> </el-col>
</el-row> <el-col :span="8">
<el-row>
<el-col class="pa-2 text-align" :span="8" v-for="(item, index) in imgList" :index="index">
<div class="pa-2">{{ item.label }}</div>
<div> <div>
<el-image style="height: calc(100vh - 420px)" :src="item.imgPath" :zoom-rate="1.2" :max-scale="7" <template v-if="_.isEmpty(resResult)"><span class="noDataClass">暂无数据</span></template>
:min-scale="0.2" :preview-src-list="[item.imgPath]" :initial-index="4" fit="cover" close-on-press-escape /> <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> </div>
</el-col> </el-col>
</el-row> </el-row>
@ -52,118 +108,137 @@
</template> </template>
<script> <script>
import { result } from "lodash"; import _ from "lodash";
import imgPath from "./assets/config/imgconf.json"; 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 { export default {
name: "app", name: "app",
components: { ArrowDown, ArrowUp },
data() { data() {
return { return {
result: "", _: _,
content: "", dayjs: dayjs,
percentage: 0, iou: 0.1,
isSend: false, conf: 0.25,
loading: false, checkLoading: false,
imgList: [], savePngResult: {},
sendmessage: null, resResult: {},
classZh: { baseUrl: "http://127.0.0.1:8006",
negative: "消极",
positive: "积极",
},
}; };
}, },
methods: { methods: {
async sendData() { /**
this.percentage = 0; * 上传检查图片
this.isSend = true; */
this.loading = true; beforeAvatarUpload(rawFile) {
this.result = ""; let imgList = ["image/jpeg", "image/png"]
if (this.sendmessage) { if (imgList.indexOf(rawFile.type) === -1) {
this.sendmessage.close() this.$msgbox.alert('请上传.png,.jpg,.jpeg格式的图片!')
} return false
this.sendmessage = this.$message({ } else if (rawFile.size / 1024 / 1024 > 50) {
showClose: true, this.$msgbox.alert('图片文件的大小为小于50MB,过大时会处理过慢')
repeatNum: 1, return true
duration: 0,
message: "王一鸣202207100038",
type: 'success',
});
let data = {
content: [this.content],
};
let res = await this.$axios.post("/api/content", data);
if (res.status === 200) {
this.isSend = false;
}
},
},
async mounted() {
this.imgList = imgPath;
for (let index = 0; index < this.imgList.length; index++) {
let element = this.imgList[index];
element.imgPath = new URL(element.path, import.meta.url).href;
} }
return true
}, },
watch: { //
async isSend(nev, olv) { async successSubmit(opts) {
let total = 96; ElMessage({
if (nev) { type: "success",
while (this.percentage < total) { message: '正在上传,请稍后',
if (this.percentage < total) { })
let random = Math.floor(Math.random() * 2); this.savePngResult = {}
this.percentage += random; 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);
let res = await axios.post('http://127.0.0.1:8006/api/savePng', formData, {
headers: { 'content-type': 'multipart/form-data' },
})
that.savePngResult = res.data
that.checkLoading = false
ElMessage.closeAll()
NProgress.done();
} }
await new Promise((resolve) => setTimeout(resolve, 50)); fileReader.onerror = function (error) {
} console.error('Error reading file:', error)
if (this.percentage > total - 1) {
while (!this.result) {
let res = await this.$axios.get("/api/model_res");
this.percentage = 100;
this.result = res.data
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
} else {
} }
fileReader.readAsArrayBuffer(file)
}, },
result(nev, olv) { //
this.loading = !nev; async checkMaonang() {
}, 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 formData = new FormData();
formData.append('iou', this.iou);
formData.append('conf', this.conf);
let res = await axios.post('http://127.0.0.1:8006/api/checkPng', formData, {
headers: { 'content-type': 'multipart/form-data' },
})
this.resResult = res.data
this.checkLoading = false
ElMessage.closeAll()
NProgress.done();
}, },
computed: {
duration() {
return Math.floor(this.percentage / 10);
}, },
async mounted() {
}, },
watch: {},
computed: {},
}; };
</script> </script>
<style scoped> <style scoped>
.bgimg { .bgimg {
height: 100vh; height: calc(100vh - 20px);
width: 100vw; width: calc(100vw - 16px);
color: #fff; padding: 12px 8px 8px 8px;
background-image: url("@/assets/imgs/otherimgs/bg.jpg"); background-color: #ecf5ff;
} }
.sendButton { .inputClass {
align-content: center; text-align: center;
margin: 60px 0 60px 0;
} }
.text-align { .outClass {
text-align: center; text-align: center;
margin: 20px 30px 20px 30px;
} }
.pa-2 { .imgClass {
padding: 4px; margin: 20px;
text-align: center;
} }
.tagClass { .spanClass {
height: 1.6em;
font-size: 3em; font-size: 3em;
} }
.noDataClass {
.opacitybg { font-size: 2em;
opacity: 0.6; color: #909399;
} }
</style> </style>

6
front/src/assets/config/imgconf.json

@ -1,6 +0,0 @@
[
{
"label": "f1-score",
"path": "assets/imgs/bilstm/1.png"
}
]

BIN
front/src/assets/imgs/bilstm/1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

2
front/src/main.js

@ -9,5 +9,5 @@ import axios from "axios"
const app = createApp(App) const app = createApp(App)
app.config.globalProperties.$_ = _ app.config.globalProperties.$_ = _
app.config.globalProperties.$axios = axios app.config.globalProperties.$axios = axios
app.use(ElementPlus) app.use(ElementPlus, { size: "large" })
app.mount('#app') app.mount('#app')

17
front/src/style.css

@ -2,4 +2,21 @@ html,
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-size: 1.2em;
}
#nprogress .bar {
background: #79bbff !important;
height: 6px;
}
.el-descriptions__body .el-descriptions__table .el-descriptions__cell {
font-size: 3em !important;
height: 64px;
}
.el-tag--large {
font-size: 26px;
line-height: 30px;
height: 48px;
} }

BIN
front/vite600.zip

Binary file not shown.

161
inference copy.py

@ -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)

135
inference.py

@ -3,12 +3,33 @@ import torch
import numpy as np import numpy as np
from PIL import Image from PIL import Image
from ultralytics import YOLO 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个输入参数 # 3个输入参数
img_path = 'img0002.jpg' img_path = "img0002.jpg"
iou = 0.1 iou = 0.1
conf = 0.25 conf = 0.25
originalImgPath = ""
result1Path = ""
result2Path = ""
nowtime1 = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime(time.time()))
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)): def split_image(img_path, size=(800, 800)):
img = cv2.imread(img_path) img = cv2.imread(img_path)
@ -39,17 +60,52 @@ def combine_images(pred_imgs, indexes, size=(800, 800), img_shape=(3000, 4000)):
combined_img[y1:y2, x1:x2] = pred_imgs[idx][: y2 - y1, : x2 - x1] combined_img[y1:y2, x1:x2] = pred_imgs[idx][: y2 - y1, : x2 - x1]
return combined_img return combined_img
follicle_groups_detector = YOLO('follicle_groups.pt')
follicles_detector = YOLO('follicles.pt')
results = follicle_groups_detector(img_path, iou=iou, conf=conf) follicle_groups_detector = YOLO("follicle_groups.pt")
follicles_detector = YOLO("follicles.pt")
# 保存图片
@app.route("/api/savePng", methods=["POST"])
def savePng():
global nowtime1
global originalImgPath
nowtime1 = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime(time.time()))
pngFile = request.files["file"]
img = Image.open(pngFile.stream)
originalImgPath = "images/original" + str(nowtime1) + ".png"
img.save(originalImgPath)
resResult = {
"hasError": False,
"originalImgPath": originalImgPath,
}
return resResult
# 检测图片
@app.route("/api/checkPng", methods=["POST"])
def checkPng():
global follicle_groups_detector
global follicles_detector
global originalImgPath
global nowtime1
global result1Path
global result2Path
global resResult
iou = request.form.get("iou")
iou = float(iou)
conf = request.form.get("conf")
conf = float(conf)
result1Path = "images/result1" + str(nowtime1) + ".png"
result2Path = "images/result2" + str(nowtime1) + ".png"
results = follicle_groups_detector(originalImgPath, iou=iou, conf=conf)
for r in results: for r in results:
num_follicle_groups = len(r.boxes) num_follicle_groups = len(r.boxes)
im_array = r.plot() im_array = r.plot()
im = Image.fromarray(im_array[..., ::-1]) im = Image.fromarray(im_array[..., ::-1])
im.save('results_1.jpg') #输出结果图1 im.save(result1Path) # 输出结果图1
img_list, indexes, (height, width) = split_image(img_path) img_list, indexes, (height, width) = split_image(result1Path)
print(f"Number of image blocks: {len(img_list)}") print(f"Number of image blocks: {len(img_list)}")
num_small_follicles = 0 num_small_follicles = 0
num_big_follicles = 0 num_big_follicles = 0
@ -63,19 +119,56 @@ for img in img_list:
pred_imgs.append(im_array) pred_imgs.append(im_array)
# 输出的3个结果文本 # 输出的3个结果文本
print('毛囊群数量:', num_follicle_groups) print("毛囊群数量:", num_follicle_groups)
print('大毛囊数量:', num_big_follicles) print("大毛囊数量:", num_big_follicles)
print('小毛囊数量:', num_small_follicles) print("小毛囊数量:", num_small_follicles)
combined_img = combine_images(pred_imgs, indexes, size=(800, 800), img_shape=(height, width)) 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 = Image.fromarray(combined_img[..., ::-1])
combined_image_pil.save('results_2.jpg') #输出结果图2 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)

BIN
results_1.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 KiB

BIN
results_2.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 KiB

Loading…
Cancel
Save