Выпуклая оболочка на Java Android Opencv 2.3
Пожалуйста, помогите мне,
У меня проблема с выпуклой оболочкой на Android. Я использую Java и OpenCV 2.3.
Прежде чем я сделал это на Java, я сделал это на C++ с Visual Studio 2008.
Этот код может успешно работать на C++.
Теперь я хочу преобразовать его из C++ в Java на Android. И я обнаружил ошибку типа "принудительное закрытие", когда я запускаю ее на симуляторе Android SDK.
Это мой код на 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 в своем коде. Я заливаю цвет внутри контура.
Кто-нибудь может помочь мне решить мою проблему?
Я очень благодарен за вашу помощь.
6 ответов
У меня нет представителя для добавления комментария, просто хочу сказать, что два приведенных выше ответа помогли мне заставить 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
Этот код хорошо работает в моем приложении. В моем случае у меня было несколько контуров для работы, поэтому вы заметите много списков, но если у вас есть только один контур, просто настройте его так, чтобы он работал без итераций.get(i).
Этот поток объясняет процесс более просто.
Android Java OpenCV 2,4 выпуклая оболочка выпуклая дефект
// 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);
}
Пример на 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;
}
Глядя на документацию findContours()
а также convexHull()
Похоже, что вы объявили переменные contours
а также hull
неправильно.
Попробуйте изменить объявления на:
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<MatOfInt> hull = new ArrayList<MatOfInt>();
Потом после звонка convexHull()
, hull
содержит индексы точек в contours
которые составляют выпуклый корпус. Для того, чтобы нарисовать точки с drawContours()
, вам нужно будет заполнить новый MatOfPoint
содержащий только точки на выпуклой оболочке, и передать это drawContours()
, Я оставляю это как упражнение для вас.
Чтобы добавить то, что сказал Аврелий, в вашей реализации C++ вы использовали вектор точек, поэтому матрица корпуса содержит реальные выпуклые точки:
"В первом случае [целочисленный вектор индексов] элементы оболочки являются индексами на основе 0 выпуклых точек корпуса в исходном массиве (поскольку множество выпуклых точек корпуса является подмножеством исходного набора точек). Во втором случай [вектор точек], элементы корпуса сами являются выпуклыми точками корпуса ". - выпуклый корпус
Вот почему вы смогли позвонить
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;
}
Использовать этот fillconvexPoly
for(;;){
Imgproc.fillConvexPoly(image_2, point,new Scalar(255, 255, 255));
}