为什么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有点生疏,所以我尽我所能写了它。。。我很高兴它成功了:)