Удаление цветных линий в Matlab
Я пытаюсь удалить цветные линии (особенно желтую и синюю линии) в серии изображений в Matlab. Пример изображения можно найти здесь:
Я могу выделить сегменты синей линии, используя базовый порог. Я также могу выделить ярко-желтые круги в пределах желтого отрезка, используя порог. Наконец, я работаю над удалением оставшихся элементов отрезка линии, используя грубое преобразование с функцией "грубые линии" и маску.
Есть ли более элегантный способ сделать это, или я застрял, используя эту комбинацию методов?
Спасибо
Изменить: я обнаружил, что грубое преобразование удаляет только один пиксель из моего изображения, а не всю желтую линию. Я размышлял о расширении вокруг обнаруженных пикселей и проверке на сходство, но меня беспокоит то, что желтая линия слишком похожа на цвета фона (ее положение может измениться так, что она не полностью отслеживает темный фон, который сейчас закончился). Любые предложения будут ценны.
%% This block was intended to deal with another data
set this function has to analyze, but it actually ended up removing my
yellow circles as well, making a further threshold step unnecessary so far
% Converts to a binary image containing almost exclusively lines and crosshairs
mask = im2bw(rgb_img, 0.8);
% Invert mask
mask = ~mask;
% Remove detected lines and crosshairs by setting to 0
rgb_img(repmat(~mask, [1, 1, 3])) = 0;
%% Removes blue targetting lines if present
% Define thresholds for RGB channel 3 based on histogram settings to remove
% blue lines
channel3Min = 0.000;
channel3Max = 0.478;
% Create mask based on chosen histogram thresholds
noBlue = (rgb_img(:,:,3) >= channel3Min ) & (rgb_img(:,:,3) <= channel3Max);
% Set background pixels where noBlue is false to zero.
rgb_img(repmat(~noBlue,[1 1 3])) = 0;
%% Removes any other targetting lines if present
imageGreyed = rgb2gray(rgb_img);
% Performs canny edge detection
BW = edge(imageGreyed, 'canny');
% Computes the hough transform
[H,theta,rho] = hough(BW);
% Finds the peaks in the hough matrix
P = houghpeaks(H,5,'threshold',ceil(0.3*max(H(:))));
% Finds any large lines present in the image
lines = houghlines(BW,theta,rho,P,'FillGap',5,'MinLength',100);
colEnd = [];
rowEnd = [];
for i = 1:length(lines)
% Extracts line start and end points from houghlines output
pointHold = lines(i).point1;
colEnd = [colEnd pointHold(1)];
rowEnd = [rowEnd pointHold(2)];
pointHold = lines(i).point2;
colEnd = [colEnd pointHold(1)];
rowEnd = [rowEnd pointHold(2)];
% Creates a line segment from the line endpoints using a simple linear regression
fit = polyfit(colEnd, rowEnd, 1);
% Creates index of "x" (column) values to be fed into regression
colIndex = (colEnd(1):colEnd(2));
rowIndex = [];
% Obtains "y" (row) pixel values from regression
for i = colIndex
rowHold = fit(1) * i + fit(2);
rowIndex = [rowIndex rowHold];
end
% Round regression output
rowIndex = round(rowIndex);
% Assemble coordinate matrix
lineCoordinates = [colIndex; rowIndex]';
rgbDim = size(rgb_img);
% Create mask based on input image size
yellowMask = ones(rgbDim(1), rgbDim(2));
for i = 1:length(rowIndex)
yellowMask(rowIndex(i), colIndex(i)) = 0;
end
% Remove the lines found by hough transform
rgb_img(repmat(~yellowMask,[1 1 3])) = 0;
end
end
3 ответа
Оказывается, что ответ включал преобразование изображения в цветовое пространство La b и выполнение трешхолдинга. Это сегментировало линии с минимальными потерями в остальной части изображения. Код ниже:
% Convert RGB image to L*a*b color space for thresholding
rgb_img = im2double(rgb_img);
cform = makecform('srgb2lab', 'AdaptedWhitePoint', whitepoint('D65'));
I = applycform(rgb_img,cform);
% Define thresholds for channel 2 based on histogram settings
channel2Min = -1.970;
channel2Max = 48.061;
% Create mask based on chosen histogram threshold
BW = (I(:,:,2) <= channel2Min ) | (I(:,:,2) >= channel2Max);
% Determines the eccentricity for regions of pixels; basically how line-like
% (vals close to 1) or circular (vals close to 0) the region is
rp = regionprops(BW, 'PixelIdxList', 'Eccentricity');
% Selects for regions which are not line segments (areas which
% may have been incorrectly thresholded out with the crosshairs)
rp = rp([rp.Eccentricity] < 0.99);
% Removes the non-line segment regions from the mask
BW(vertcat(rp.PixelIdxList)) = false;
% Set background pixels where BW is false to zero.
rgb_img(repmat(BW,[1 1 3])) = 0;
Этот пост не будет посвящен стороне проблемы обработки изображений, а скорее сосредоточен на реализации и предложит пути улучшения существующего кода. Теперь код имеет polyfit
расчет на каждой итерации цикла, который я не уверен, может быть векторизован. Итак, давайте попробуем векторизовать остальные коды внутри цикла, и, надеюсь, это приведет к некоторому ускорению всего кода. Изменения, которые я хотел бы предложить, находятся в двух шагах внутри самого внутреннего цикла.
1) Заменить -
rowIndex=[]
for i = colIndex
rowHold = fit(1) * i + fit(2)
rowIndex = [rowIndex rowHold];
end
с -
rowIndex = fit(1)*colIndex + fit(2)
2) Заменить -
yellowMask = ones(rgbDim(1), rgbDim(2));
for i = 1:length(rowIndex)
yellowMask(rowIndex(i), colIndex(i)) = 0;
end
rgb_img(repmat(~yellowMask,[1 1 3])) = 0;
с -
idx1 = (colIndex-1)*rgbDim(1) + rowIndex
rgb_img(bsxfun(@plus,idx1(:),[0:rgbDim(3)-1]*rgbDim(1)*rgbDim(2))) = 0;
Я кратко протестировал пример, приведенный на http://de.mathworks.com/help/images/examples/color-based-segmentation-using-k-means-clustering.html?prodcode=IP&language=en
используя ваше изображение, которое:
he = imread('HlQVN.jpg');
imshow(he)
cform = makecform('srgb2lab');
lab_he = applycform(he,cform);
ab = double(lab_he(:,:,2:3));
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);
nColors = 3;
% repeat the clustering 3 times to avoid local minima
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
'Replicates',3);
pixel_labels = reshape(cluster_idx,nrows,ncols);
segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);
for k = 1:nColors
color = he;
color(rgb_label ~= k) = 0;
segmented_images{k} = color;
end
imshow(segmented_images{1}), title('objects in cluster 1');
это уже довольно хорошо идентифицирует синюю линию.