Выпуклая оболочка на 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));
    }
Другие вопросы по тегам