feat: Tesseract识别 优化增加红色框

This commit is contained in:
user 2025-03-11 09:50:56 +08:00
parent b73ece1631
commit 9a3bfbe7cd
5 changed files with 116 additions and 8 deletions

30
package-lock.json generated
View File

@ -13,6 +13,7 @@
"@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-solid-svg-icons": "6.7.2",
"@fortawesome/vue-fontawesome": "3.0.8",
"@paddlejs-models/ocr": "^1.2.4",
"@vue/compat": "3.5.13",
"@vuelidate/core": "2.0.3",
"@vuelidate/validators": "2.0.4",
@ -2583,6 +2584,35 @@
"dev": true,
"license": "MIT"
},
"node_modules/@paddlejs-mediapipe/opencv": {
"version": "0.0.4",
"resolved": "https://registry.npmmirror.com/@paddlejs-mediapipe/opencv/-/opencv-0.0.4.tgz",
"integrity": "sha512-bfwixZPKGFh7JcAtLToTBmBiu/nyQjVrm0gf/pn92apHJQEYyhnAFGvgDubmqQbijmtP2/fbOMR4CuSSlq2g8w==",
"license": "ISC"
},
"node_modules/@paddlejs-models/ocr": {
"version": "1.2.4",
"resolved": "https://registry.npmmirror.com/@paddlejs-models/ocr/-/ocr-1.2.4.tgz",
"integrity": "sha512-mdvaWXQaCmLULEvCxcsUzHtDgmoDVzJX2LsqyMmJxSzfhgrtnscF1eLiLbaouDwg6n08koXP0BCzeB+0oAv/AQ==",
"license": "ISC",
"dependencies": {
"@paddlejs-mediapipe/opencv": "0.0.4",
"@paddlejs/paddlejs-backend-webgl": "^1.1.19",
"@paddlejs/paddlejs-core": "^2.1.17"
}
},
"node_modules/@paddlejs/paddlejs-backend-webgl": {
"version": "1.2.9",
"resolved": "https://registry.npmmirror.com/@paddlejs/paddlejs-backend-webgl/-/paddlejs-backend-webgl-1.2.9.tgz",
"integrity": "sha512-cVDa0/Wbw2EyfsYqdYUPhFeqKsET79keEUWjyhYQmQkJfWg8j1qdR6yp7g6nx9qAGrqFvwuj1s0EqkYA1dok6A==",
"license": "ISC"
},
"node_modules/@paddlejs/paddlejs-core": {
"version": "2.2.0",
"resolved": "https://registry.npmmirror.com/@paddlejs/paddlejs-core/-/paddlejs-core-2.2.0.tgz",
"integrity": "sha512-P3rPkF9fFHtq8uSte5gA7fJQwBNl9Ytsvj6aTcfQSsirnBO/HxMNu0gJyh7+lItvEtF92PR15eI0eOwJYfZDhQ==",
"license": "ISC"
},
"node_modules/@pinia/testing": {
"version": "0.1.7",
"resolved": "https://registry.npmmirror.com/@pinia/testing/-/testing-0.1.7.tgz",

View File

@ -81,6 +81,7 @@
"@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-solid-svg-icons": "6.7.2",
"@fortawesome/vue-fontawesome": "3.0.8",
"@paddlejs-models/ocr": "^1.2.4",
"@vue/compat": "3.5.13",
"@vuelidate/core": "2.0.3",
"@vuelidate/validators": "2.0.4",

View File

@ -1,7 +1,12 @@
<template>
<div class="weight-reader-container">
<div v-if="!cameraError">
<video ref="video" autoplay playsinline></video>
<div class="camera-view">
<video ref="video" autoplay playsinline></video>
<div class="overlay">
<div class="capture-frame"></div>
</div>
</div>
<canvas ref="canvas" style="display: none"></canvas>
<div class="weight-result">
<p>
@ -30,6 +35,7 @@
import { defineComponent, ref, onMounted, onBeforeUnmount } from 'vue';
import { useI18n } from 'vue-i18n';
import Tesseract from 'tesseract.js';
//import ocr from "@paddlejs-models/ocr";
import { library } from '@fortawesome/fontawesome-svg-core';
import { faCheck, faRedo } from '@fortawesome/free-solid-svg-icons';
@ -98,7 +104,7 @@ export default defineComponent({
const startOCR = () => {
hasValidWeight.value = false;
weight.value = t('entity.action.weightReader.initializing');
weight.value = t('entity.action.weightReader.reading');
ocrInterval.value = window.setInterval(() => {
captureFrame();
}, 2000);
@ -110,13 +116,43 @@ export default defineComponent({
const ctx = canvas.value.getContext('2d');
if (!ctx) return;
canvas.value.width = video.value.videoWidth;
canvas.value.height = video.value.videoHeight;
//
canvas.value.width = 200; // capture-frame
canvas.value.height = 80; // capture-frame
ctx.drawImage(video.value, 0, 0, canvas.value.width, canvas.value.height);
//
const videoWidth = video.value.videoWidth;
const videoHeight = video.value.videoHeight;
const sourceX = (videoWidth - (200 * videoWidth) / video.value.offsetWidth) / 2;
const sourceY = (videoHeight - (80 * videoHeight) / video.value.offsetHeight) / 2;
const sourceWidth = (200 * videoWidth) / video.value.offsetWidth;
const sourceHeight = (80 * videoHeight) / video.value.offsetHeight;
//
ctx.drawImage(video.value, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, canvas.value.width, canvas.value.height);
const imageData = canvas.value.toDataURL('image/jpeg');
/*
const result = await ocr.recognize(imageData);
console.log("OCR 识别结果:", result);
const numberMatch = result.text.match(/\d+\.\d+/); //
if (numberMatch && numberMatch.length > 0) {
const weightValue = numberMatch.reduce((max, current) => {
return parseFloat(current) > parseFloat(max) ? current : max;
}, '0');
if (parseFloat(weightValue) > 0) {
weight.value = weightValue;
//emit('weight', weightValue);
if (ocrInterval.value) {
window.clearInterval(ocrInterval.value);
ocrInterval.value = null;
hasValidWeight.value = true;
}
}
}
*/
Tesseract.recognize(imageData, 'eng', {
logger: m => {},
})
@ -155,6 +191,7 @@ export default defineComponent({
onMounted(() => {
video.value = document.querySelector('video');
canvas.value = document.querySelector('canvas');
//await ocr.loadModel(); // Paddle.js OCR
startCamera();
});
@ -185,12 +222,45 @@ export default defineComponent({
text-align: center;
}
.camera-view {
position: relative;
width: 100%;
max-height: 300px;
margin-bottom: 10px;
}
video {
width: 100%;
max-height: 300px;
border: 2px solid #ddd;
border-radius: 8px;
margin-bottom: 10px;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
mask:
linear-gradient(#000 0 0) center/200px 80px no-repeat,
linear-gradient(#000 0 0);
mask-composite: exclude;
-webkit-mask:
linear-gradient(#000 0 0) center/200px 80px no-repeat,
linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
}
.capture-frame {
width: 200px;
height: 80px;
border: 2px solid #ff0000;
background: transparent;
}
.weight-result {

View File

@ -101,6 +101,12 @@
</tbody>
</table>
</div>
<div class="signature-row">
<div class="signature-item">
<span class="signature-label">接收日期</span>
<div class="signature-line"></div>
</div>
</div>
</div>
<!-- 签名区域 -->
<div class="print-section signature-section">

View File

@ -152,8 +152,9 @@
"select": "(选择)",
"null": "(无)",
"weightReader": {
"initializing": "初始化中...",
"realtime": "实时重量"
"initializing": "初始化...",
"reading": "扫描中...",
"realtime": "识别值"
},
"camera": {
"open": "打开相机",