Ask Your Question

Revision history [back]

Not all convexity defects are being found

I wrote some code to detect convexity defects from a picture. I use opencv320 (tried 240 and got the exact same issue) and the code is Java.

http://i.imgur.com/3PdOhi3.jpg

And the result is always the same, it stops at a point and I don't understand why:

image description

As you see, I drew the bounding rectangle, the contour, the convex hull and when I want to calculate the convexity defects they are calculated only up until the ring finger starts.

public class Recognition {

    protected String whichHand = "left";
    public ArrayList<MatOfPoint> contours = new ArrayList<>();
    public MatOfPoint largestContour;
    public MatOfInt convexHull = new MatOfInt();
    protected Mat originalImage;
    public int largestContourIndex = -1;
    public MatOfInt4 convexityDefects = new MatOfInt4();
    public ArrayList<Defect> relevantDefects = new ArrayList<Defect>();

    public Recognition(Mat originalImage) {

        this.originalImage = originalImage;
    }


    public Recognition flip() {
        if (whichHand != "left")
            Core.flip(originalImage, originalImage, 1);

        return this;
    }

    public Recognition getContours() {
        Imgproc.findContours(originalImage, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));

        return this;
    }

    public Recognition getLargestContour() {


        double largestArea = 0;
        int contourNumber = contours.size();

        for (int i = 0; i < contourNumber; i++) {
            //double a=contourArea( hull[i],false);  //  surface
            double contourArea = Imgproc.contourArea(contours.get(i));
            if (contourArea > largestArea) {
                largestArea = contourArea;
                largestContourIndex = i;
            }

        }

        largestContour = contours.get(largestContourIndex);

        return this;
    }

    public Recognition getConvexHull() {

        Imgproc.convexHull(largestContour, convexHull);

        return this;
    }


    public Recognition getConvexityDefects() {

        Imgproc.convexityDefects(largestContour, convexHull, convexityDefects);

        int convexityDefectsList[] = convexityDefects.toArray();
        int convexityDefectsSize = convexityDefectsList.length;



        Point contourArray[] = largestContour.toArray();

        for (int d = 0; d < convexityDefectsSize; d += 4) {
            Point startPoint = contourArray[d];
            Point endPoint = contourArray[d + 1];
            Point depthPoint = contourArray[d + 2];

            double depth = convexityDefectsList[d + 3] / 256;

            Defect defect = new Defect();
            defect.startPoint = startPoint;
            defect.endPoint = endPoint;
            defect.depthPoint = depthPoint;
            defect.depth = depth;

            relevantDefects.add(defect);

        }


        return this;
    }

}

I think the problem is that I am getting way too few defects, around 20-30, but the Java function has really strange output when compared with the c++ one, it puts all the defects info in groups of 4 in the same array, really strange, so I've made an object to store it better.

I think I calculate the contour and hull properly, because you can see in the image that it's displayed fully.

This is the code I use, drawer is just another class that draws the specific points on the image, if you want I can provide it, too. I load the image, detect skin from the binary version, get the largest contour, get the hull and try to get the convexity defects.

Mat imagemat = Imgcodecs.imread("src/hsr/util/D1.png");
Mat skinMat = SkinDetector.detectSkin(imagemat);
Recognition recognition = new Recognition(skinMat);
Drawer drawer = new Drawer();
recognition.flip().getContours().getLargestContour();
Mat contourMat = Mat.zeros(skinMat.size(), CvType.CV_8UC3);
recognition.getConvexHull().getConvexityDefects();
drawer.showBiggestContour(contourMat,recognition.contours,recognition.largestContourIndex);
drawer.showHull(contourMat,recognition.convexHull,recognition.largestContour);
drawer.showRotatedBoundingRectangle(recognition.largestContour,contourMat);
drawer.drawDefects(contourMat,recognition.relevantDefects);
Imgcodecs.imwrite("asd.png",contourMat);

Not all convexity defects are being found

