Как обнаружить длинные края стены, чтобы подготовить маску и перекрасить


Основная идея состоит в том, чтобы позволить пользователю перекрашивать к определенному выбору пользователя на основе стены. В настоящее время я реализовал эту функцию с помощью cvFloodFill (помогает подготовить изображение маски), которая может помочь мне изменить относительное значение HSV для стены, чтобы я мог сохранить края. но проблема с этим решением заключается в том, что оно работает на цвете, и все стены перекрашиваются вместо одной стены, выбранной пользователем.

Я также пробовал canny edge detection, но он просто способен обнаружить край,но не способен преобразовать его в область.

Пожалуйста, найдите ниже код, который я в настоящее время использую для перерисовки функции

  1. Подготовить маску

    cvFloodFill(mask, new CvPoint(295, 75), new CvScalar(255, 255, 255,0), cvScalarAll(1), cvScalarAll(1), null, 4, null);

  2. Разделенный канал

    cvSplit(hsvImage, hChannel, sChannel, vChannel, null);

  3. Изменить цвет

    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 15

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, чтобы найти разницу ребер. Некоторые ссылки

  1. StackOverFlow
  2. StackOverFlow
  3. OpenCV QA
  4. OpenCV
  5. Родной Учебник

Я надеюсь, что это может помочь вам. Спасибо.

Вот некоторый код 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. удалить мелкие края

  1. Вы можете использовать морфологические операции, чтобы закрыть края. Ищите операторы расширения и закрытия.

  2. Вы можете удалить небольшие края, сделав надпись. Подсчитайте количество пикселей в каждой области (Соединенных белых пикселей). Удалите любую область с числом пикселей меньше некоторого порогового значения. Я не использую opencv, но большинство библиотеки имеют функцию маркировки, которая создает изображение, где каждому набору соприкасающихся пикселей одного цвета присваивается уникальный цвет в выходном изображении.