first commit

This commit is contained in:
leidenglai 2022-05-23 16:26:14 +08:00
commit 1ef46ecdbe
13 changed files with 13597 additions and 0 deletions

0
README.md Normal file
View File

BIN
example/img/1.JPG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

BIN
example/img/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
example/img/5.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

160
example/index.html Normal file
View File

@ -0,0 +1,160 @@
<!DOCTYPE html>
<head>
<style>
.canvasInput-wrap {
width: 400px;
}
#canvasInput {
width: 100%;
}
#qrcodeCanvasOutput {
height: 120px;
width: 120px;
object-fit: contain;
}
</style>
</head>
<body>
<button id="qrcodeTryIt" disabled="true" onclick="qrcode_run()">Try it OpenCV</button><br>
<button id="qrcodeTryItJS" disabled="true" onclick="qrcode_run_qrjs()">Try it QRjs</button><br>
<div id="status"></div>
<hr>
<input type="file" id="fileInput" name="file" />
<hr>
<div id="qrcodeResult"><label for="">OpenCV QRCode:</label><span></span></div>
<div id="qrcodeResultQRjs"><label for="">QRjs QRCode:</label><span></span></div>
<div id="qrcodeShowcase">
<div>
<div class="canvasInput-wrap">
<canvas id="canvasInput"></canvas>
</div>
</div>
<hr>
<div>
<label for="">OpenCV QRCode image:</label>
<br />
<canvas id="qrcodeCanvasOutput"></canvas>
</div>
</div>
<script src="./jsqr.js"></script>
<script src="./utils.js"></script>
<script>
let qrcode_detector = undefined;
const OPENCV_URL = "./opencv.js";
const utils = new Utils();
utils.loadScript(OPENCV_URL).then(
() =>
{
loadModels();
},
() =>
{
utils.printError("Failed to load " + OPENCV_URL);
}
);
function updateStatus(text)
{
document.getElementById("status").innerHTML = text;
}
async function loadModels()
{
const detect_proto = "detect.prototxt";
const detect_weight = "detect.caffemodel";
const sr_proto = "sr.prototxt";
const sr_weight = "sr.caffemodel";
if (qrcode_detector != undefined) {
updateStatus("Model Existed");
} else {
const dp = await utils.fetchModelsData(detect_proto);
const dw = await utils.fetchModelsData(detect_weight);
const sp = await utils.fetchModelsData(sr_proto);
const sw = await utils.fetchModelsData(sr_weight);
cv.FS_createDataFile("/", "detect.prototxt", dp, true, false, false);
cv.FS_createDataFile("/", "detect.caffemodel", dw, true, false, false);
cv.FS_createDataFile("/", "sr.prototxt", sp, true, false, false);
cv.FS_createDataFile("/", "sr.caffemodel", sw, true, false, false);
qrcode_detector = new cv.wechat_qrcode_WeChatQRCode(
"detect.prototxt",
"detect.caffemodel",
"sr.prototxt",
"sr.caffemodel"
);
updateStatus("OpenCV Model Created");
}
}
function qrcode_run()
{
console.time("OpenCV耗时");
let inputImage = cv.imread("canvasInput", cv.IMREAD_GRAYSCALE);
let points_vec = new cv.MatVector();
let res = qrcode_detector.detectAndDecode(inputImage, points_vec);
console.log('opencv识别结果:', res.get(0));
if (res.size() !== 0) {
document.querySelector("#qrcodeResult span").innerHTML = res.get(0);
let points = points_vec.get(0);
let x = points.floatAt(0);
let y = points.floatAt(1);
let width = points.floatAt(4) - points.floatAt(0);
let height = points.floatAt(5) - points.floatAt(1);
let rect = new cv.Rect(x, y, width, height);
dst = inputImage.roi(rect);
cv.imshow("qrcodeCanvasOutput", dst);
}
console.timeEnd("OpenCV耗时");
}
function qrcode_run_qrjs()
{
console.time("QRjs耗时");
const canvas = document.getElementById("canvasInput");
const ctx = canvas.getContext("2d");
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const qrInfo = jsQR(imageData.data, imageData.width, imageData.height);
console.log('qrjs识别结果:', qrInfo);
if (qrInfo) {
document.querySelector("#qrcodeResultQRjs span").innerHTML = qrInfo.data;
}
console.timeEnd("QRjs耗时");
}
utils.loadImageToCanvas("./img/1.JPG", "canvasInput");
let fileInputElement = document.getElementById("fileInput");
fileInputElement.addEventListener("change", qrcodeHandleFiles, false);
function qrcodeHandleFiles(e)
{
const file = e.target.files[0];
const qrcodeUrl = URL.createObjectURL(file);
utils.loadImageToCanvas(qrcodeUrl, "canvasInput");
}
function onReady()
{
document.getElementById("qrcodeTryIt").disabled = false;
document.getElementById("qrcodeTryItJS").disabled = false;
}
if (typeof cv !== "undefined") {
onReady();
} else {
document.getElementById("opencvjs").onload = onReady;
}
</script>
</body>