I wrote some code to detect convexity defects from a picture. I use opencv320 (tried 240 and got the exact same issue) and the code is Java.

http://i.imgur.com/3PdOhi3.jpgimage description

And the result is always the same, it stops at a point and I don't understand why:

image descriptionwhy: image description

As you see, I drew the bounding rectangle, the contour, the convex hull and when I want to calculate the convexity defects they are calculated only up until the ring finger starts.

public class Recognition {

    protected String whichHand = "left";
    public ArrayList<MatOfPoint> contours = new ArrayList<>();
    public MatOfPoint largestContour;
    public MatOfInt convexHull = new MatOfInt();
    protected Mat originalImage;
    public int largestContourIndex = -1;
    public MatOfInt4 convexityDefects = new MatOfInt4();
    public ArrayList<Defect> relevantDefects = new ArrayList<Defect>();

    public Recognition(Mat originalImage) {

        this.originalImage = originalImage;
    }


    public Recognition flip() {
        if (whichHand != "left")
            Core.flip(originalImage, originalImage, 1);

        return this;
    }

    public Recognition getContours() {
        Imgproc.findContours(originalImage, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));

        return this;
    }

    public Recognition getLargestContour() {


        double largestArea = 0;
        int contourNumber = contours.size();

        for (int i = 0; i < contourNumber; i++) {
            //double a=contourArea( hull[i],false);  //  surface
            double contourArea = Imgproc.contourArea(contours.get(i));
            if (contourArea > largestArea) {
                largestArea = contourArea;
                largestContourIndex = i;
            }

        }

        largestContour = contours.get(largestContourIndex);

        return this;
    }

    public Recognition getConvexHull() {

        Imgproc.convexHull(largestContour, convexHull);

        return this;
    }


    public Recognition getConvexityDefects() {

        Imgproc.convexityDefects(largestContour, convexHull, convexityDefects);

        int convexityDefectsList[] = convexityDefects.toArray();
        int convexityDefectsSize = convexityDefectsList.length;



        Point contourArray[] = largestContour.toArray();

        for (int d = 0; d < convexityDefectsSize; d += 4) {
            Point startPoint = contourArray[d];
            Point endPoint = contourArray[d + 1];
            Point depthPoint = contourArray[d + 2];

            double depth = convexityDefectsList[d + 3] / 256;

            Defect defect = new Defect();
            defect.startPoint = startPoint;
            defect.endPoint = endPoint;
            defect.depthPoint = depthPoint;
            defect.depth = depth;

            relevantDefects.add(defect);

        }


        return this;
    }

}

I think the problem is that I am getting way too few defects, around 20-30, but the Java function has really strange output when compared with the c++ one, it puts all the defects info in groups of 4 in the same array, really strange, so I've made an object to store it better.

I think I calculate the contour and hull properly, because you can see in the image that it's displayed fully.

This is the code I use, drawer is just another class that draws the specific points on the image, if you want I can provide it, too. I load the image, detect skin from the binary version, get the largest contour, get the hull and try to get the convexity defects.

Mat imagemat = Imgcodecs.imread("src/hsr/util/D1.png");
Mat skinMat = SkinDetector.detectSkin(imagemat);
Recognition recognition = new Recognition(skinMat);
Drawer drawer = new Drawer();
recognition.flip().getContours().getLargestContour();
Mat contourMat = Mat.zeros(skinMat.size(), CvType.CV_8UC3);
recognition.getConvexHull().getConvexityDefects();
drawer.showBiggestContour(contourMat,recognition.contours,recognition.largestContourIndex);
drawer.showHull(contourMat,recognition.convexHull,recognition.largestContour);
drawer.showRotatedBoundingRectangle(recognition.largestContour,contourMat);
drawer.drawDefects(contourMat,recognition.relevantDefects);
Imgcodecs.imwrite("asd.png",contourMat);

Not all convexity defects are being found

I wrote some code to detect convexity defects from a picture. I use opencv320 (tried 240 and got the exact same issue) and the code is Java.

