Я хочу, чтобы изображение руки было черно-белым. Вот пример ввода и желаемого результата: рука черно-белая http://imageshack.us/a/img853/4017/handtobw.jpg
использование порога не дает желаемого результата, потому что некоторые цвета внутри руки совпадают с цветом фона. Как я могу получить желаемый результат?
Адаптивный порог, найти контуры, заливка?
По сути, адаптивный порог превращает ваше изображение в черно-белое, но принимает пороговый уровень на основе местных условий вокруг каждого пикселя — таким образом, вы должны избегать проблем, с которыми вы сталкиваетесь при использовании обычного порога. На самом деле, я не уверен, почему кто-то захочет использовать нормальный порог.
Если это не сработает, альтернативный подход — найти самый большой контур на изображении, нарисовать его на отдельной матрице и затем залить все внутри него черным. (Floodfill похож на инструмент bucket в MSPaint — он начинается с определенного пикселя и заполняет все, что связано с этим пикселем, того же цвета другим цветом по вашему выбору.)
Возможно, самый надежный подход к различным условиям освещения — это делать их все в порядке сверху. Но вы можете быть в состоянии обойтись только с порогом или счетчиками / заливкой.
Кстати, пожалуй, самая сложная часть — это на самом деле найти контуры, потому что findContours возвращает массив / вектор / что угодно (зависит от платформы, которую я думаю) от MatOfPoints. MatOfPoint является подклассом Mat, но вы не можете нарисовать его напрямую — вам нужно использовать drawContours. Вот код для OpenCV4Android, который, как я знаю, работает:
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's Java :)
Imgproc.drawContours(border, contours, index, new Scalar(255)); // 255 = draw contours in white
return border;
}
Две быстрые вещи, которые вы можете попробовать:
После порога вы можете:
Сделать морфологическое закрытие,
или, самое простое: cv::findContours
оставьте наибольшее, если оно больше одного, затем нарисуйте его, используя cv::fillConvexPoly
и вы получите эту маску. (fillConvexPoly
буду заполнять дыры для вас)