Create Sticker

<!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>
粤ICP备17098559号