image description

And the result is always the same, it stops at a point and I don't understand why: image description

As you see, I drew the bounding rectangle, the contour, the convex hull and when I want to calculate the convexity defects they are calculated only up until the ring finger starts.

public class Recognition {

    protected String whichHand = "left";
    public ArrayList<MatOfPoint> contours = new ArrayList<>();
    public MatOfPoint largestContour;
    public MatOfInt convexHull = new MatOfInt();
    protected Mat originalImage;
    public int largestContourIndex = -1;
    public MatOfInt4 convexityDefects = new MatOfInt4();
    public ArrayList<Defect> relevantDefects = new ArrayList<Defect>();

    public Recognition(Mat originalImage) {

        this.originalImage = originalImage;
    }


    public Recognition flip() {
        if (whichHand != "left")
            Core.flip(originalImage, originalImage, 1);

        return this;
    }

    public Recognition getContours() {
        Imgproc.findContours(originalImage, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));

        return this;
    }

    public Recognition getLargestContour() {


        double largestArea = 0;
        int contourNumber = contours.size();

        for (int i = 0; i < contourNumber; i++) {
            //double a=contourArea( hull[i],false);  //  surface
            double contourArea = Imgproc.contourArea(contours.get(i));
            if (contourArea > largestArea) {
                largestArea = contourArea;
                largestContourIndex = i;
            }

        }

        largestContour = contours.get(largestContourIndex);

        return this;
    }

    public Recognition getConvexHull() {

        Imgproc.convexHull(largestContour, convexHull);

        return this;
    }


    public Recognition getConvexityDefects() {

        Imgproc.convexityDefects(largestContour, convexHull, convexityDefects);

        int convexityDefectsList[] = convexityDefects.toArray();
        int convexityDefectsSize = convexityDefectsList.length;



        Point contourArray[] = largestContour.toArray();

        for (int d = 0; d < convexityDefectsSize; d += 4) {
            Point startPoint = contourArray[d];
            Point endPoint = contourArray[d + 1];
            Point depthPoint = contourArray[d + 2];

            double depth = convexityDefectsList[d + 3] / 256;

            Defect defect = new Defect();
            defect.startPoint = startPoint;
            defect.endPoint = endPoint;
            defect.depthPoint = depthPoint;
            defect.depth = depth;

            relevantDefects.add(defect);

        }


        return this;
    }

}

I think the problem is that I am getting way too few defects, around 20-30, but the Java function has really strange output when compared with the c++ one, it puts all the defects info in groups of 4 in the same array, really strange, so I've made an object to store it better.

I think I calculate the contour and hull properly, because you can see in the image that it's displayed fully.

This is the code I use, drawer is just another class that draws the specific points on the image, if you want I can provide it, too. I load the image, detect skin from the binary version, get the largest contour, get the hull and try to get the convexity defects.

Mat imagemat = Imgcodecs.imread("src/hsr/util/D1.png");
Mat skinMat = SkinDetector.detectSkin(imagemat);
Recognition recognition = new Recognition(skinMat);
Drawer drawer = new Drawer();
recognition.flip().getContours().getLargestContour();
Mat contourMat = Mat.zeros(skinMat.size(), CvType.CV_8UC3);
recognition.getConvexHull().getConvexityDefects();
drawer.showBiggestContour(contourMat,recognition.contours,recognition.largestContourIndex);
drawer.showHull(contourMat,recognition.convexHull,recognition.largestContour);
drawer.showRotatedBoundingRectangle(recognition.largestContour,contourMat);
drawer.drawDefects(contourMat,recognition.relevantDefects);
Imgcodecs.imwrite("asd.png",contourMat);

Skindetector class

public class SkinDetector {

