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

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

Основная идея заключается в том, чтобы позволить пользователю перекрашивать конкретный пользовательский выбор на стене. В настоящее время я реализовал эту функцию с помощью 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

4b9b3361

Ответ 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" . Вам также необходимо сгладить входное изображение перед обнаружением контура, чтобы избежать раздражения деталями или текстурами.

Надеюсь, что это поможет, Томас

Ответ 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, но большинство библиотек имеют функцию маркировки, которая создаст изображение, где каждому набору трогательных пикселей одного цвета присваивается уникальный цвет в выходном изображении.