HTML5 吊牌识别小工具

关键点说明

  • facingMode: 'environment':这个参数告诉浏览器优先使用设备的后置摄像头,这对于拍摄物体(如吊牌)非常重要。
  • Tesseract.recognize(canvas, 'chi_sim+eng', ...):这是OCR的核心。
  • 第一个参数 canvas 是要识别的图像源。
  • 第二个参数 'chi_sim+eng' 指定了要识别的语言。chi_sim 代表简体中文,eng 代表英文。吊牌通常是中英混合,所以这个组合很合适。
  • 第三个参数中的 logger 是一个回调函数,可以用来监控识别的进度,提升用户体验。
  • 首次加载:Tesseract.js 在第一次识别特定语言时,需要从CDN下载该语言的训练数据包。这个过程可能需要一些时间,之后再次识别就会非常快。
  • 识别准确率:OCR的准确率受多种因素影响,包括 光照、图像清晰度(对焦)、拍摄角度 和 文字的复杂性。为了获得最佳效果,请确保吊牌平整、光线充足且在摄像头焦点内。

1. 最常见原因:安全环境 (HTTPS)

为了保护用户隐私,现代浏览器要求调用摄像头的页面必须在 安全环境 下运行。这意味着您的网页地址必须是:

  • 以 https:// 开头
  • 或者是 localhost (本地开发环境)

如果您是直接通过文件浏览器打开的 HTML 文件 (地址栏显示为 file:///...),浏览器会阻止摄像头启动。解决方案:使用一个简单的本地服务器来运行您的 HTML 文件。如果您正在使用 Visual Studio Code,最简单的方法是:

  1. 在 VS Code 中安装 Live Server 插件。
  1. 在您的 HTML 文件上右键,选择 “Open with Live Server”。
  1. 它会自动用 http://localhost:5500 这样的地址在浏览器中打开页面,这就满足了安全环境的要求。

2. 摄像头权限问题

当页面首次尝试访问摄像头时,浏览器会弹出一个权限请求框。

  • 您是否点击了“允许”? 如果不小心点击了“拒绝”,浏览器会记住这个选择,之后将不再询问并直接阻止。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML5 吊牌识别</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin: 0;
padding: 20px;
background-color: #f0f2f5;
}
h1 {
color: #333;
}
#video-container {
position: relative;
width: 90%;
max-width: 600px;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
#video {
width: 100%;
height: auto;
display: block;
}
#capture-btn {
margin-top: 20px;
padding: 12px 24px;
font-size: 16px;
color: #fff;
background-color: #007bff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
#capture-btn:hover {
background-color: #0056b3;
}
#capture-btn:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
#result-container {
margin-top: 20px;
width: 90%;
max-width: 600px;
padding: 15px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
min-height: 100px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
}
#status {
font-weight: bold;
color: #555;
margin-bottom: 10px;
}
#result {
white-space: pre-wrap; /* 保留换行和空格 */
word-wrap: break-word;
font-size: 16px;
line-height: 1.6;
color: #333;
}
/* 隐藏canvas,它只在后台用于处理图像 */
#canvas {
display: none;
}
</style>
</head>
<body>

<h1>HTML5 吊牌识别</h1>

<div id="video-container">
<video id="video" autoplay playsinline></video>
</div>

<button id="capture-btn">拍照并识别</button>

<div id="result-container">
<div id="status">识别结果将显示在这里</div>
<pre id="result"></pre>
</div>

<!-- 隐藏的Canvas元素 -->
<canvas id="canvas"></canvas>

<!-- 引入 Tesseract.js 库 -->
<script src='https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'></script>

<script>
document.addEventListener('DOMContentLoaded', () => {
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const captureBtn = document.getElementById('capture-btn');
const statusDiv = document.getElementById('status');
const resultDiv = document.getElementById('result');

let stream = null;

// 1. 启动摄像头
async function startCamera() {
try {
// 优先使用后置摄像头 (environment)
const constraints = {
video: {
facingMode: 'environment'
}
};
stream = await navigator.mediaDevices.getUserMedia(constraints);
video.srcObject = stream;
video.onloadedmetadata = () => {
video.play();
};
} catch (err) {
console.error("摄像头访问出错: ", err);
statusDiv.textContent = "无法访问摄像头。请检查权限或尝试使用HTTPs协议访问页面。";
// 如果后置摄像头失败,尝试使用前置摄像头
try {
const fallbackConstraints = { video: true };
stream = await navigator.mediaDevices.getUserMedia(fallbackConstraints);
video.srcObject = stream;
} catch (fallbackErr) {
console.error("前置摄像头也无法访问: ", fallbackErr);
}
}
}

// 2. 拍照并进行OCR识别
captureBtn.addEventListener('click', async () => {
if (!stream) {
alert('摄像头未启动!');
return;
}

// 禁用按钮,更新状态
captureBtn.disabled = true;
statusDiv.textContent = '正在识别中,请稍候... (首次识别需要下载语言包,会比较慢)';
resultDiv.textContent = '';

// 将视频帧绘制到Canvas上
const context = canvas.getContext('2d');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
context.drawImage(video, 0, 0, canvas.width, canvas.height);

// 使用Tesseract.js进行识别
try {
// 'chi_sim+eng' 表示同时识别简体中文和英文
const { data } = await Tesseract.recognize(
canvas,
'chi_sim+eng',
{
logger: m => {
// 在控制台显示识别进度
console.log(m);
if (m.status === 'recognizing text') {
const progress = (m.progress * 100).toFixed(2);
statusDiv.textContent = `正在识别... ${progress}%`;
}
}
}
);

// 显示识别结果
statusDiv.textContent = '识别完成!';
resultDiv.textContent = data.text || '未能识别出任何文字。';

} catch (error) {
console.error('OCR识别失败:', error);
statusDiv.textContent = '识别失败,请重试。';
} finally {
// 重新启用按钮
captureBtn.disabled = false;
}
});

// 页面加载后立即启动摄像头
startCamera();
});
</script>
</body>
</html>

posted @ 2025-07-11 16:05  Token007  阅读(22)  评论(0)    收藏  举报