    public static Mat detectSkin(Mat input) {


        //test
//        int Y_MIN = 0;
//        int Y_MAX = 255;
//        int Cr_MIN = 135;
//        int Cr_MAX = 180;
//        int Cb_MIN = 85;
//        int Cb_MAX = 135;


//        //bune
//        int Y_MIN = 0;
//        int Y_MAX = 255;
//
//        int Cr_MIN = 133;
//        int Cr_MAX = 173;
//
//        int Cb_MIN = 77;
//        int Cb_MAX = 127;

        // mai mult test
        int Y_MIN  = 0;
        int Y_MAX  = 255;
        int Cr_MIN = 133;
        int Cr_MAX = 180;
        int Cb_MIN = 77;
        int Cb_MAX = 135;

        Mat skin = new Mat();
        // RGB to YCrCb
        Imgproc.cvtColor(input, skin, Imgproc.COLOR_BGR2YCrCb);

        //input, filtru, output
        Core.inRange(skin, new Scalar(Y_MIN, Cr_MIN, Cb_MIN), new Scalar(Y_MAX, Cr_MAX, Cb_MAX), skin);

        //input, output, kernel(impar >1) 15
        Imgproc.medianBlur(skin, skin, 15);

        return skin;


    }

    public static float getSkinPercentage(Mat skinImage){

        int TotalNumberOfPixels = skinImage.rows() * skinImage.cols();
        int blackpixels = Core.countNonZero(skinImage);
        int ZeroPixels = TotalNumberOfPixels - blackpixels;
        float skinPerc = (float)ZeroPixels / (float)TotalNumberOfPixels * 100;

        return skinPerc;
    }

}

Not all convexity defects are being found

I wrote some code to detect convexity defects from a picture. I use opencv320 (tried 240 and got the exact same issue) and the code is Java.

image description

And the result is always the same, it stops at a point and I don't understand why: image description

As you see, I drew the bounding rectangle, the contour, the convex hull and when I want to calculate the convexity defects they are calculated only up until the ring finger starts.

public class Recognition {

    protected String whichHand = "left";
    public ArrayList<MatOfPoint> contours = new ArrayList<>();
    public MatOfPoint largestContour;
    public MatOfInt convexHull = new MatOfInt();
    protected Mat originalImage;
    public int largestContourIndex = -1;
    public MatOfInt4 convexityDefects = new MatOfInt4();
    public ArrayList<Defect> relevantDefects = new ArrayList<Defect>();

    public Recognition(Mat originalImage) {

        this.originalImage = originalImage;
    }


    public Recognition flip() {
        if (whichHand != "left")
            Core.flip(originalImage, originalImage, 1);

        return this;
    }

    public Recognition getContours() {
        Imgproc.findContours(originalImage, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));

        return this;
    }

    public Recognition getLargestContour() {


        double largestArea = 0;
        int contourNumber = contours.size();

        for (int i = 0; i < contourNumber; i++) {
            //double a=contourArea( hull[i],false);  //  surface
            double contourArea = Imgproc.contourArea(contours.get(i));
            if (contourArea > largestArea) {
                largestArea = contourArea;
                largestContourIndex = i;
            }

        }

        largestContour = contours.get(largestContourIndex);

        return this;
    }

    public Recognition getConvexHull() {

        Imgproc.convexHull(largestContour, convexHull);

        return this;
    }


    public Recognition getConvexityDefects() {

        Imgproc.convexityDefects(largestContour, convexHull, convexityDefects);

        int convexityDefectsList[] = convexityDefects.toArray();
        int convexityDefectsSize = convexityDefectsList.length;



        Point contourArray[] = largestContour.toArray();

        for (int d = 0; d < convexityDefectsSize; d += 4) {
            Point startPoint = contourArray[d];
            Point endPoint = contourArray[d + 1];
            Point depthPoint = contourArray[d + 2];

            double depth = convexityDefectsList[d + 3] / 256;

            Defect defect = new Defect();
            defect.startPoint = startPoint;
            defect.endPoint = endPoint;
            defect.depthPoint = depthPoint;
            defect.depth = depth;

            relevantDefects.add(defect);

        }


        return this;
    }

}

