web前端用opencv.js做照片非矩形裁剪

176 阅读1分钟

场景

通常web前端想对图片做裁切,用的较多的前端组件比如Cropper.js,裁切都是规则矩形裁切 1cropper.js官网.png 进入官网对应的演练场,可以看到矩形裁切的功能
2矩形裁切.png 如果我们的场景是,需要裁切的照片如下面所示,拍摄时不是垂直拍摄,按我的专业方向来说就是非正射照片,需要选取的四边形区域不是正正好好的矩形,会有一定的变形,如图片中框定的红色区域所示,那么Cropper.js等只能规则矩形裁剪的前端库就不适用了! 4原图编辑.png 这里我找到的方法就是利用opencv.js来实现在web前端场景做四边形非矩形裁剪

opencv.js

本科和研究生时候用C++做遥感图像处理时,学习和用到opencv,它的功能超级强大,通过官网可以了解到现在借助WebAssembly,已经可以在web端发挥它的能力了!

5opencv.js介绍.png

示例代码

下面是我做的一个简单的html示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>OpenCV.js Perspective Transform</title>
    <style>
      canvas {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <h1>OpenCV.js Perspective Transform</h1>
    <h3 id="status">Loading the Opencv ...</h3>
    <input type="file" id="fileInput" accept="image/*" />
    <canvas id="canvas"></canvas>
    <canvas id="outputCanvas"></canvas>
    <script>
      let imgElement = new Image();
      let points = [];
      const maxPoints = 4;

      document
        .getElementById("fileInput")
        .addEventListener("change", (event) => {
          const file = event.target.files[0];
          const reader = new FileReader();
          reader.onload = function (e) {
            imgElement.src = e.target.result;
          };
          reader.readAsDataURL(file);
        });

      imgElement.onload = function () {
        const canvas = document.getElementById("canvas");
        const ctx = canvas.getContext("2d");
        canvas.width = imgElement.width;
        canvas.height = imgElement.height;
        ctx.drawImage(imgElement, 0, 0);
        points = [];
        canvas.addEventListener("click", getPoint);
      };

      function getPoint(event) {
        if (points.length < maxPoints) {
          const canvas = document.getElementById("canvas");
          const rect = canvas.getBoundingClientRect();
          const x = event.clientX - rect.left;
          const y = event.clientY - rect.top;
          points.push([x, y]);
          drawPoint(x, y);
          if (points.length === maxPoints) {
            performPerspectiveTransform();
          }
        }
      }

      function drawPoint(x, y) {
        const ctx = document.getElementById("canvas").getContext("2d");
        ctx.fillStyle = "red";
        ctx.beginPath();
        ctx.arc(x, y, 5, 0, Math.PI * 2);
        ctx.fill();
      }

      function performPerspectiveTransform() {
        const srcPoints = cv.matFromArray(4, 1, cv.CV_32FC2, points.flat());
        const dstPoints = cv.matFromArray(4, 1, cv.CV_32FC2, [
          0,
          0,
          imgElement.width,
          0,
          imgElement.width,
          imgElement.height,
          0,
          imgElement.height,
        ]);

        const M = cv.getPerspectiveTransform(srcPoints, dstPoints);
        const src = cv.imread("canvas");
        const dst = new cv.Mat();

        cv.warpPerspective(
          src,
          dst,
          M,
          new cv.Size(imgElement.width, imgElement.height),
          cv.INTER_LINEAR,
          cv.BORDER_CONSTANT,
          new cv.Scalar()
        );

        cv.imshow("outputCanvas", dst);

        src.delete();
        dst.delete();
        M.delete();
        srcPoints.delete();
        dstPoints.delete();
      }

      function onOpenCvReady() {
        document.getElementById("status").remove();
      }
    </script>
    <script
      async
      src="https://docs.opencv.org/4.5.3/opencv.js"
      onload="onOpenCvReady();"
      type="text/javascript"
    ></script>
  </body>
</html>

初始页面如下7初始页面.png打开一张图片显示在左侧,直接在左侧图片顺时针点选四个点8 选择一张图片.png在左侧图片选完四个点自动在右侧裁剪出四个点组成区域的照片,这里其实是用到opencv.js透视变换,大家可以自行根据上面示例代码查看9裁切.png
并最后附上测试图片
6缩略图.png

附上阿b视频链接