10100
example/jsqr.js Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

403
example/models/sr.prototxt Normal file
View File

@ -0,0 +1,403 @@
layer {
name: "data"
type: "Input"
top: "data"
input_param {
shape {
dim: 1
dim: 1
dim: 224
dim: 224
}
}
}
layer {
name: "conv0"
type: "Convolution"
bottom: "data"
top: "conv0"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 32
bias_term: true
pad: 1
kernel_size: 3
group: 1
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "conv0/lrelu"
type: "ReLU"
bottom: "conv0"
top: "conv0"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "db1/reduce"
type: "Convolution"
bottom: "conv0"
top: "db1/reduce"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 8
bias_term: true
pad: 0
kernel_size: 1
group: 1
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "db1/reduce/lrelu"
type: "ReLU"
bottom: "db1/reduce"
top: "db1/reduce"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "db1/3x3"
type: "Convolution"
bottom: "db1/reduce"
top: "db1/3x3"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 8
bias_term: true
pad: 1
kernel_size: 3
group: 8
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "db1/3x3/lrelu"
type: "ReLU"
bottom: "db1/3x3"
top: "db1/3x3"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "db1/1x1"
type: "Convolution"
bottom: "db1/3x3"
top: "db1/1x1"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 32
bias_term: true
pad: 0
kernel_size: 1
group: 1
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "db1/1x1/lrelu"
type: "ReLU"
bottom: "db1/1x1"
top: "db1/1x1"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "db1/concat"
type: "Concat"
bottom: "conv0"
bottom: "db1/1x1"
top: "db1/concat"
concat_param {
axis: 1
}
}
layer {
name: "db2/reduce"
type: "Convolution"
bottom: "db1/concat"
top: "db2/reduce"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 8
bias_term: true
pad: 0
kernel_size: 1
group: 1
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "db2/reduce/lrelu"
type: "ReLU"
bottom: "db2/reduce"
top: "db2/reduce"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "db2/3x3"
type: "Convolution"
bottom: "db2/reduce"
top: "db2/3x3"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 8
bias_term: true
pad: 1
kernel_size: 3
group: 8
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "db2/3x3/lrelu"
type: "ReLU"
bottom: "db2/3x3"
top: "db2/3x3"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "db2/1x1"
type: "Convolution"
bottom: "db2/3x3"
top: "db2/1x1"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 32
bias_term: true
pad: 0
kernel_size: 1
group: 1
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "db2/1x1/lrelu"
type: "ReLU"
bottom: "db2/1x1"
top: "db2/1x1"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "db2/concat"
type: "Concat"
bottom: "db1/concat"
bottom: "db2/1x1"
top: "db2/concat"
concat_param {
axis: 1
}
}
layer {
name: "upsample/reduce"
type: "Convolution"
bottom: "db2/concat"
top: "upsample/reduce"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 32
bias_term: true
pad: 0
kernel_size: 1
group: 1
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "upsample/reduce/lrelu"
type: "ReLU"
bottom: "upsample/reduce"
top: "upsample/reduce"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "upsample/deconv"
type: "Deconvolution"
bottom: "upsample/reduce"
top: "upsample/deconv"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 32
bias_term: true
pad: 1
kernel_size: 3
group: 32
stride: 2
weight_filler {
type: "msra"
}
}
}
layer {
name: "upsample/lrelu"
type: "ReLU"
bottom: "upsample/deconv"
top: "upsample/deconv"
relu_param {
negative_slope: 0.05000000074505806
}
}
layer {
name: "upsample/rec"
type: "Convolution"
bottom: "upsample/deconv"
top: "upsample/rec"
param {
lr_mult: 1.0
decay_mult: 1.0
}
param {
lr_mult: 1.0
decay_mult: 0.0
}
convolution_param {
num_output: 1
bias_term: true
pad: 0
kernel_size: 1
group: 1
stride: 1
weight_filler {
type: "msra"
}
}
}
layer {
name: "nearest"
type: "Deconvolution"
bottom: "data"
top: "nearest"
param {
lr_mult: 0.0
decay_mult: 0.0
}
convolution_param {
num_output: 1
bias_term: false
pad: 0
kernel_size: 2
group: 1
stride: 2
weight_filler {
type: "constant"
value: 1.0
}
}
}
layer {
name: "Crop1"
type: "Crop"
bottom: "nearest"
bottom: "upsample/rec"
top: "Crop1"
}
layer {
name: "fc"
type: "Eltwise"
bottom: "Crop1"
bottom: "upsample/rec"
top: "fc"
eltwise_param {
operation: SUM
}
}