I think the problem is that I am getting way too few defects, around 20-30, but the Java function has really strange output when compared with the c++ one, it puts all the defects info in groups of 4 in the same array, really strange, so I've made an object to store it better.

I think I calculate the contour and hull properly, because you can see in the image that it's displayed fully.

This is the code I use, drawer is just another class that draws the specific points on the image, if you want I can provide it, too. I load the image, detect skin from the binary version, get the largest contour, get the hull and try to get the convexity defects.

Mat imagemat = Imgcodecs.imread("src/hsr/util/D1.png");
Mat skinMat = SkinDetector.detectSkin(imagemat);
Recognition recognition = new Recognition(skinMat);
Drawer drawer = new Drawer();
recognition.flip().getContours().getLargestContour();
Mat contourMat = Mat.zeros(skinMat.size(), CvType.CV_8UC3);
recognition.getConvexHull().getConvexityDefects();
drawer.showBiggestContour(contourMat,recognition.contours,recognition.largestContourIndex);
drawer.showHull(contourMat,recognition.convexHull,recognition.largestContour);
drawer.showRotatedBoundingRectangle(recognition.largestContour,contourMat);
drawer.drawDefects(contourMat,recognition.relevantDefects);
Imgcodecs.imwrite("asd.png",contourMat);

Skindetector class

public class SkinDetector {

    public static Mat detectSkin(Mat input) {


        //test
//        int Y_MIN = 0;
//        int Y_MAX = 255;
//        int Cr_MIN = 135;
//        int Cr_MAX = 180;
//        int Cb_MIN = 85;
//        int Cb_MAX = 135;


//        //bune
//        int Y_MIN = 0;
//        int Y_MAX = 255;
//
//        int Cr_MIN = 133;
//        int Cr_MAX = 173;
//
//        int Cb_MIN = 77;
//        int Cb_MAX = 127;

        // mai mult test
        int Y_MIN  = 0;
        int Y_MAX  = 255;
        int Cr_MIN = 133;
        int Cr_MAX = 180;
        int Cb_MIN = 77;
        int Cb_MAX = 135;

        Mat skin = new Mat();
        // RGB to YCrCb
        Imgproc.cvtColor(input, skin, Imgproc.COLOR_BGR2YCrCb);

        //input, filtru, output
        Core.inRange(skin, new Scalar(Y_MIN, Cr_MIN, Cb_MIN), new Scalar(Y_MAX, Cr_MAX, Cb_MAX), skin);

        //input, output, kernel(impar >1) 15
        Imgproc.medianBlur(skin, skin, 15);

        return skin;


    }

    public static float getSkinPercentage(Mat skinImage){

        int TotalNumberOfPixels = skinImage.rows() * skinImage.cols();
        int blackpixels = Core.countNonZero(skinImage);
        int ZeroPixels = TotalNumberOfPixels - blackpixels;
        float skinPerc = (float)ZeroPixels / (float)TotalNumberOfPixels * 100;

        return skinPerc;
    }

}

Drawer

public class Drawer {

    public void showAllContours(Mat image, ArrayList<MatOfPoint> contours) {

        int contoursNumber = contours.size();
        Random random = new Random(12345);

        for (int i = 0; i < contoursNumber; i++) {
            Scalar color = new Scalar(random.nextInt(256), random.nextInt(256), random.nextInt(256));
            Imgproc.drawContours(image, contours, i, color, 1, 8, new Mat(), 0, new Point());
        }
    }

    public void showBiggestContour(Mat image, ArrayList<MatOfPoint> contours, int index) {
        Imgproc.drawContours(image, contours, index, new Scalar(255, 204, 51), 1, 8, new Mat(), 0, new Point());
    }


