Как обнаружить длинные края стены, чтобы подготовить маску и перекрасить
Основная идея заключается в том, чтобы позволить пользователю перекрашивать конкретный пользовательский выбор на стене.
В настоящее время я реализовал эту функцию с помощью cvFloodFill
(помогает подготовить изображение маски), что может помочь мне изменить относительное значение HSV
для стены, чтобы я мог удерживать края. но проблема с этим решением заключается в том, что он работает с цветом, и все стены перекрашиваются вместо отдельной стены, выбранной пользователем.
Я также пробовал обнаружение canny edge, но он просто смог обнаружить край, но не смог преобразовать его в область.
Ниже приведен код, который я использую для функции repaint
-
Подготовить маску
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.
![Sample image]()
Edit
Я могу добиться некоторого результата, как показано ниже, используя следующие шаги.
cvCvtColor(image, gray, CV_BGR2GRAY);
cvSmooth(gray,smooth,CV_GAUSSIAN,7,7,0,0);
cvCanny(smooth, canny, 10, 250, 5);
есть две проблемы с этим выходом, не уверены, как их разрешить
1. близко к краям
2. Удалите небольшие края.
![enter image description here]()
Ответы
Ответ 1
Думаю, у меня может быть решение для вас!
В OpenCV есть образец файла, называемый waterhed.cpp, просто запустите его, и вы получите следующий результат:
![Watershed with only short line keypoints]()
Вы можете заставить пользователя нарисовать его экран, чтобы различать каждую стену.
Затем, если вам нужно что-то более точное, вы можете очертить области (не касаясь других строк) следующим образом:
![Better outline]()
И ТАДА!:
![Pretty good result ;)]()
С небольшой работой вы можете сделать ее удобной (отменить последнюю строку, соединить области и т.д.)
Надеюсь, что это поможет!
Ответ 2
Вы можете попробовать что-то вроде:
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" .
Вам также необходимо сгладить входное изображение перед обнаружением контура, чтобы избежать раздражения деталями или текстурами.
Надеюсь, что это поможет,
Томас
Ответ 3
Я думаю, вы можете использовать алгоритм Canny Edge Detection
, чтобы найти разницу в ребрах. Некоторые ссылки
Надеюсь, это поможет вам. Спасибо.
Ответ 4
Вот несколько кодов OpenCV4Android, чтобы найти самый большой контур в Mat
под названием image
, который мы будем предполагать в цветовом пространстве RGBA. Чтобы найти контуры, сначала необходимо установить порог или бинарировать изображение (преобразовать в черно-белый). Использование Gaussian Blur на изображении до порогового значения уменьшает количество создаваемых небольших контуров. Параметры размера для размытия и порога должны быть нечетными числами; вы можете поиграть, чтобы найти, какое значение дает лучшие результаты (здесь я использовал 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;
}
}
Ответ 5
есть две проблемы с этим выходом, не уверены, как их разрешить 1. закрыть рядом с ребрами 2. удалить небольшие ребра
-
Вы можете использовать морфологические операции для закрытия ребер. Найдите операторы расширения и закрытия.
-
Вы можете удалить небольшие ребра, выполнив маркировку. Подсчитайте количество пикселей в каждом регионе (связанные белые пиксели). Удалите любую область с количеством пикселей, меньшим некоторого порога. Я не использую opencv, но большинство библиотек имеют функцию маркировки, которая создаст изображение, где каждому набору трогательных пикселей одного цвета присваивается уникальный цвет в выходном изображении.