Учитывая матрицу изображения, как я могу получить расположение пикселей, расстояние до шахматной доски которых от пикселя А меньше, чем Д. Мне нужно выполнить это для всех пикселей.
Используя функцию MATLAB bwdist
я не смог добиться желаемого результата. Какое решение?
[D,idx] = bwdist(Img,'chessboard');
Учитывая изображение, пиксель и максимальное расстояние:
% Test image
Image = zeros(20,30);
% Maximum chessboard distance from image
maxDist = 7;
% The pixel from which to measure distance
pix = [4,19];
Чтобы найти пиксели, которые находятся на расстоянии шахматной доски от pix
меньше, чем maxDist
и в границах изображения:
Опция 1: Использование bwdist
% Create a binary image with all pixels zero except 'pix'
bw = zeros(size(Image));
bw(pix(1), pix(2)) = 1;
% Get the chessboard distance transform
[D,idx] = bwdist(bw,'chessboard');
% Get the linear index of 'pix'
pixInd = sub2ind(size(bw), pix(1), pix(2));
% Find linear indices of pixels who's chessboard distance from pixel are
% less than 'maxDist'
pointsInd = find(idx == pixInd & D < maxDist);
% Remove 'pix'
pointsInd(pointsInd == pixInd) = [];
% Get the pairs of (x,y) of the pixels
[pointsX, pointsY] = ind2sub(size(bw), pointsInd);
Вариант 2: Использование meshgrid
% Get the range of x and y indices who's chessboard distance from pixel are
% less than 'maxDist' and in the image bounds
xRange = max((pix(1)-(maxDist-1)),1):min((pix(1)+(maxDist-1)),size(Image,1));
yRange = max((pix(2)-(maxDist-1)),1):min((pix(2)+(maxDist-1)),size(Image,2));
% Create a mesgrid to get the pairs of (x,y) of the pixels
[pointsX, pointsY] = meshgrid(xRange, yRange);
pointsX = pointsX(:);
pointsY = pointsY(:);
% Remove 'pix'
pixIndToRemove = (pointsX == pix(1) & pointsY == pix(2));
pointsX(pixIndToRemove) = [];
pointsY(pixIndToRemove) = [];
Отображение результата:
% Get linear indices of pixels
pointsInd = sub2ind(size(Image), pointsX, pointsY);
% To display the result, create a binary image with all found pixels
% colored white
bwPoints = zeros(size(Image));
bwPoints(pointsInd) = 1;
% Show points
imshow(bwPoints, 'InitialMagnification', 2000)
% Show pixel grid lines
hold on
[rows, cols] = size(bwPoints);
for row = 0.5 : 1 : (rows + 0.5)
line([0.5, cols+0.5], [row, row], 'Color', 'r', 'LineWidth', 0.5);
end
for col = 0.5 : 1 : (cols + 0.5)
line([col, col], [0.5, rows+0.5], 'Color', 'r', 'LineWidth', 0.5);
end
Эффективность и работа в цикле по всем пикселям изображения:
Вариант 2 намного быстрее, чем Опция 1. Сначала я написал Опция 1, потому что в вопросе упоминалось bwdist
. Запуск Вариант 2 в цикле можно улучшить, если сначала вычислить пиксели, а затем сместить их в положение каждого пикселя:
% Get the range of x and y indices who's chessboard distance from pixel
% (0,0) are less than 'maxDist'
xRange = (-(maxDist-1)):(maxDist-1);
yRange = (-(maxDist-1)):(maxDist-1);
% Create a mesgrid to get the pairs of (x,y) of the pixels
[pointsX, pointsY] = meshgrid(xRange, yRange);
pointsX = pointsX(:);
pointsY = pointsY(:);
% Remove pixel (0,0)
pixIndToRemove = (pointsX == 0 & pointsY == 0);
pointsX(pixIndToRemove) = [];
pointsY(pixIndToRemove) = [];
for x=1:size(Image, 1)
for y=1:size(Image, 2)
% Get a shifted copy of 'pointsX' and 'pointsY' that is centered
% around (x, y)
pointsX1 = pointsX + x;
pointsY1 = pointsY + y;
% Remove the the pixels that are out of the image bounds
inBounds =...
pointsX1 >= 1 & pointsX1 <= size(Image, 1) &...
pointsY1 >= 1 & pointsY1 <= size(Image, 2);
pointsX1 = pointsX1(inBounds);
pointsY1 = pointsY1(inBounds);
% Do stuff with 'pointsX1' and 'pointsY1'
% ...
end
end
@dtr43: я отредактировал ответ и удалил целевой пиксель.
Это работает, но в примерном случае (для изображения 434 * 700 пикселей) для вычисления расстояний до шахматной доски для всех пикселей вариант 1 (предлагаемое вами решение) был использован в двух циклах for. Кроме того, есть еще один внутренний цикл, который вычисляет евклидово расстояние между целевым пикселем и окружающими пикселями в пределах расстояния шахматной доски. Этот процесс очень трудоемкий и неэффективный. Есть ли какой-нибудь трюк, чтобы сделать это более эффективным?
@ dtr43: Вариант 2 намного быстрее. Я отредактировал ответ и добавил раздел о: Эффективность и работа в цикле по всем пикселям изображения
"The aim is to access the location of the pixels whose chessboard distances from pixel A is less than D. The process should be performed for all pixels..."
Поскольку Д создает квадратную область выбора, просто используйте простую математику.
Например: если Д равно 3, то из позиции [x,y] пикселя A...
//# we minus D by 1 since you want less than D (not equal / higher)
Start-X = pixelA.x - (D-1); //from the left
End-X = pixelA.y + (D-1); //to the right
Start-Y = pixelA.y - (D-1); //from the top
End-Y = pixelA.y + (D-1); //to the bottom
Это даст вам квадратный периметр, который представляет требуемую область выбора.
Посмотрите на этот пример изображения ниже:
Каждый квадрат — это пиксель. Если значок «корона» представляет собой пиксель А, а Д равен 3 (где ваш "меньше Д" означает, что Д имеет максимальную длину 2 пикселя), вы видите, как применяется приведенный выше псевдокод?
Спасибо за предложение; Я боюсь, если он может вычислить диагональные окрестности.
Если я правильно понял ваш комментарий... (1)
Шаг на один пиксель влево/вправо, а также шаг на один пиксель вверх/вниз для перемещения по диагонали. (2)
Повторяйте шаг (1), пока не будут покрыты все диагональные пиксели.
Спасибо за рабочее решение. Вроде все нормально, но есть тривиальная проблема: местоположение целевого пикселя (pix) включается в пары [pointsX, pointsY], чего быть не должно.