    public void showHull(Mat image, MatOfInt hull, MatOfPoint contour) {


        List<Point[]> hullpoints = new ArrayList<Point[]>();

        Point[] points = new Point[hull.rows()];

        // Loop over all points that need to be hulled in current contour
        for (int j = 0; j < hull.rows(); j++) {
            int index = (int) hull.get(j, 0)[0];
            points[j] = new Point(contour.get(index, 0)[0], contour.get(index, 0)[1]);
        }

        hullpoints.add(points);

        List<MatOfPoint> hulls = new ArrayList<MatOfPoint>();
        MatOfPoint mop = new MatOfPoint();
        mop.fromArray(hullpoints.get(0));
        hulls.add(mop);

        Imgproc.drawContours(image, hulls, 0, new Scalar(255, 0, 255), 1, 8, new Mat(), 0, new Point());
    }

    public void showBoundingRectangle(MatOfPoint largestContour, Mat image) {
        MatOfPoint2f approxCurve = new MatOfPoint2f();
        //Convert contour from MatOfPoint to MatOfPoint2f
        MatOfPoint2f contour2f = new MatOfPoint2f(largestContour.toArray());
        //Processing on mMOP2f1 which is in type MatOfPoint2f
        double approxDistance = Imgproc.arcLength(contour2f, true) * 0.02;
        Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);

        //Convert back to MatOfPoint
        MatOfPoint points = new MatOfPoint(approxCurve.toArray());

        // Get bounding rect of contour
        Rect rect = Imgproc.boundingRect(points);

        Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 0, 0, 255), 1);
    }

    public void showRotatedBoundingRectangle(MatOfPoint largestContour, Mat image) {
        MatOfPoint2f contour2f = new MatOfPoint2f(largestContour.toArray());
        RotatedRect rectangle = Imgproc.minAreaRect(contour2f);

        Point[] points = new Point[4];
        rectangle.points(points);

        for (int j = 0; j < 4; j++) {
            Imgproc.line(image, points[j], points[(j + 1) % 4], new Scalar(255, 255, 0), 1);
        }
    }

    public void drawDefects(Mat image, ArrayList<Defect> defects) {

        for (int i = 0; i < defects.size(); i++) {

            Defect defect = defects.get(i);

            Imgproc.line(image, defect.startPoint, defect.depthPoint, new Scalar(0, 255, 0), 2);
            Imgproc.line(image, defect.endPoint, defect.depthPoint, new Scalar(0, 255, 0), 2);
            Imgproc.circle(image, defect.startPoint, 4, new Scalar(100, 0, 255), 2);
            //Imgproc.circle(image, ptEnd, 4, new Scalar(100, 0, 255), 2);         //cercuri pt pct de sfarsit
        }



        //cv::putText(fingers, to_string(d), ptStart, FONT_HERSHEY_SCRIPT_SIMPLEX, 2, Scalar::all(255), 3,8); //numere


    }
}

Not all convexity defects are being found

I wrote some code to detect convexity defects from a picture. I use opencv320 (tried 240 and got the exact same issue) and the code is Java.

image description

And the result is always the same, it stops at a point and I don't understand why: image description

As you see, I drew the bounding rectangle, the contour, the convex hull and when I want to calculate the convexity defects they are calculated only up until the ring finger starts.

public class Recognition {

    protected String whichHand = "left";
    public ArrayList<MatOfPoint> contours = new ArrayList<>();
    public MatOfPoint largestContour;
    public MatOfInt convexHull = new MatOfInt();
    protected Mat originalImage;
    public int largestContourIndex = -1;
    public MatOfInt4 convexityDefects = new MatOfInt4();
    public ArrayList<Defect> relevantDefects = new ArrayList<Defect>();

    public Recognition(Mat originalImage) {

        this.originalImage = originalImage;
    }


    public Recognition flip() {
        if (whichHand != "left")
            Core.flip(originalImage, originalImage, 1);

        return this;
    }

    public Recognition getContours() {
        Imgproc.findContours(originalImage, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));

