为什么OpenCV中的drawContour()会生成这种奇怪的遮罩?

为什么OpenCV中的drawContour()会生成这种奇怪的遮罩?,opencv,image-processing,opencv3.0,opencv4android,opencv-contour,Opencv,Image Processing,Opencv3.0,Opencv4android,Opencv Contour,我从这张Mat开始阅读 然后我将其转换为灰度,并对其应用Imgproc.canny(),得到以下掩码 然后我使用Imgproc.findContours()查找轮廓,Imgproc.drawContours(),和Core.putText()用数字标记轮廓: 然后我做了Rect boundingRect=Imgproc.boundingRect(contours.get(0)); Mat子矩阵=新Mat(); 子矩阵=原始矩阵子矩阵(boundingRect)获取以下子矩阵: 到目前为止

我从这张
Mat
开始阅读

然后我将其转换为灰度,并对其应用
Imgproc.canny()
,得到以下掩码

然后我使用
Imgproc.findContours()
查找轮廓,
Imgproc.drawContours()
,和
Core.putText()
用数字标记轮廓:

然后我做了
Rect boundingRect=Imgproc.boundingRect(contours.get(0));
Mat子矩阵=新Mat();
子矩阵=原始矩阵子矩阵(boundingRect)
获取以下
子矩阵

到目前为止还不错。问题从下文开始:

现在我需要一个
子矩阵的掩码。所以我决定使用
Imgproc.drawContours()
来获得面具:

Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1);
        List<MatOfPoint> contourList = new ArrayList<>();
        contourList.add(contours.get(0));
        Imgproc.drawContours(mask, contourList, 0, new Scalar(255), -1);
Mat mask=new Mat(submatrix.rows()、submatrix.cols()、CvType.CV_8UC1);
List contourList=新的ArrayList();
contourList.add(contours.get(0));
Imgproc.drawContours(掩码,轮廓列表,0,新标量(255),-1);
我得到了以下面具:

我所期待的是黑色背景上的填充(白色)钻石形状。

为什么我会得到这个意外的结果?


编辑:

Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1);
        List<MatOfPoint> contourList = new ArrayList<>();
        contourList.add(contours.get(0));
        Imgproc.drawContours(mask, contourList, 0, new Scalar(255), -1);
  • 当我替换
    Mat mask=new Mat(submatrix.rows())时,
    submatrix.cols(),CvType.CV_8UC1)由,
    最后一个带白色垃圾的面具被一个空面具取代
    黑色面具上没有任何白色。我有下面的潜艇
    和面具:

  • 我得到了轮廓列表中的第一个轮廓(命名为
    等高线
    )通过
    等高线。获取(0)
    ,并使用此第一个等高线 计算
    Imgproc.boundingRect()
    以及
    contourList.add(contours.get(0))稍后(其中
    轮廓列表
    为 仅一个轮廓的列表,将在最后一个轮廓中使用
    drawContours()

    然后我继续更改
    轮廓。将(0)
    设置为
    轮廓。在
    Imgproc.boundingRect()以及
    轮廓列表中获取(1)
    (就在
    Imgproc.drawContours()之前)。那个
    导致此submat和mask:

  • 然后我又回到了
    轮廓。进入(0)
    Imgproc.boundingRect()
    ;让
    contourList.add(contours.get(1))在那里。得到以下信息
    潜艇和面罩:


  • <> >强>现在我完全不能理解这里发生了什么。<强> > /p> < p>我不确定java中的句柄(我通常使用C++或Python中的OpenCV),但是代码中有一个错误…

    等高线
    列表将包含点列表。此点将参考原始图像。因此,这意味着,如果图1在,比如说,
    x=300,y=300,width=100,height=100
    那么当你得到你的子矩阵时,它会尝试在一个较小的图像中画出这些点。。。因此,当它试图在100x100图像中绘制点
    (300300)
    时,它将失败。。。可能会抛出一个错误或者根本不画任何东西

    解决方法是,对轮廓的每个点执行for循环并减去边界矩形的初始点(在我的示例中为
    (300300)

    作为,为什么会有一些垃圾被抽取。。。你从不初始化矩阵。在java中不确定,但是C++中你必须将它们设置为0。 我认为应该是这样的:

    Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1, new Scalar(0));
    
    我希望这有帮助:)

    编辑

    我想我以前没有解释清楚

    你的轮廓是一组点(x,y)。这些是表示原始图像中每个轮廓的点的坐标。此图像有一个大小,子矩阵的大小较小。这些点位于这个小图像边界之外

    您应该执行以下操作来修复它:

    for (int j = 0; j < contours[0].length; j++) {
        contours[0][j].x -= boundingrect.x;
        contours[0][j].y -= boundingrect.y;
    }
    
    for(int j=0;j
    然后你可以画出等高线,因为它们将在submat的边界上

    我认为在java中也可以直接减去opencv点:

    for (int j = 0; j < contours[0].length; j++) {
        contours[0][j] -= boundingrect.tl();
    }
    
    for(int j=0;j

    但在这种情况下,我不确定,因为我在C++中只尝试了


    boundingrect.tl()
    ->提供了我尝试过的新Mat(submatrix.rows()、submatrix.cols()、CvType.CV_8UC1、新标量(0))的矩形左上角点,但这不起作用。但是
    Mat.zeros()
    有效。我尝试了其他一些东西,这让我更加困惑。你能看到我问题底部的编辑吗?非常感谢你解决了我的问题。我无法完全理解最初的答案,但感谢您在编辑中澄清。在Java中,我必须将轮廓(其类型为
    MatOfPoint
    )转换为一个
    点数组
    ,然后我操作每个
    点的
    x
    y
    坐标
    点[]点ray=contours.get(0).toArray();对于(int pointIndex=0;pointIndex
    @Solace没问题,我的Java有点生疏,所以我尽我所能写了它。。。我很高兴它成功了:)