使用Opencv.js从图像中检测矩形形状并将其裁剪

3

我看不到输出,也没有错误…… 我试图使用opencv.js从图像中检测矩形形状并裁剪它并保存它。

  onFilePicked() {
        let imgElement = document.getElementById('imageSrc');
        const files = event.target.files;
        imgElement.src = URL.createObjectURL(files[0]);
        var app = this
        imgElement.onload = function () {
            let mat = cv.imread(imgElement)
            let dst = new cv.Mat();

            cv.cvtColor(mat, mat, cv.COLOR_RGB2GRAY);
            // gray = cv.bilateralFilter(gray, 11, 17, 17)
            cv.Canny(mat, dst, 30, 200, 3, false);

            let contours = new cv.MatVector();
            let hierarchy = new cv.Mat();

            var transformed = null

            cv.findContours(dst, contours, hierarchy, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
            var sortableContours = []
            for (let i = 0; i < contours.size(); i++) {
                let cnt = contours.get(i);
                let area = cv.contourArea(cnt, false);
                let perim = cv.arcLength(cnt, false);

                sortableContours.push({
                    areaSize: area,
                    perimiterSize: perim,
                    contour: cnt
                });
                let color = new cv.Scalar(255, 0, 0, 255);
                let hierarchy2 = new cv.Mat();
                cv.drawContours(mat, contours, -1, (0, 255, 0), 3);
            }
            cv.imshow('canvasOutput', mat);

            let foundContour = null;
            for (let sortableContour of sortableContours) {
                let peri = cv.arcLength(sortableContour.contour, true);
                let approx = new cv.Mat();

                cv.approxPolyDP(sortableContour.contour, approx, 0.1 * peri, true);

                if (approx.rows == 4) {

                    foundContour = approx
                    transformed = app.perspective_transform(mat, foundContour)

                    break;
                } else {
                    approx.delete();
                }

            }

            let rotate = app.rotate_image(transformed, 90)

            cv.imshow('canvasOutput', rotate)


        };

    },

变换

  perspective_transform(image, foundContour) {

        let corner1 = new cv.Point(foundContour.data32S[0], foundContour.data32S[1]);
        let corner2 = new cv.Point(foundContour.data32S[2], foundContour.data32S[3]);
        let corner3 = new cv.Point(foundContour.data32S[4], foundContour.data32S[5]);
        let corner4 = new cv.Point(foundContour.data32S[6], foundContour.data32S[7]);

        //Order the corners
        let cornerArray = [{
            corner: corner1
        }, {
            corner: corner2
        }, {
            corner: corner3
        }, {
            corner: corner4
        }];
        //Sort by Y position (to get top-down)
        cornerArray.sort((item1, item2) => {
            return (item1.corner.y < item2.corner.y) ? -1 : (item1.corner.y > item2.corner.y) ? 1 : 0;
        }).slice(0, 5);

        //Determine left/right based on x position of top and bottom 2
        let tl = cornerArray[0].corner.x < cornerArray[1].corner.x ? cornerArray[0] : cornerArray[1];
        let tr = cornerArray[0].corner.x > cornerArray[1].corner.x ? cornerArray[0] : cornerArray[1];
        let bl = cornerArray[2].corner.x < cornerArray[3].corner.x ? cornerArray[2] : cornerArray[3];
        let br = cornerArray[2].corner.x > cornerArray[3].corner.x ? cornerArray[2] : cornerArray[3];

        //Calculate the max width/height
        let widthBottom = Math.hypot(br.corner.x - bl.corner.x, br.corner.y - bl.corner.y);
        let widthTop = Math.hypot(tr.corner.x - tl.corner.x, tr.corner.y - tl.corner.y);
        let theWidth = (widthBottom > widthTop) ? widthBottom : widthTop;
        let heightRight = Math.hypot(tr.corner.x - br.corner.x, tr.corner.y - br.corner.y);
        let heightLeft = Math.hypot(tl.corner.x - bl.corner.x, tr.corner.y - bl.corner.y);
        let theHeight = (heightRight > heightLeft) ? heightRight : heightLeft;

        //Transform!
        let finalDestCoords = cv.matFromArray(4, 1, cv.CV_32FC2, [0, 0, theWidth - 1, 0, theWidth - 1, theHeight - 1, 0, theHeight - 1]); 
       // corners
        let srcCoords = cv.matFromArray(4, 1, cv.CV_32FC2, [tl.corner.x, tl.corner.y, tr.corner.x, tr.corner.y, br.corner.x, br.corner.y, bl.corner.x, bl.corner.y]);
        let dsize = new cv.Size(theWidth, theHeight);
        let M = cv.getPerspectiveTransform(srcCoords, finalDestCoords)
        let dst = new cv.Mat();

        cv.warpPerspective(image, dst, M, dsize);

        return dst

    },

旋转图像。
rotate_image(image, angle) {

            let dst = new cv.Mat();
            let dsize = new cv.Size(image.rows, image.cols);
            let center = new cv.Point(image.cols / 2, image.rows / 2);
            // You can try more different parameters
            let M = cv.getRotationMatrix2D(center, angle, 1);
            cv.warpAffine(image, dst, M, dsize, cv.INTER_LINEAR, cv.BORDER_CONSTANT, new cv.Scalar());

            return dst
        },
1个回答

0

你只是在整个可排序轮廓数组中抓取第一个有4个点的轮廓,并对其运行变换。你需要先按面积最大的进行排序。

//sorts the contours by largest area first
let slicer = Math.min(sortableContours.length, 4);
let sortedContours = sortableContours.sort((a,b) => (a.areaSize < b.areaSize) ? 1 : -1).slice(0, slicer);

此外,我建议从for循环中删除这行代码,因为它可以在循环外执行一次,并且会显著减慢进程(运行数千次)。
cv.drawContours(mat, contours, -1, (0, 255, 0), 3);

我的最后建议是,如果您得到的结果不佳,以下行可能需要从.1调整为像.02这样的较小数字。.1更加宽容,但.02更加精确。或者,您可以同时使用两种方法,将所有结果保留在数组中,在完成后选择具有最大面积的结果,以获得最佳结果。
cv.approxPolyDP(sortableContour.contour, approx, 0.1 * peri, true);

两全其美:

//iterates through the largest contours and creates transformed images if the contour's shape is a rectangle
let transformedOptions = [];
for (let sortedContour of sortedContours) {
    let perimeter = cv.arcLength(sortedContour.contour, true);
    let precisePoly = new cv.Mat();
    let approxPoly = new cv.Mat();

    cv.approxPolyDP(sortedContour.contour, precisePoly, 0.02 * perimeter, true); //the smaller number (0.02) is more precise
    cv.approxPolyDP(sortedContour.contour, approxPoly, 0.1 * perimeter, true); //the larger number (0.1) is more forgiving

    //if the polygon has 4 points (rectangle-ish)
    if (precisePoly.rows == 4) {
        transformedOptions.push(this.perspectiveTransform(originalImage, precisePoly, imageHeight, imageWidth))
    }
    if(approxPoly.rows == 4) {
      transformedOptions.push(this.perspectiveTransform(originalImage, approxPoly, imageHeight, imageWidth))
    }

    precisePoly.delete();
    approxPoly.delete();
}

let transformed = this.getLargestTransformation(transformedOptions);

//this could be optimized a bit
private getLargestTransformation(options) {
var transformed = null;
for(let option of options) {
  if(option == null) continue;

  var largestArea = 0;
  var area = option.rows * option.cols;
  if(transformed == null || area > largestArea) {
    transformed = option;
    largestArea = area;
  }
}

return transformed;

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接