Java Android Opencv 2.3 上的凸壳
Posted
技术标签:
【中文标题】Java Android Opencv 2.3 上的凸壳【英文标题】:Convex Hull on Java Android Opencv 2.3 【发布时间】:2013-07-09 08:17:23 【问题描述】:请帮帮我,
我在 android 上遇到了 Convex Hull 的问题。我使用 Java 和 OpenCV 2.3。
在使用 Java 之前,我使用 Visual Studio 2008 在 C++ 上创建了它。
此代码可以在 C++ 上成功运行。
现在,我想在 Android 上将它从 C++ 转换为 Java。当我在 SDK Android 模拟器上运行它时,我发现了类似“强制关闭”的错误。
这是我的 C++ 代码:
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
drawing = Mat::zeros( canny_output.size(), CV_64F );
/// Find the convex hull object for each contour
vector<vector<Point> > hull ( contours.size() );
for( int i = 0; i < contours.size(); i++ )
convexHull( Mat(contours[i]), hull[i], false );
for(size_t i = 0; i < contours.size(); i++)
drawContours( drawing, hull, i, Scalar(255, 255, 255), CV_FILLED ); // FILL WHITE COLOR
这是我在 Android 上的代码:
Mat hierarchy = new Mat(img_canny.rows(),img_canny.cols(),CvType.CV_8UC1,new Scalar(0));
List<Mat> contours =new ArrayList<Mat>();
List<Mat> hull = new ArrayList<Mat>(contours.size());
drawing = Mat.zeros(img_canny.size(), im_gray);
Imgproc.findContours(img_dilasi, contours, hierarchy,Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
for(int i=0; i<contours.size(); i++)
Imgproc.convexHull(contours.get(i), hull.get(i), false);
for(int i=0; i<contours.size(); i++)
Imgproc.drawContours(drawing, hull, i, new Scalar(255.0, 255.0, 255.0), 5);
为了您的信息,我在我的代码中对 Convex Hull 做了一些修改。 我在轮廓内填充颜色。
谁能帮我解决我的问题?
非常感谢您的帮助。
【问题讨论】:
很难说是什么导致了您的问题。你得到的具体错误是什么?有没有相关的日志输出? 当我在 SDK Android Simulator 上运行它时,出现 windows 错误,“应用程序意外停止”,我被告知单击“强制关闭”停止。当我检查 Log Cat 错误 Eclipse 时,我发现进程停止在这一行“Imgproc.convexHull(contours.get(i), hull.get(i), false);”我不知道为什么该过程在那条线上停止。你不能帮我解释一下吗? 我想我在声明“hull”变量时犯了一个错误。但是,我不知道如何解决这个问题。我想我已经根据适用的规定声明了该变量。你的意见呢?你认为我的代码中变量“hull”的声明不正确吗? 发布的答案是否解决了您的问题?如果是这样,你会accept 其中之一吗?如果没有,请发表评论说明我们可以改进的地方。 【参考方案1】:没有代表添加评论,只是想说上面的两个答案帮助我让 Imgproc.convexHull() 像这样 (2.4.8) 为我的用例工作:
MatOfPoint mopIn = ...
MatOfInt hull = new MatOfInt();
Imgproc.convexHull(mopIn, hull, false);
MatOfPoint mopOut = new MatOfPoint();
mopOut.create((int)hull.size().height,1,CvType.CV_32SC2);
for(int i = 0; i < hull.size().height ; i++)
int index = (int)hull.get(i, 0)[0];
double[] point = new double[]
mopIn.get(index, 0)[0], mopIn.get(index, 0)[1]
;
mopOut.put(i, 0, point);
// do something interesting with mopOut
【讨论】:
【参考方案2】:此代码在我的应用程序中运行良好。在我的例子中,我有多个轮廓可以使用,所以你会注意到很多列表,但如果你只有一个轮廓,只需调整它以使其在没有 .get(i) 迭代的情况下工作。
这个帖子更简单地解释了这个过程。
android java opencv 2.4 convexhull convexdefect
// Find the convex hull
List<MatOfInt> hull = new ArrayList<MatOfInt>();
for(int i=0; i < contours.size(); i++)
hull.add(new MatOfInt());
for(int i=0; i < contours.size(); i++)
Imgproc.convexHull(contours.get(i), hull.get(i));
// Convert MatOfInt to MatOfPoint for drawing convex hull
// Loop over all contours
List<Point[]> hullpoints = new ArrayList<Point[]>();
for(int i=0; i < hull.size(); i++)
Point[] points = new Point[hull.get(i).rows()];
// Loop over all points that need to be hulled in current contour
for(int j=0; j < hull.get(i).rows(); j++)
int index = (int)hull.get(i).get(j, 0)[0];
points[j] = new Point(contours.get(i).get(index, 0)[0], contours.get(i).get(index, 0)[1]);
hullpoints.add(points);
// Convert Point arrays into MatOfPoint
List<MatOfPoint> hullmop = new ArrayList<MatOfPoint>();
for(int i=0; i < hullpoints.size(); i++)
MatOfPoint mop = new MatOfPoint();
mop.fromArray(hullpoints.get(i));
hullmop.add(mop);
// Draw contours + hull results
Mat overlay = new Mat(binaryImage.size(), CvType.CV_8UC3);
Scalar color = new Scalar(0, 255, 0); // Green
for(int i=0; i < contours.size(); i++)
Imgproc.drawContours(overlay, contours, i, color);
Imgproc.drawContours(overlay, hullmop, i, color);
【讨论】:
【参考方案3】:Java 示例 (OpenCV 2.4.11)
hullMat
包含gray
的子垫,由convexHull
方法标识。 您可能想要过滤您真正需要的轮廓,例如根据它们的面积。
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
MatOfInt4 hierarchy = new MatOfInt4();
MatOfInt hull = new MatOfInt();
void foo(Mat gray)
Imgproc.findContours(gray, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++)
Imgproc.convexHull(contours.get(i), hull);
MatOfPoint hullContour = hull2Points(hull, contours.get(i));
Rect box = Imgproc.boundingRect(hullContour);
Mat hullMat = new Mat(gray, box);
...
MatOfPoint hull2Points(MatOfInt hull, MatOfPoint contour)
List<Integer> indexes = hull.toList();
List<Point> points = new ArrayList<>();
MatOfPoint point= new MatOfPoint();
for(Integer index:indexes)
points.add(contour.toList().get(index));
point.fromList(points);
return point;
【讨论】:
【参考方案4】:查看findContours()
和convexHull()
的文档,您似乎错误地声明了变量contours
和hull
。
尝试将声明更改为:
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<MatOfInt> hull = new ArrayList<MatOfInt>();
然后,在您调用convexHull()
之后,hull
包含contours
中构成凸包的点的索引。为了用drawContours()
绘制点,您需要填充一个仅包含凸包上的点的新MatOfPoint
,并将其传递给drawContours()
。我把这个留给你做练习。
【讨论】:
【参考方案5】:为了补充 Aurelius 所说的,在您的 C++ 实现中,您使用了点向量,因此外壳矩阵包含实际的凸点:
“在第一种情况下[索引的整数向量],外壳元素是原始数组中凸包点的基于 0 的索引(因为凸包点的集合是原始点集的子集)。在第二种情况下[点向量],外壳元素是凸包点本身。” - convexHull
这就是你能打电话的原因
drawContours( drawing, hull, i, Scalar(255, 255, 255), CV_FILLED );
在您的 android 版本中,船体输出只是一个索引数组,对应于原始 contours.get(i) 矩阵中的点。因此,您需要查找原始矩阵中的凸点。这是一个非常粗略的想法:
MatOfInt hull = new MatOfInt();
MatOfPoint tempContour = contours.get(i);
Imgproc.convexHull(tempContour, hull, false); // O(N*Log(N))
//System.out.println("hull size: " + hull.size() + " x" + hull.get(0,0).length);
//System.out.println("Contour matrix size: " + tempContour.size() + " x" + tempContour.get(0,0).length);
int index = (int) hull.get(((int) hull.size().height)-1, 0)[0];
Point pt, pt0 = new Point(tempContour.get(index, 0)[0], tempContour.get(index, 0)[1]);
for(int j = 0; j < hull.size().height -1 ; j++)
index = (int) hull.get(j, 0)[0];
pt = new Point(tempContour.get(index, 0)[0], tempContour.get(index, 0)[1]);
Core.line(frame, pt0, pt, new Scalar(255, 0, 100), 8);
pt0 = pt;
【讨论】:
【参考方案6】:使用这个fillconvexPoly
for( int i = 0; i < contours.size(); i++ )
Imgproc.fillConvexPoly(image_2, point,new Scalar(255, 255, 255));
【讨论】:
以上是关于Java Android Opencv 2.3 上的凸壳的主要内容,如果未能解决你的问题,请参考以下文章
C++ OpenCV 2.3 中缺少 MoveWindow()