From e575ecdd7445dbff79ecb5e8b7193d7ac6281509 Mon Sep 17 00:00:00 2001 From: xxss0903 Date: Fri, 25 Oct 2024 17:30:11 +0800 Subject: [PATCH] feat: add extract red circle stamp --- extractstamp.js | 115 +++++++++++++++++------------------------------- index.html | 37 +++++++++++++--- 2 files changed, 71 insertions(+), 81 deletions(-) diff --git a/extractstamp.js b/extractstamp.js index 3b1bbdb..d52e4a0 100644 --- a/extractstamp.js +++ b/extractstamp.js @@ -36,7 +36,6 @@ function initOpenCV(callback) { */ function extractStampWithColorImpl( img, - extractColor = "#ff0000", setColor = "#ff0000" ) { if (cvReady) { @@ -52,65 +51,23 @@ function extractStampWithColorImpl( cv.cvtColor(src, dst, cv.COLOR_RGBA2RGB); cv.cvtColor(dst, dst, cv.COLOR_RGB2HSV); - // 将提取颜色转换为HSV - const extractColorRGB = hexToRgba(extractColor); - const extractColorHSV = cv.matFromArray(1, 1, cv.CV_8UC3, [ - extractColorRGB[0], - extractColorRGB[1], - extractColorRGB[2], - ]); - cv.cvtColor(extractColorHSV, extractColorHSV, cv.COLOR_RGB2HSV); - const hsvValues = extractColorHSV.data32F; - - // 定义提取颜色的HSV范围 - let lowColor, highColor; - if (extractColor.toLowerCase() === "#ff0000") { - // 红色的HSV范围 - lowColor = new cv.Mat(dst.rows, dst.cols, dst.type(), [0, 100, 100, 0]); - highColor = new cv.Mat( - dst.rows, - dst.cols, - dst.type(), - [10, 255, 255, 255] - ); - } else if (extractColor.toLowerCase() === "#00ff00") { - // 绿色的HSV范围 - lowColor = new cv.Mat(dst.rows, dst.cols, dst.type(), [60, 100, 100, 0]); - highColor = new cv.Mat( - dst.rows, - dst.cols, - dst.type(), - [80, 255, 255, 255] - ); - } else if (extractColor.toLowerCase() === "#000000") { - // 黑色的HSV范围 - lowColor = new cv.Mat(dst.rows, dst.cols, dst.type(), [0, 0, 0, 0]); - highColor = new cv.Mat( - dst.rows, - dst.cols, - dst.type(), - [180, 255, 30, 255] - ); - } else { - // 其他颜色(包括随机颜色如#00ffff)使用动态计算的范围 - const hue = hsvValues[0]; - const hueRange = 10; // 色相范围,可以根据需要调整 - lowColor = new cv.Mat(dst.rows, dst.cols, dst.type(), [ - Math.max(0, hue - hueRange), - 100, - 100, - 0, - ]); - highColor = new cv.Mat(dst.rows, dst.cols, dst.type(), [ - Math.min(180, hue + hueRange), - 255, - 255, - 255, - ]); - } + // 定义红色的HSV范围 + // 低值范围 (0-10) + let lowRedA = new cv.Mat(dst.rows, dst.cols, dst.type(), [0, 50, 50, 0]); + let highRedA = new cv.Mat(dst.rows, dst.cols, dst.type(), [10, 255, 255, 255]); + + // 高值范围 (170-180) + let lowRedB = new cv.Mat(dst.rows, dst.cols, dst.type(), [170, 50, 50, 0]); + let highRedB = new cv.Mat(dst.rows, dst.cols, dst.type(), [180, 255, 255, 255]); // 创建掩码 - cv.inRange(dst, lowColor, highColor, mask); + let maskA = new cv.Mat(); + let maskB = new cv.Mat(); + cv.inRange(dst, lowRedA, highRedA, maskA); + cv.inRange(dst, lowRedB, highRedB, maskB); + + // 合并掩码 + cv.add(maskA, maskB, mask); // 将十六进制颜色值转换为RGBA const dstColor = hexToRgba(setColor); @@ -139,9 +96,12 @@ function extractStampWithColorImpl( src.delete(); dst.delete(); mask.delete(); - lowColor.delete(); - highColor.delete(); - extractColorHSV.delete(); + maskA.delete(); + maskB.delete(); + lowRedA.delete(); + highRedA.delete(); + lowRedB.delete(); + highRedB.delete(); colorMat.delete(); result.delete(); return dataURL; @@ -152,19 +112,18 @@ function extractStampWithColorImpl( } /** - * 提取指定颜色的印章 + * 提取红色的印章 * @param file 图片文件 - * @param extractColor 提取的颜色 * @param setColor 设置的颜色,比如提取红色设置红色那么能够进行对印章的填充 * @param isCircle 是否是圆形,如果是圆形,那么会进行圆形的裁剪,否则进行椭圆的裁剪 * @returns */ -function extractStampWithFile(file, extractColor, setColor, isCircle = true) { +function extractStampWithFile(file, setColor, isCircle = true) { return new Promise((resolve, reject) => { const img = new Image(); let distImgList = []; img.onload = async () => { - let dstImg = extractStampWithColorImpl(img, extractColor, setColor); + let dstImg = extractStampWithColorImpl(img, setColor); let debugCircle = true; if (debugCircle) { // 将base64的图像数据转换为Image对象 @@ -180,8 +139,10 @@ function extractStampWithFile(file, extractColor, setColor, isCircle = true) { const resultRedImg = await base64ToImage(dstImg); // 提取圆圈并获取结果 distImgList = extractCircles(resultRedImg, isCircle); + resolve(distImgList); + } else { + resolve([dstImg]) } - resolve(distImgList); }; img.onerror = (error) => { console.error("图片加载失败", error); @@ -200,7 +161,7 @@ function detectCircles(dst) { // 创建一个新的Mat对象来存储检测到的圆形 let circles = new cv.Mat(); // 计算最小和最大半径,用于限制检测到的圆形大小 - let minRadius = Math.min(dst.rows, dst.cols) * 0.05; // 最小半径为图像最小边的5% + let minRadius = Math.min(dst.rows, dst.cols) * 0.03; // 最小半径为图像最小边的5% let maxRadius = Math.min(dst.rows, dst.cols) * 0.5; // 最大半径为图像最小边的50% // 使用Hough变换检测圆形 cv.HoughCircles( @@ -208,8 +169,8 @@ function detectCircles(dst) { circles, cv.HOUGH_GRADIENT, 1, // 两个圆心之间的最小距离 - dst.rows / 4, // 检测圆心之间的最小距离 - 100, // 检测圆形的阈值 + dst.rows / 8, // 检测圆心之间的最小距离 + 200, // 修改检测圆形的阈值为200 50, // 检测圆形的阈值 minRadius, // 检测圆形的最小半径 maxRadius // 检测圆形的最大半径 @@ -226,21 +187,22 @@ function detectCircles(dst) { radius: circles.data32F[i * 3 + 2] // 半径 }); } + console.log("detectedCircles:", detectedCircles, maxRadius, minRadius, dst.rows, dst.cols); // 根据半径大小对检测到的圆形进行排序,确保最大的圆形排在前面 detectedCircles.sort((a, b) => b.radius - a.radius); // 释放内存 circles.delete(); // 返回最大的3个圆形 - return detectedCircles.slice(0, 3); + return detectedCircles.slice(0, 6); } /** * 提取印章圆形 - * @param {*} img - * @param {*} isCircle - * @returns + * @param {*} img + * @param {*} isCircle + * @returns */ function extractCircles(img, isCircle = true) { let src = cv.imread(img); @@ -393,13 +355,13 @@ function extractRedStampWithColor(img, color = primaryColor) { cv.cvtColor(src, dst, cv.COLOR_RGBA2RGB); cv.cvtColor(dst, dst, cv.COLOR_RGB2HSV); - // 定义红色的HSV范围 + // 定义红色和暗红色的HSV范围 let lowRedA = new cv.Mat(dst.rows, dst.cols, dst.type(), [0, 100, 100, 0]); let highRedA = new cv.Mat( dst.rows, dst.cols, dst.type(), - [10, 255, 255, 255] + [50, 255, 255, 255] ); let lowRedB = new cv.Mat( dst.rows, @@ -419,6 +381,8 @@ function extractRedStampWithColor(img, color = primaryColor) { let maskB = new cv.Mat(); cv.inRange(dst, lowRedA, highRedA, maskA); cv.inRange(dst, lowRedB, highRedB, maskB); + + cv.add(maskA, maskB, mask); // 将十六进制颜色值转换为RGB @@ -480,3 +444,4 @@ window.initOpenCV = initOpenCV; window.extractRedStampWithFile = extractRedStampWithFile; window.extractRedStamp = extractRedStamp; window.extractStampWithFile = extractStampWithFile; + diff --git a/index.html b/index.html index 272673e..59f2c84 100644 --- a/index.html +++ b/index.html @@ -7,17 +7,21 @@