OpenCV image for black and white

I want the hand image to be black and white. Here is an example of input and the desired result: hand black and white

using a threshold does not give the desired result, because some colors inside the hand match the background color. How can I get the desired result?

+4
source share
2 answers

Adaptive threshold , find outlines , floodfill ?

Basically, an adaptive threshold turns your image into black and white, but takes a threshold level depending on local conditions around each pixel. Therefore, you should avoid the problem that you are facing with a normal threshold. In fact, I'm not sure why anyone would want to use a normal threshold.

If this does not work, an alternative approach is to find the largest outline in the image, draw it on a separate matrix, and then fill everything inside it with black. (Floodfill is similar to the bucket tool in MSPaint — it starts with a specific pixel and fills everything connected with that pixel, which has the same color with a different color of your choice.)

Perhaps the most reliable approach to various lighting conditions is to do it all in the sequence above. But you can only leave with a threshold or with a counter / fill.

By the way, maybe the hardest part is finding the outlines, because findContours returns arraylist / vector / whatever (platform dependent, I think) from MatOfPoints. MatOfPoint is a subclass of Mat, but you cannot draw it directly - you need to use drawContours. Here is some code for OpenCV4Android that I know works:
private Mat drawLargestContour(Mat input) { /** Allocates and returns a black matrix with the * largest contour of the input matrix drawn in white. */ List<MatOfPoint> contours = new ArrayList<MatOfPoint>(); Imgproc.findContours(input, contours, new Mat() /* hierarchy */, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); double maxArea = 0; int index = -1; for (MatOfPoint contour : contours) { // iterate over every contour in the list double area = Imgproc.contourArea(contour); if (area > maxArea) { maxArea = area; index = contours.indexOf(contour); } } if (index == -1) { Log.e(TAG, "Fatal error: no contours in the image!"); } Mat border = new Mat(input.rows(), input.cols(), CvType.CV_8UC1); // initialized to 0 (black) by default because it Java :) Imgproc.drawContours(border, contours, index, new Scalar(255)); // 255 = draw contours in white return border; } 
+5
source

Two quick things you can try:

After the threshold, you can:

  • Make a morphological closure,

  • or, the simplest: cv::findContours , hold the largest if it is more than one, then draw it with cv::fillConvexPoly and you will get this mask. ( fillConvexPoly fill the holes for you)

+1
source

Source: https://habr.com/ru/post/1435671/


All Articles