49
example/opencv.js Normal file

File diff suppressed because one or more lines are too long

49
example/opencv_old.js Normal file

File diff suppressed because one or more lines are too long

120
example/utils.js Normal file
View File

@ -0,0 +1,120 @@
function Utils(errorOutputId) {
this.errorOutput = document.getElementById(errorOutputId);
this.loadScript = function (url) {
return new Promise((resolve, reject) => {
let script = document.createElement("script");
script.setAttribute("async", "");
script.setAttribute("type", "text/javascript");
script.setAttribute("id", "opencvjs");
script.addEventListener("load", async () => {
if (cv.getBuildInformation) {
console.log(cv.getBuildInformation());
resolve();
} else {
// WASM
if (cv instanceof Promise) {
cv = await cv;
console.log(cv.getBuildInformation());
resolve();
} else {
cv["onRuntimeInitialized"] = () => {
console.log(cv.getBuildInformation());
resolve();
};
}
}
});
script.addEventListener("error", () => {
reject();
});
script.src = url;
let node = document.getElementsByTagName("script")[0];
node.parentNode.insertBefore(script, node);
});
};
/**
* 请求二维码训练模型文件
*/
this.fetchModelsData = async function (name) {
// const response = await fetch(`https://static.xxxx.com/common/opencv/models/${name}`, {
const response = await fetch(`./models/${name}`, {
method: "GET",
});
const data = await response.arrayBuffer();
return new Uint8Array(data);
};
/**
* 加载图片到canvas
* 发票的二维码基本都在左上角
* 为提高效率只截取出图片二维码的左上角区域放入canvas
* @param {*} url
* @param {*} cavansId
*/
this.loadImageToCanvas = function (url, cavansId) {
let canvas = document.getElementById(cavansId);
let ctx = canvas.getContext("2d");
let img = new Image();
img.crossOrigin = "anonymous";
img.onload = function () {
const { width, height } = img;
const isVertical = width < height;
const crossNum = isVertical ? 3 : 4;
const verticalNum = isVertical ? 4 : 3;
canvas.width = width / crossNum;
canvas.height = height / verticalNum;
ctx.drawImage(img, isVertical ? width * (2 / 3) : 0, 0, width, height, 0, 0, width, height);
};
img.src = url;
};
/**
* canvas转图片
*/
this.imagedataToImage = function (imagedata) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = imagedata.width;
canvas.height = imagedata.height;
ctx.putImageData(imagedata, 0, 0);
return new Promise((resolve) => {
const img = new Image();
img.src = canvas.toDataURL();
img.onload = () => {
resolve(img);
};
});
};
/**
* 拆分图片坐标
* @param {*} width 图片宽
* @param {*} height 图片高
*
* @returns 坐标数组 [x,y,width,height][]
*/
this.segmentationImageCoordinates = function (width, height) {
const isVertical = width < height;
const crossNum = isVertical ? 3 : 5;
const verticalNum = isVertical ? 5 : 3;
const blockWidth = width / crossNum;
const blockHeight = height / verticalNum;
const coordinates = [];
for (let y = 0; y < verticalNum; y++) {
for (let x = 0; x < crossNum; x++) {
const cx = x * blockWidth;
const cy = y * blockHeight;
coordinates.push([cx, cy, blockWidth, blockHeight]);
}
}
return coordinates;
};
}