首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Opencv.js从图像中检测矩形形状并将其切割

Opencv.js从图像中检测矩形形状并将其切割
EN

Stack Overflow用户
提问于 2020-02-01 23:05:55
回答 1查看 2.9K关注 0票数 3

我看不到输出,也没有错误..。我试着从图像中检测出矩形的形状,并将其切割并用opencv.js保存。

代码语言:javascript
运行
复制
  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)


        };

    },

变换

代码语言:javascript
运行
复制
  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

    },

旋转图像

代码语言:javascript
运行
复制
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
        },
EN

回答 1

Stack Overflow用户

发布于 2021-08-06 16:43:48

您只是在整个包含4个点的sortableContours数组中获取第一个等高线,并对其运行转换。你得先把它们排序到面积最大的地方。

代码语言:javascript
运行
复制
//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循环中删除这一行代码,因为它可以在循环之外执行一次,并使进程慢很多(运行几千次)。

代码语言:javascript
运行
复制
cv.drawContours(mat, contours, -1, (0, 255, 0), 3);

我最后要注意的是,如果您得到的结果很差,那么下面这一行可能需要从.1调整到更小的数量,比如.02。.1更宽容,但.02更精确。或者,您可以同时执行这两项操作,将所有结果保存在一个数组中,并在完成两个世界中最好的操作时,选择一个具有最大区域的结果。

代码语言:javascript
运行
复制
cv.approxPolyDP(sortableContour.contour, approx, 0.1 * peri, true);

这两个世界都是最好的:

代码语言:javascript
运行
复制
//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;

}

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60021855

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档