mirror of
https://github.com/woodchen-ink/extractstamp.git
synced 2025-07-18 14:02:01 +08:00
feat: motified extract with Mat function
This commit is contained in:
parent
191a7fb45e
commit
cec56bd613
109
extractstamp.js
109
extractstamp.js
@ -249,7 +249,7 @@ function detectCircles(dst) {
|
|||||||
1, // 两个圆心之间的最小距离
|
1, // 两个圆心之间的最小距离
|
||||||
dst.rows / 6, // 检测圆心之间的最小距离
|
dst.rows / 6, // 检测圆心之间的最小距离
|
||||||
200, // 修改检测圆形的阈值为200
|
200, // 修改检测圆形的阈值为200
|
||||||
50, // 检测<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>的阈值
|
50, // 检测的阈值
|
||||||
minRadius, // 检测圆形的最小半径
|
minRadius, // 检测圆形的最小半径
|
||||||
maxRadius // 检测圆形的最大半径
|
maxRadius // 检测圆形的最大半径
|
||||||
);
|
);
|
||||||
@ -335,107 +335,86 @@ function extractCircles(img, isCircle = true) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function extractCirclesWithCvMat(img, cvMat, isCircle = true) {
|
function extractCirclesWithCvMat(img, cvMat, isCircle = true) {
|
||||||
const dst = new cv.Mat()
|
let dst = new cv.Mat();
|
||||||
// 转换为灰度图
|
// 转换为灰度图
|
||||||
cv.cvtColor(cvMat, dst, cv.COLOR_RGBA2GRAY);
|
cv.cvtColor(cvMat, dst, cv.COLOR_RGBA2GRAY);
|
||||||
// 应用高斯模糊以减少噪声
|
// 应用高斯模糊以减少噪声
|
||||||
cv.GaussianBlur(dst, dst, new cv.Size(5, 5), 2, 2);
|
cv.GaussianBlur(dst, dst, new cv.Size(5, 5), 2, 2);
|
||||||
|
|
||||||
let croppedStamps = [];
|
let croppedStamps = [];
|
||||||
if (isCircle) {
|
if (isCircle) {
|
||||||
let circles = [];
|
|
||||||
// 检测圆形
|
// 检测圆形
|
||||||
circles = detectCircles(dst);
|
let circles = detectCircles(dst);
|
||||||
console.log("circles:", circles);
|
console.log("circles:", circles);
|
||||||
circles.forEach((circle) => {
|
circles.forEach((circle) => {
|
||||||
console.log("draw circle:", circle);
|
console.log("draw circle:", circle);
|
||||||
croppedStamps.push(cropAndDownloadCircle(img, circle));
|
croppedStamps.push(cropAndDownloadCircle(cvMat, circle));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let ellipses = [];
|
|
||||||
// 检测椭圆
|
// 检测椭圆
|
||||||
ellipses = detectEllipses(dst);
|
let ellipses = detectEllipses(dst);
|
||||||
console.log("ellipses:", ellipses);
|
console.log("ellipses:", ellipses);
|
||||||
ellipses.forEach((ellipse) => {
|
ellipses.forEach((ellipse) => {
|
||||||
console.log("draw ellipse:", ellipse);
|
console.log("draw ellipse:", ellipse);
|
||||||
croppedStamps.push(cropAndDownloadEllipse(img, ellipse));
|
croppedStamps.push(cropAndDownloadEllipse(cvMat, ellipse));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 释放内存
|
// 释放内存
|
||||||
dst.delete();
|
dst.delete();
|
||||||
cvMat.delete();
|
|
||||||
|
|
||||||
return croppedStamps;
|
return croppedStamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cropAndDownloadCircle(img, circle) {
|
function cropAndDownloadCircle(cvMat, circle) {
|
||||||
// 定义缩放因子,使裁剪范围比圆形大一些
|
// 定义缩放因子,使裁剪范围比圆形大一些
|
||||||
const scaleFactor = 1.2; // 增加20%的范围,您可以根据需要调整这个值
|
const scaleFactor = 1.2;
|
||||||
// 计算新的半径和尺寸
|
// 计算新的半径和尺寸
|
||||||
let newRadius = circle.radius * scaleFactor;
|
let newRadius = circle.radius * scaleFactor;
|
||||||
let size = newRadius * 2;
|
let size = Math.round(newRadius * 2);
|
||||||
|
|
||||||
// 创建一个新的canvas来裁剪圆形
|
// 创建一个新的Mat来存储裁剪后的图像
|
||||||
let cropCanvas = document.createElement("canvas");
|
let croppedMat = new cv.Mat();
|
||||||
cropCanvas.width = size;
|
let rect = new cv.Rect(
|
||||||
cropCanvas.height = size;
|
Math.round(circle.x - newRadius),
|
||||||
let ctx = cropCanvas.getContext("2d");
|
Math.round(circle.y - newRadius),
|
||||||
|
size,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
if (ctx) {
|
// 确保裁剪区域在图像范围内
|
||||||
// 清除整个canvas
|
rect.x = Math.max(0, Math.min(rect.x, cvMat.cols - rect.width));
|
||||||
ctx.clearRect(0, 0, size, size);
|
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);
|
||||||
|
|
||||||
// 裁剪圆形区域
|
// 裁剪图像
|
||||||
ctx.beginPath();
|
croppedMat = cvMat.roi(rect);
|
||||||
ctx.arc(newRadius, newRadius, newRadius, 0, Math.PI * 2);
|
|
||||||
ctx.closePath();
|
|
||||||
ctx.clip();
|
|
||||||
|
|
||||||
// 计算源图像的裁剪区域
|
// 创建圆形掩码
|
||||||
let sx = circle.x - newRadius;
|
let mask = new cv.Mat.zeros(size, size, cv.CV_8UC1);
|
||||||
let sy = circle.y - newRadius;
|
let center = new cv.Point(size / 2, size / 2);
|
||||||
let sWidth = size;
|
cv.circle(mask, center, Math.round(newRadius), new cv.Scalar(255, 255, 255), -1);
|
||||||
let sHeight = size;
|
|
||||||
|
|
||||||
// 确保不会裁剪到图像边界外
|
// 应用掩码
|
||||||
if (sx < 0) {
|
let result = new cv.Mat();
|
||||||
sWidth += sx;
|
cv.bitwise_and(croppedMat, croppedMat, result, mask);
|
||||||
sx = 0;
|
|
||||||
}
|
|
||||||
if (sy < 0) {
|
|
||||||
sHeight += sy;
|
|
||||||
sy = 0;
|
|
||||||
}
|
|
||||||
if (sx + sWidth > img.width) {
|
|
||||||
sWidth = img.width - sx;
|
|
||||||
}
|
|
||||||
if (sy + sHeight > img.height) {
|
|
||||||
sHeight = img.height - sy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绘制裁剪后的图像
|
// 将结果转换为PNG数据URL
|
||||||
ctx.drawImage(img, sx, sy, sWidth, sHeight, 0, 0, size, size);
|
let imgData = new ImageData(new Uint8ClampedArray(result.data), result.cols, result.rows);
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
canvas.width = result.cols;
|
||||||
|
canvas.height = result.rows;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
ctx.putImageData(imgData, 0, 0);
|
||||||
|
let dataURL = canvas.toDataURL("image/png");
|
||||||
|
|
||||||
// 获取图像数据
|
// 释放内存
|
||||||
let imageData = ctx.getImageData(0, 0, size, size);
|
croppedMat.delete();
|
||||||
let data = imageData.data;
|
mask.delete();
|
||||||
|
result.delete();
|
||||||
|
|
||||||
// 将白色背景转为透明
|
|
||||||
for (let i = 0; i < data.length; i += 4) {
|
|
||||||
// 检查像素是否接近白色
|
|
||||||
if (data[i] > 240 && data[i + 1] > 240 && data[i + 2] > 240) {
|
|
||||||
// 将alpha通道设置为0(完全透明)
|
|
||||||
data[i + 3] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将处理后的图像数据放回canvas
|
|
||||||
ctx.putImageData(imageData, 0, 0);
|
|
||||||
|
|
||||||
// 将裁剪后的图像转换为数据URL(PNG格式以保持透明度)
|
|
||||||
let dataURL = cropCanvas.toDataURL("image/png");
|
|
||||||
return dataURL;
|
return dataURL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user