<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>OpenCV.js + QRCode 识别 + JS 耗时统计</title>
<style>
canvas, input {
margin: 10px;
border: 1px solid #ccc;
}
.slider-container {
display: flex;
align-items: center;
gap: 10px;
}
#qrResults, #timeStats {
white-space: pre-wrap;
background-color: #f4f4f4;
padding: 10px;
margin-top: 10px;
font-family: monospace;
}
</style>
</head>
<body>
<h2>上传图片并实时调节二值化阈值 + 识别二维码 + JS 耗时统计</h2>
<input type="file" id="imageInput" accept="image/*"><br><br>
<div class="slider-container">
<label for="thresholdSlider">阈值 (0~255): </label>
<input type="range" id="thresholdSlider" min="0" max="255" value="128">
<span id="thresholdValue">128</span>
</div>
<canvas id="canvasOriginal"></canvas>
<canvas id="canvasGray"></canvas>
<canvas id="canvasBinary"></canvas>
<h3>识别到的二维码:</h3>
<div id="qrResults">暂无识别结果</div>
<h3>JS 耗时统计:</h3>
<div id="timeStats">等待图像处理...</div>
<!-- OpenCV.js -->
<script async src="https://docs.opencv.org/4.5.0/opencv.js"></script>
<!-- jsQR.js 用于识别二维码 -->
<script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js"></script>
<script>
let currentGray = null;
let threshold = 128;
// 等待 OpenCV 加载完成
window.addEventListener("load", function () {
if (typeof cv !== 'undefined' && typeof jsQR === 'function') {
console.log("OpenCV 和 jsQR 已加载");
const slider = document.getElementById('thresholdSlider');
const thresholdLabel = document.getElementById('thresholdValue');
// 监听滑动事件
slider.addEventListener('input', function () {
threshold = parseInt(slider.value);
thresholdLabel.textContent = threshold;
if (currentGray) {
updateBinaryImage(currentGray, threshold);
}
});
document.getElementById('imageInput').addEventListener('change', handleImageUpload);
} else {
alert("OpenCV 或 jsQR 加载失败,请检查网络!");
}
});
function handleImageUpload(e) {
let file = e.target.files[0];
if (!file) return;
let img = new Image();
img.onload = function () {
processImage(img);
};
img.src = URL.createObjectURL(file);
}
function processImage(img) {
const timeStats = document.getElementById("timeStats");
timeStats.innerText = "正在处理...";
const tStart = performance.now();
let src = cv.imread(img); // 原图
const tRead = performance.now();
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY);
const tGray = performance.now();
// 保存灰度图用于后续处理
if (currentGray) {
currentGray.delete();
}
currentGray = gray.clone();
const tClone = performance.now();
// 初始显示原图和灰度图
cv.imshow("canvasOriginal", src);
const tShowOrig = performance.now();
cv.imshow("canvasGray", gray);
const tShowGray = performance.now();
// 初始显示二值化图像
updateBinaryImage(gray, threshold);
const tEnd = performance.now();
// 计算耗时
const stats = `
【JS 耗时统计】
读取图像: ${(tRead - tStart).toFixed(2)} ms
灰度转换: ${(tGray - tRead).toFixed(2)} ms
克隆灰度图: ${(tClone - tGray).toFixed(2)} ms
显示原图: ${(tShowOrig - tClone).toFixed(2)} ms
显示灰度图: ${(tShowGray - tShowOrig).toFixed(2)} ms
初始化二值化: ${(tEnd - tShowGray).toFixed(2)} ms
总计: ${(tEnd - tStart).toFixed(2)} ms
`.trim();
timeStats.innerText = stats;
// 释放资源
src.delete();
}
function updateBinaryImage(gray, thresholdValue) {
let binary = new cv.Mat();
try {
const tBinaryStart = performance.now();
cv.threshold(gray, binary, thresholdValue, 255, cv.THRESH_BINARY);
cv.imshow("canvasBinary", binary);
const tBinaryEnd = performance.now();
// 更新耗时统计
const statsDiv = document.getElementById("timeStats");
const existingText = statsDiv.innerText;
const binaryTime = (tBinaryEnd - tBinaryStart).toFixed(2);
statsDiv.innerText = existingText + `\n二值化耗时: ${binaryTime} ms`;
// 调用二维码识别
detectQRFromMat(binary);
} catch (err) {
console.error(err);
} finally {
binary.delete();
}
}
function detectQRFromMat(mat) {
const canvasBinary = document.getElementById("canvasBinary");
const ctx = canvasBinary.getContext("2d");
const imageData = ctx.getImageData(0, 0, canvasBinary.width, canvasBinary.height);
const tQRStart = performance.now();
const code = jsQR(imageData.data, imageData.width, imageData.height);
const tQREnd = performance.now();
const resultDiv = document.getElementById("qrResults");
const timeStatsDiv = document.getElementById("timeStats");
if (code) {
resultDiv.innerHTML = `识别到二维码:\n${code.data}`;
timeStatsDiv.innerText += `\n二维码识别耗时: ${(tQREnd - tQRStart).toFixed(2)} ms`;
} else {
resultDiv.innerText = "未识别到二维码。";
timeStatsDiv.innerText += `\n二维码识别耗时: ${(tQREnd - tQRStart).toFixed(2)} ms`;
}
}
</script>
</body>
</html>