Как обнаружить длинные края стены, чтобы подготовить маску и перекрасить
Основная идея состоит в том, чтобы позволить пользователю перекрашивать к определенному выбору пользователя на основе стены.
В настоящее время я реализовал эту функцию с помощью cvFloodFill
(помогает подготовить изображение маски), которая может помочь мне изменить относительное значение HSV
для стены, чтобы я мог сохранить края. но проблема с этим решением заключается в том, что оно работает на цвете, и все стены перекрашиваются вместо одной стены, выбранной пользователем.
Я также пробовал canny edge detection, но он просто способен обнаружить край,но не способен преобразовать его в область.
Пожалуйста, найдите ниже код, который я в настоящее время использую для перерисовки функции
-
Подготовить маску
cvFloodFill(mask, new CvPoint(295, 75), new CvScalar(255, 255, 255,0), cvScalarAll(1), cvScalarAll(1), null, 4, null);
-
Разделенный канал
cvSplit(hsvImage, hChannel, sChannel, vChannel, null);
-
Изменить цвет
cvAddS(vChannel, new CvScalar(255*(0.76-0.40),0,0,0), vChannel, mask);
Как мы можем обнаружить края и соответствующую область на изображении.
Я ищу решение, которое может быть отличным от opencv
, но должно быть возможно для iPhone и android
Edit
Я могу добиться некоторого результата, как показано ниже, используя следующие шаги
cvCvtColor(image, gray, CV_BGR2GRAY);
cvSmooth(gray,smooth,CV_GAUSSIAN,7,7,0,0);
cvCanny(smooth, canny, 10, 250, 5);
Есть две проблемы с этим выходом, не знаю, как их решить 1. близко по краям 2. удалить мелкие края
5 ответов:
Я думаю, что у меня есть решение для вас! Существует образец файла под названием watershed.cpp в OpenCV, просто запустите его, и вы получите такой результат:
Вы можете заставить пользователя рисовать на своем экране, чтобы различать каждую стену. Затем, если вы хотите что-то более точное, вы можете очертить области (не касаясь других линий) следующим образом:
И ТАДА! :
С небольшой работой вы можете сделать его удобным для пользователя (отмена последней строки, подключение территории и т. д...)
Надеюсь, это поможет!
Вы можете попробовать что-то вроде:
Mat imageOut = Mat::zeros(imageIn.rows, imageIn.cols, CV_8UC3); vector<vector<Point> > contours; vector<Vec4i> hierarchy; findContours( imageIn, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); for( int idx = 0; idx >= 0; idx = hierarchy[idx][0] ) { Scalar color( rand()&255, rand()&255, rand()&255 ); drawContours( imageOut, contours, idx, color, CV_FILLED, 8, hierarchy ); }
Он должен рисовать стены в разных цветах. Если это работает, то это означает, что в" иерархии " каждая стена идентифицируется как контур, вам нужно будет узнать, какой из них пользователь выбрал на своем сенсорном экране и выполнить обработку настройки цвета.
Возможно, вам придется изменить различные параметры в "findContours" link. Вам также нужно будет сгладить входное изображение перед обнаружением контура, чтобы избежать раздражения от детали или текстуры.
Надеюсь, это поможет, Томас
Я думаю, что вы можете использовать алгоритм
Canny Edge Detection
, чтобы найти разницу ребер. Некоторые ссылкиЯ надеюсь, что это может помочь вам. Спасибо.
Вот некоторый код OpenCV4Android, чтобы найти самый большой контур в
Mat
под названиемimage
, который, как мы предположим, находится в цветовом пространстве RGBA. Чтобы найти контуры, сначала необходимо порогировать или бинаризовать изображение (преобразовать в черно-белое). Использование гауссовского размытия на изображении перед пороговым значением уменьшает количество создаваемых мелких контуров. Параметры размера для размытия и порога должны быть нечетными числами; вы можете поиграть, чтобы найти, какое значение дает наилучшие результаты (здесь, Я использовал 7 для обоих).List<MatOfPoint> contours = new ArrayList<MatOfPoint>(); Mat BW = new Mat(); Mat hierarchy = new Mat(); MatOfPoint largestContour; Imgproc.cvtColor(image, image, Imgproc.COLOR_RGBA2GRAY); // convert to grayscale Imgproc.GaussianBlur(image, BW, new Size(7,7), 0); Imgproc.adaptiveThreshold(BW, BW, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 7, 2.0); Imgproc.findContours(BW, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); double maxArea = 0; for (MatOfPoint contour : contours) { double area = Imgproc.contourArea(contour); if (area > maxArea) { maxArea = area; largestContour = contour; } }
Есть две проблемы с этим выходом, не знаю, как их решить 1. вблизи по краям 2. удалить мелкие края
Вы можете использовать морфологические операции, чтобы закрыть края. Ищите операторы расширения и закрытия.
Вы можете удалить небольшие края, сделав надпись. Подсчитайте количество пикселей в каждой области (Соединенных белых пикселей). Удалите любую область с числом пикселей меньше некоторого порогового значения. Я не использую opencv, но большинство библиотеки имеют функцию маркировки, которая создает изображение, где каждому набору соприкасающихся пикселей одного цвета присваивается уникальный цвет в выходном изображении.