<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
canvas {
border: 1px solid black;
background: #eee;
width: 600px;
height: auto;
}
#canvas {
margin-right: 20px;
}
</style>
</head>
<body>
<div style="margin-bottom: 20px;">
<input type="file" id="upload" accept="image/*">
</div>
<div>
<canvas id="canvas2"></canvas>
<canvas id="canvas"></canvas>
</div>
</body>
<script src="./opencv.js" type="text/javascript"></script>
<script>
const cv2 = cv;
const canvas = document.getElementById('canvas');
const canvas2 = document.getElementById('canvas2');
function extractAlphaChannel(img) {
const alphaChannel = new cv.Mat(img.rows, img.cols, cv.CV_8UC1);
for (let row = 0; row < img.rows; row++) {
for (let col = 0; col < img.cols; col++) {
alphaChannel.ucharPtr(row, col)[0] = img.ucharPtr(row, col)[3]; // Extract alpha channel manually
}
}
return alphaChannel;
}
function getLargestContour(alphaChannel) {
const contours = new cv.MatVector();
const hierarchy = new cv.Mat();
const blurred = new cv.Mat();
// Smoothing using GaussianBlur
cv.GaussianBlur(alphaChannel, blurred, new cv.Size(15, 15), 0);
cv.findContours(blurred, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
let largestContour = new cv.Mat();
let maxArea = 0;
for (let i = 0; i < contours.size(); ++i) {
const contour = contours.get(i);
const area = cv.contourArea(contour);
if (area > maxArea) {
maxArea = area;
contour.copyTo(largestContour);
}
}
return largestContour;
}
function drawFilledContourOnBlackBackground(contour, rows, cols) {
const contourImg = cv.Mat.zeros(rows, cols, cv.CV_8UC1);
const contours = new cv.MatVector();
contours.push_back(contour);
cv.drawContours(contourImg, contours, -1, new cv.Scalar(255, 255, 255), cv.FILLED);
return contourImg;
}
function applyDilation(img) {
const dilated = new cv.Mat();
const kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, new cv.Size(30, 30));
cv.dilate(img, dilated, kernel);
return dilated;
}
function applyOverlays(img, dilated) {
for (let row = 0; row < img.rows; row++) {
for (let col = 0; col < img.cols; col++) {
if (dilated.ucharPtr(row, col)[0] === 255 && img.ucharPtr(row, col)[3] === 0) {
img.ucharPtr(row, col)[0] = 255; // Set Red
img.ucharPtr(row, col)[1] = 255; // Set Green
img.ucharPtr(row, col)[2] = 255; // Set Blue
img.ucharPtr(row, col)[3] = 255; // Set Alpha
}
}
}
return img;
}
function createSticker(img) {
const alphaChannel = extractAlphaChannel(img);
const largestContour = getLargestContour(alphaChannel);
const contourImg = drawFilledContourOnBlackBackground(largestContour, alphaChannel.rows, alphaChannel.cols);
const dilatedImg = applyDilation(contourImg);
cv.imshow(canvas2, img);
const finalCanvas = applyOverlays(img, dilatedImg);
return finalCanvas;
}
document.getElementById('upload').addEventListener('change', (e) => {
const file = e.target.files[0];
const img = new Image();
const reader = new FileReader();
reader.onload = (event) => {
img.onload = () => {
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const src = cv.imread(canvas);
const dst = createSticker(src);
cv.imshow(canvas, dst);
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
});
</script>
</html>