        return this;
    }

    public Recognition getLargestContour() {


        double largestArea = 0;
        int contourNumber = contours.size();

        for (int i = 0; i < contourNumber; i++) {
            //double a=contourArea( hull[i],false);  //  surface
            double contourArea = Imgproc.contourArea(contours.get(i));
            if (contourArea > largestArea) {
                largestArea = contourArea;
                largestContourIndex = i;
            }

        }

        largestContour = contours.get(largestContourIndex);

        return this;
    }

    public Recognition getConvexHull() {

        Imgproc.convexHull(largestContour, convexHull);

        return this;
    }


    public Recognition getConvexityDefects() {

        Imgproc.convexityDefects(largestContour, convexHull, convexityDefects);

        int convexityDefectsList[] = convexityDefects.toArray();
        int convexityDefectsSize = convexityDefectsList.length;



        Point contourArray[] = largestContour.toArray();

        for (int d = 0; d < convexityDefectsSize; d += 4) {
            Point startPoint = contourArray[d];
            Point endPoint = contourArray[d + 1];
            Point depthPoint = contourArray[d + 2];

            double depth = convexityDefectsList[d + 3] / 256;

            Defect defect = new Defect();
            defect.startPoint = startPoint;
            defect.endPoint = endPoint;
            defect.depthPoint = depthPoint;
            defect.depth = depth;

            relevantDefects.add(defect);

        }


        return this;
    }

}

I think the problem is that I am getting way too few defects, around 20-30, but the Java function has really strange output when compared with the c++ one, it puts all the defects info in groups of 4 in the same array, really strange, so I've made an object to store it better.

I think I calculate the contour and hull properly, because you can see in the image that it's displayed fully.

This is the code I use, drawer is just another class that draws the specific points on the image, if you want I can provide it, too. I load the image, detect skin from the binary version, get the largest contour, get the hull and try to get the convexity defects.

Mat imagemat = Imgcodecs.imread("src/hsr/util/D1.png");
Mat skinMat = SkinDetector.detectSkin(imagemat);
Recognition recognition = new Recognition(skinMat);
Drawer drawer = new Drawer();
recognition.flip().getContours().getLargestContour();
Mat contourMat = Mat.zeros(skinMat.size(), CvType.CV_8UC3);
recognition.getConvexHull().getConvexityDefects();
drawer.showBiggestContour(contourMat,recognition.contours,recognition.largestContourIndex);
drawer.showHull(contourMat,recognition.convexHull,recognition.largestContour);
drawer.showRotatedBoundingRectangle(recognition.largestContour,contourMat);
drawer.drawDefects(contourMat,recognition.relevantDefects);
Imgcodecs.imwrite("asd.png",contourMat);

Skindetector class

public class SkinDetector {

    public static Mat detectSkin(Mat input) {


        //test
//        int Y_MIN = 0;
//        int Y_MAX = 255;
//        int Cr_MIN = 135;
//        int Cr_MAX = 180;
//        int Cb_MIN = 85;
//        int Cb_MAX = 135;


//        //bune
//        int Y_MIN = 0;
//        int Y_MAX = 255;
//
//        int Cr_MIN = 133;
//        int Cr_MAX = 173;
//
//        int Cb_MIN = 77;
//        int Cb_MAX = 127;

        // mai mult test
        int Y_MIN  = 0;
        int Y_MAX  = 255;
        int Cr_MIN = 133;
        int Cr_MAX = 180;
        int Cb_MIN = 77;
        int Cb_MAX = 135;

        Mat skin = new Mat();
        // RGB to YCrCb
        Imgproc.cvtColor(input, skin, Imgproc.COLOR_BGR2YCrCb);

        //input, filtru, output
        Core.inRange(skin, new Scalar(Y_MIN, Cr_MIN, Cb_MIN), new Scalar(Y_MAX, Cr_MAX, Cb_MAX), skin);

        //input, output, kernel(impar >1) 15
        Imgproc.medianBlur(skin, skin, 15);

        return skin;


    }

