Я использую хитрое обнаружение краев и функцию поиска контуров (оба OpenCV), чтобы создать маркеры для преобразования водораздела. Все отлично работает, но я не на 100% удовлетворен результатами. Причина в том, что некоторые грани отсутствуют, и поэтому важная информация теряется. Более подробно, я получил несколько окон (вид спереди), которые являются прямоугольниками, после преобразования водораздела я получаю что-то вроде этого:
но я бы предпочел иметь хорошие прямоугольники, которые являются полными и не открываются в одну сторону. Сохраняя неправильные формы (кусты перед домом, машины …). Есть идеи, как мне решить эту проблему? Я думал о наложении всего изображения на сетку, но не могу заставить его работать.
Большое спасибо.
Вот мой код:
Mat gray;
cvtColor(im, gray, CV_BGR2GRAY);
// Use Canny instead of threshold to catch squares with gradient shading
Mat bw;
Canny(gray, bw, 0, 100, 5, true);
// Find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( bw, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );// watershed
Mat markers(bw.size(), CV_32S);
markers = Scalar::all(0);
int idx = 0;
int compCount = 0;
for( ; idx >= 0; idx = hierarchy[idx][0], compCount++ ) {
if (fabs(contourArea(contours[compCount])) < min_size )
continue;
drawContours(markers, contours, idx, Scalar::all(compCount+1), 1, 8, hierarchy, INT_MAX);
}
watershed( im, markers );
Как и требовалось, вот исходное изображение, изображение, которое я хотел бы получить, и мой вывод:
И я хотел бы иметь такую сегментацию (хотя чрезмерная сегментация не повредит, я просто должен убедиться, что я получаю все детали):
Пока я получаю что-то вроде этого:
(пожалуйста, игнорируйте цвета, они не важны для этого вопроса и являются просто результатом моей общей программы). Это только один пример, если вы хотите, я могу показать вам больше, также, пожалуйста, посмотрите на набор данных etrims, все мои фотографии оттуда.
Две вещи —
1) Как уже упоминалось, обнаружение краев приводит к обнаружению паразитных краев.
2) Использование этих краев в качестве маркеров для сегментации водораздела приводит к избыточной сегментации, потому что каждый маркер производит сегментированную область на выходе.
Стратегия —
(i) Предварительная обработка: сильно сгладить изображение (морфологическое раскрытие путем реконструкции можно использовать для гомогенизации интенсивностей без существенного влияния на интересующие вас кромки).
(ii) Маркеры: вместо того, чтобы использовать ребра в качестве семян, я бы использовал локальные экстремумы. В идеале нам нужен один маркер для каждого региона, который мы хотим сегментировать.
(iii) Сегментация: найдите величину градиента (фильтрация диапазона также является хорошим вариантом) изображения на шаге (i) и используйте его в качестве функции сегментации.
Используя эту стратегию, я получаю следующую сегментацию.
В качестве альтернативы, после шага (i), вы можете использовать функцию обнаружения ребер Canny и выполнить некоторую морфологическую очистку (чтобы заполнить контуры и удалить оставшиеся ребра). Это то, что я получаю.
Это не совсем ожидаемая сегментация (некоторые объекты, такие как автомобиль, не обнаружены), но это хорошее начало.
Редактировать: код MATLAB, используемый для генерации изображений —
% convert to grayscale
img = rgb2gray(origImg);
% create an appropriate structuring element
w_size = 20;
seSquare = strel('square', w_size);
% opening by reconstruction - to smooth dark regions
imgEroded = imerode(img, seSquare);
imgRecon = imreconstruct(imgEroded, img);
% invert and repeat - to smooth bright regions
imgReconComp = imcomplement(imgRecon);
imgEroded2 = imerode(imgReconComp, seSquare);
imgRecon2 = imreconstruct(imgEroded2, imgReconComp);
% get foreground markers
fgm = imregionalmax(imgRecon2);
% get background markers - this step can be skipped
% in which case only fgm would be the marker image
% and the segmentation would be different
distTrans = bwdist(fgm);
wLines= watershed(distTrans);
bgm = wLines == 0;
% get the segmentation function and impose markers
% perform watershed segmentation
seSquare3 = strel('square', 3);
rangeImg = rangefilt(imgRecon2, getnhood(seSquare3));
segFunc = imimposemin(rangeImg, fgm | bgm);
grayLabel = watershed(segFunc);
rgbLabel= label2rgb(grayLabel);
figure, imshow(rgbLabel); title('Output using Watershed')
% alternatively, extract edges from the preprocessed image
% perform morph cleanup
bwEdges = edge(imgRecon2, 'canny');
bwFilled = imfill(bwEdges, 'holes');
bwRegions = imopen(bwFilled, seSquare3);
grayLabel = bwlabel(bwRegions);
rgbLabel = label2rgb(grayLabel, 'jet', 'k');
figure, imshow(rgbLabel); title('Output using Canny')
Судя по виду желаемого результата и результата программы, детектор краев обнаруживает паразитные грани. Детектор краев Canny содержит фильтр нижних частот, но он может помочь вам выполнить отдельный шаг гауссовой фильтрации нижних частот, прежде чем вы действительно запустите детектор краев Canny.
Кроме этого, трудно достичь желаемого результата. Например, посмотрите на самые верхние окна на картинке. У них разные цвета — рамка, тень рамки и окно. Границы этих цветов будут обнаружены краями детектором краев.