mirror of
https://github.com/woodchen-ink/extractstamp.git
synced 2025-07-18 05:52:00 +08:00
feat: remove special red stamp functions
This commit is contained in:
parent
c630526a94
commit
134d70f7df
202
extractstamp.js
202
extractstamp.js
@ -313,32 +313,6 @@ function extractCircles(img) {
|
|||||||
return croppedStamps;
|
return croppedStamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectEllipses(dst) {
|
|
||||||
let thresh = new cv.Mat();
|
|
||||||
cv.threshold(dst, thresh, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU);
|
|
||||||
let contours = new cv.MatVector();
|
|
||||||
let hierarchy = new cv.Mat();
|
|
||||||
cv.findContours(thresh, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
|
|
||||||
|
|
||||||
let detectedEllipses = [];
|
|
||||||
let minRadius = Math.min(dst.rows, dst.cols) * 0.05; // 最小半径
|
|
||||||
let maxRadius = Math.min(dst.rows, dst.cols) * 0.5; // 最大半径
|
|
||||||
|
|
||||||
for (let i = 0; i < contours.size(); ++i) {
|
|
||||||
let cnt = contours.get(i);
|
|
||||||
if (cnt.rows >= 5) { // 至少需要5个点来拟合椭圆
|
|
||||||
let ellipse = cv.fitEllipse(cnt);
|
|
||||||
let avgRadius = (ellipse.size.width + ellipse.size.height) / 4; // 计算平均半径
|
|
||||||
if (avgRadius >= minRadius && avgRadius <= maxRadius) {
|
|
||||||
detectedEllipses.push(ellipse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thresh.delete(); contours.delete(); hierarchy.delete();
|
|
||||||
return detectedEllipses;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取印章圆形
|
* 提取印章圆形
|
||||||
* @param {*} cvMat
|
* @param {*} cvMat
|
||||||
@ -416,180 +390,6 @@ function cropAndDownloadCircle(cvMat, circle) {
|
|||||||
return dataURL;
|
return dataURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cropAndDownloadEllipse(cvMat, ellipse) {
|
|
||||||
// 定义缩放因子,使裁剪范围比椭圆大一些
|
|
||||||
const scaleFactor = 1.2;
|
|
||||||
const width = ellipse.size.width > ellipse.size.height ? ellipse.size.width : ellipse.size.height;
|
|
||||||
const height = ellipse.size.width < ellipse.size.height ? ellipse.size.width : ellipse.size.height;
|
|
||||||
const scaledWidth = Math.round(width * scaleFactor);
|
|
||||||
const scaledHeight = Math.round(height * scaleFactor);
|
|
||||||
|
|
||||||
// 创建一个新的Mat来存储裁剪后的图像
|
|
||||||
let croppedMat = new cv.Mat();
|
|
||||||
let rect = new cv.Rect(
|
|
||||||
Math.round(ellipse.center.x - scaledWidth / 2),
|
|
||||||
Math.round(ellipse.center.y - scaledHeight / 2),
|
|
||||||
scaledWidth,
|
|
||||||
scaledHeight
|
|
||||||
);
|
|
||||||
|
|
||||||
// 确保裁剪区域在图像范围内
|
|
||||||
rect.x = Math.max(0, Math.min(rect.x, cvMat.cols - rect.width));
|
|
||||||
rect.y = Math.max(0, Math.min(rect.y, cvMat.rows - rect.height));
|
|
||||||
rect.width = Math.min(rect.width, cvMat.cols - rect.x);
|
|
||||||
rect.height = Math.min(rect.height, cvMat.rows - rect.y);
|
|
||||||
|
|
||||||
// 裁剪图像
|
|
||||||
croppedMat = cvMat.roi(rect);
|
|
||||||
|
|
||||||
// 创建椭圆形掩码
|
|
||||||
let mask = new cv.Mat.zeros(scaledHeight, scaledWidth, cv.CV_8UC1);
|
|
||||||
let center = new cv.Point(scaledWidth / 2, scaledHeight / 2);
|
|
||||||
let axes = new cv.Size(width / 2, height / 2);
|
|
||||||
cv.ellipse(mask, center, axes, ellipse.angle, 0, 360, new cv.Scalar(255, 255, 255), -1);
|
|
||||||
|
|
||||||
// 应用掩码
|
|
||||||
let result = new cv.Mat();
|
|
||||||
cv.bitwise_and(croppedMat, croppedMat, result, mask);
|
|
||||||
|
|
||||||
// 将结果转换为PNG数据URL
|
|
||||||
let canvas = document.createElement('canvas');
|
|
||||||
canvas.width = result.cols;
|
|
||||||
canvas.height = result.rows;
|
|
||||||
cv.imshow(canvas, result);
|
|
||||||
let dataURL = canvas.toDataURL("image/png");
|
|
||||||
|
|
||||||
// 释放内存
|
|
||||||
croppedMat.delete();
|
|
||||||
mask.delete();
|
|
||||||
result.delete();
|
|
||||||
|
|
||||||
return dataURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据文件提取红色印章
|
|
||||||
* @param file
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function extractRedStampWithFile(file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const img = new Image();
|
|
||||||
img.onload = () => {
|
|
||||||
const dstImg = extractRedStampWithColor(img, primaryColor);
|
|
||||||
resolve(dstImg);
|
|
||||||
};
|
|
||||||
img.onerror = (error) => {
|
|
||||||
console.error("图片加载失败", error);
|
|
||||||
reject(new Error("图片加载失败"));
|
|
||||||
};
|
|
||||||
img.src = URL.createObjectURL(file);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提取红色印章
|
|
||||||
* @param img 原始图片
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function extractRedStamp(img) {
|
|
||||||
if (cvReady) {
|
|
||||||
const dstImg = extractRedStampWithColor(img, primaryColor);
|
|
||||||
return dstImg;
|
|
||||||
} else {
|
|
||||||
console.error("OpenCV.js 未加载");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提取红色印章
|
|
||||||
* @param img
|
|
||||||
* @param color
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function extractRedStampWithColor(img, color = primaryColor) {
|
|
||||||
if (cvReady) {
|
|
||||||
// 获取图片的宽高
|
|
||||||
const imgWidth = img.width;
|
|
||||||
const imgHeight = img.height;
|
|
||||||
console.log("图片宽度:", imgWidth, "图片高度:", imgHeight);
|
|
||||||
let src = cv.imread(img);
|
|
||||||
let dst = new cv.Mat();
|
|
||||||
let mask = new cv.Mat();
|
|
||||||
|
|
||||||
// 转换为HSV颜色空间
|
|
||||||
cv.cvtColor(src, dst, cv.COLOR_RGBA2RGB);
|
|
||||||
cv.cvtColor(dst, dst, cv.COLOR_RGB2HSV);
|
|
||||||
|
|
||||||
// 定义红色和暗红色的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(),
|
|
||||||
[50, 255, 255, 255]
|
|
||||||
);
|
|
||||||
let lowRedB = new cv.Mat(
|
|
||||||
dst.rows,
|
|
||||||
dst.cols,
|
|
||||||
dst.type(),
|
|
||||||
[160, 100, 100, 0]
|
|
||||||
);
|
|
||||||
let highRedB = new cv.Mat(
|
|
||||||
dst.rows,
|
|
||||||
dst.cols,
|
|
||||||
dst.type(),
|
|
||||||
[180, 255, 255, 255]
|
|
||||||
);
|
|
||||||
|
|
||||||
// 创建掩码
|
|
||||||
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);
|
|
||||||
|
|
||||||
// 将十六进制颜色值转换为RGB
|
|
||||||
const dstColor = hexToRgba(color);
|
|
||||||
console.log("dstColor:", dstColor);
|
|
||||||
// 创建纯红色图像
|
|
||||||
let red = new cv.Mat(src.rows, src.cols, src.type(), dstColor);
|
|
||||||
|
|
||||||
// 使用掩码将红色区域设置为纯红色
|
|
||||||
red.copyTo(dst, mask);
|
|
||||||
|
|
||||||
// 创建隐藏的canvas用来保存提取后的图片
|
|
||||||
const hiddenCanvas = document.createElement("canvas");
|
|
||||||
hiddenCanvas.width = dst.cols;
|
|
||||||
hiddenCanvas.height = dst.rows;
|
|
||||||
cv.imshow(hiddenCanvas, dst);
|
|
||||||
let dataURL = hiddenCanvas.toDataURL("image/png");
|
|
||||||
let link = document.createElement("a");
|
|
||||||
link.download = "extracted_red_image.png";
|
|
||||||
link.href = dataURL;
|
|
||||||
link.click();
|
|
||||||
|
|
||||||
// 释放内存
|
|
||||||
src.delete();
|
|
||||||
dst.delete();
|
|
||||||
mask.delete();
|
|
||||||
maskA.delete();
|
|
||||||
maskB.delete();
|
|
||||||
lowRedA.delete();
|
|
||||||
highRedA.delete();
|
|
||||||
lowRedB.delete();
|
|
||||||
highRedB.delete();
|
|
||||||
red.delete();
|
|
||||||
return dst;
|
|
||||||
} else {
|
|
||||||
console.error("OpenCV.js 未加载");
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将十六进制颜色值转换为RGBA
|
* 将十六进制颜色值转换为RGBA
|
||||||
* @param hex
|
* @param hex
|
||||||
@ -616,8 +416,6 @@ function extractStampWithImage(img, setColor) {
|
|||||||
|
|
||||||
// 在文件末尾,将函数添加到全局作用域
|
// 在文件末尾,将函数添加到全局作用域
|
||||||
window.initOpenCV = initOpenCV;
|
window.initOpenCV = initOpenCV;
|
||||||
window.extractRedStampWithFile = extractRedStampWithFile;
|
|
||||||
window.extractRedStamp = extractRedStamp;
|
|
||||||
window.extractStampWithFile = extractStampWithFile;
|
window.extractStampWithFile = extractStampWithFile;
|
||||||
window.extractStampWithImage = extractStampWithImage;
|
window.extractStampWithImage = extractStampWithImage;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user