    public static float getSkinPercentage(Mat skinImage){

        int TotalNumberOfPixels = skinImage.rows() * skinImage.cols();
        int blackpixels = Core.countNonZero(skinImage);
        int ZeroPixels = TotalNumberOfPixels - blackpixels;
        float skinPerc = (float)ZeroPixels / (float)TotalNumberOfPixels * 100;

        return skinPerc;
    }

}

Drawer

public class Drawer {

    public void showAllContours(Mat image, ArrayList<MatOfPoint> contours) {

        int contoursNumber = contours.size();
        Random random = new Random(12345);

        for (int i = 0; i < contoursNumber; i++) {
            Scalar color = new Scalar(random.nextInt(256), random.nextInt(256), random.nextInt(256));
            Imgproc.drawContours(image, contours, i, color, 1, 8, new Mat(), 0, new Point());
        }
    }

    public void showBiggestContour(Mat image, ArrayList<MatOfPoint> contours, int index) {
        Imgproc.drawContours(image, contours, index, new Scalar(255, 204, 51), 1, 8, new Mat(), 0, new Point());
    }


    public void showHull(Mat image, MatOfInt hull, MatOfPoint contour) {


        List<Point[]> hullpoints = new ArrayList<Point[]>();

        Point[] points = new Point[hull.rows()];

        // Loop over all points that need to be hulled in current contour
        for (int j = 0; j < hull.rows(); j++) {
            int index = (int) hull.get(j, 0)[0];
            points[j] = new Point(contour.get(index, 0)[0], contour.get(index, 0)[1]);
        }

        hullpoints.add(points);

        List<MatOfPoint> hulls = new ArrayList<MatOfPoint>();
        MatOfPoint mop = new MatOfPoint();
        mop.fromArray(hullpoints.get(0));
        hulls.add(mop);

        Imgproc.drawContours(image, hulls, 0, new Scalar(255, 0, 255), 1, 8, new Mat(), 0, new Point());
    }

    public void showBoundingRectangle(MatOfPoint largestContour, Mat image) {
        MatOfPoint2f approxCurve = new MatOfPoint2f();
        //Convert contour from MatOfPoint to MatOfPoint2f
        MatOfPoint2f contour2f = new MatOfPoint2f(largestContour.toArray());
        //Processing on mMOP2f1 which is in type MatOfPoint2f
        double approxDistance = Imgproc.arcLength(contour2f, true) * 0.02;
        Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);

        //Convert back to MatOfPoint
        MatOfPoint points = new MatOfPoint(approxCurve.toArray());

        // Get bounding rect of contour
        Rect rect = Imgproc.boundingRect(points);

        Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 0, 0, 255), 1);
    }

    public void showRotatedBoundingRectangle(MatOfPoint largestContour, Mat image) {
        MatOfPoint2f contour2f = new MatOfPoint2f(largestContour.toArray());
        RotatedRect rectangle = Imgproc.minAreaRect(contour2f);

        Point[] points = new Point[4];
        rectangle.points(points);

        for (int j = 0; j < 4; j++) {
            Imgproc.line(image, points[j], points[(j + 1) % 4], new Scalar(255, 255, 0), 1);
        }
    }

    public void drawDefects(Mat image, ArrayList<Defect> defects) {

        for (int i = 0; i < defects.size(); i++) {

            Defect defect = defects.get(i);

            Imgproc.line(image, defect.startPoint, defect.depthPoint, new Scalar(0, 255, 0), 2);
            Imgproc.line(image, defect.endPoint, defect.depthPoint, new Scalar(0, 255, 0), 2);
            Imgproc.circle(image, defect.startPoint, 4, new Scalar(100, 0, 255), 2);
            //Imgproc.circle(image, ptEnd, 4, new Scalar(100, 0, 255), 2);         //cercuri pt pct de sfarsit
        }



        //cv::putText(fingers, to_string(d), ptStart, FONT_HERSHEY_SCRIPT_SIMPLEX, 2, Scalar::all(255), 3,8); //numere


    }
}