如何在 Matlab 中获取图像中存在的 n 条曲线的长度?
How to get the length of n curves present in an image in Matlab?
目前我一直致力于获取曲线的长度,使用以下代码我已经设法获取图像中存在的曲线长度。
test image one curve
然后我粘贴我用来获取简单图像曲线长度的代码。我所做的如下:
- 我得到了图像的列和行
- 我得到了 x 中的列和 y 中的行
- 我根据公式得到了曲线的系数
寓言
- 构建方程式
执行弧长公式得到曲线的长度
grayImage = imread(fullFileName);
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
subplot(2, 2, 1);
imshow(grayImage, []);
% Get the rows (y) and columns (x).
[rows, columns] = find(binaryImage);
coefficients = polyfit(columns, rows, 2); % Gets coefficients of the formula.
% Fit a curve to 500 points in the range that x has.
fittedX = linspace(min(columns), max(columns), 500);
% Now get the y values.
fittedY = polyval(coefficients, fittedX);
% Plot the fitting:
subplot(2,2,3:4);
plot(fittedX, fittedY, 'b-', 'linewidth', 4);
grid on;
xlabel('X', 'FontSize', fontSize);
ylabel('Y', 'FontSize', fontSize);
% Overlay the original points in red.
hold on;
plot(columns, rows, 'r+', 'LineWidth', 2, 'MarkerSize', 10)
formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]);
% formulaD = vpa(formula)
df=diff(formula);
df = df^2;
f= (sqrt(1+df));
i = int(f,min(columns),max(columns));
j = double(i);
disp(j);
现在我有一个有n条曲线的图像2,我不知道如何才能得到每条曲线的长度
test image n curves
我认为你应该通过图像并询问是否有'1'如果有,请询问以下内容从而识别曲线的开头,获取长度并将其保存在BD中,我是代码不是很好,但这是我的想法
我试着用这个 post 但我不太了解,但是 Colours123 的想法听起来不错,这个 post 谈论 GUI https://www.mathworks.com/matlabcentral/fileexchange/24195-gui-utility-to-extract-x--y-data-series-from-matlab-figures
我建议你看看霍夫变换:
https://uk.mathworks.com/help/images/hough-transform.html
您将需要图像处理工具箱。否则,你必须发展自己的逻辑。
https://en.wikipedia.org/wiki/Hough_transform
更新 1
我花了两个小时思考你的问题,但我只能提取第一条曲线。问题是定位曲线的起点。不管怎样,这是我想出的代码,希望能给你一些进一步开发的想法。
clc;clear;close all;
grayImage = imread('2.png');
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
% find edge.
bw = edge(grayImage,'canny');
imshow(bw);
[x, y] = find(bw == 1);
P = [x,y];
% For each point, find a point that is of distance 1 or sqrt(2) to it, i.e.
% find its connectivity.
cP = cell(1,length(x));
for i = 1:length(x)
px = x(i);
py = y(i);
dx = x - px*ones(size(x));
dy = y - py*ones(size(y));
distances = (dx.^2 + dy.^2).^0.5;
cP{i} = [x(distances == 1), y(distances == 1);
x(distances == sqrt(2)), y(distances == sqrt(2))];
end
% pick the first point and a second point that is connected to it.
fP = P(1,:);
Q(1,:) = fP;
Q(2,:) = cP{1}(1,:);
m = 2;
while true
% take the previous point from point set Q, when current point is
% Q(m,1)
pP = Q(m-1,:);
% find the index of the current point in point set P.
i = find(P(:,1) == Q(m,1) & P(:,2) == Q(m,2));
% Find the distances from the previous points to all points connected
% to the current point.
dx = cP{i}(:,1) - pP(1)*ones(length(cP{i}),1);
dy = cP{i}(:,2) - pP(2)*ones(length(cP{i}),1);
distances = (dx.^2 + dy.^2).^0.5;
% Take the farthest point as the next point.
m = m+1;
p_cache = cP{i}(find(distances==max(distances),1),:);
% Calculate the distance of this point to the first point.
distance = ((p_cache(1) - fP(1))^2 + (p_cache(2) - fP(2))^2).^0.5;
if distance == 0 || distance == 1
break;
else
Q(m,:) = p_cache;
end
end
% By now we should have built the ordered point set Q for the first curve.
% However, there is a significant weakness and this weakness prevents us to
% build the second curve.
更新 2
自上次更新以来还有一些工作要做。我现在可以分开每条曲线了。我在这里看到的唯一问题是要有一个好的曲线拟合。我建议使用 B 样条曲线或贝塞尔曲线而不是多项式拟合。我想我会在这里停下来,让您自己解决剩下的问题。希望这有帮助。
请注意,以下脚本使用 Image Processing Toolbox 来查找曲线的边缘。
clc;clear;close all;
grayImage = imread('2.png');
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
% find edge.
bw = edge(grayImage,'canny');
imshow(bw);
[x, y] = find(bw == 1);
P = [x,y];
% For each point, find a point that is of distance 1 or sqrt(2) to it, i.e.
% find its connectivity.
cP =[0,0]; % add a place holder
for i = 1:length(x)
px = x(i);
py = y(i);
dx = x - px*ones(size(x));
dy = y - py*ones(size(y));
distances = (dx.^2 + dy.^2).^0.5;
c = [find(distances == 1); find(distances == sqrt(2))];
cP(end+1:end+length(c),:) = [ones(length(c),1)*i, c];
end
cP (1,:) = [];% remove the place holder
% remove duplicates
cP = unique(sort(cP,2),'rows');
% seperating curves
Q{1} = cP(1,:);
for i = 2:length(cP)
cp = cP(i,:);
% search for points in cp in Q.
for j = 1:length(Q)
check = ismember(cp,Q{j});
if ~any(check) && j == length(Q) % if neither has been saved in Q
Q{end+1} = cp;
break;
elseif sum(check) == 2 % if both points cp has been saved in Q
break;
elseif sum(check) == 1 % if only one of the points exists in Q, add the one missing.
Q{j} = [Q{j}, cp(~check)];
break;
end
end
% review sets in Q, merge the ones having common points
for j = 1:length(Q)-1
q = Q{j};
for m = j+1:length(Q)
check = ismember(q,Q{m});
if sum(check)>=1 % if there are common points
Q{m} = [Q{m}, q(~check)]; % merge
Q{j} = []; % delete the merged set
break;
end
end
end
Q = Q(~cellfun('isempty',Q)); % remove empty cells;
end
% each cell in Q represents a curve. Note that points are not ordered.
figure;hold on;axis equal;grid on;
for i = 1:length(Q)
x_ = x(Q{i});
y_ = y(Q{i});
coefficients = polyfit(y_, x_, 3); % Gets coefficients of the formula.
% Fit a curve to 500 points in the range that x has.
fittedX = linspace(min(y_), max(y_), 500);
% Now get the y values.
fittedY = polyval(coefficients, fittedX);
plot(fittedX, fittedY, 'b-', 'linewidth', 4);
% Overlay the original points in red.
plot(y_, x_, 'r.', 'LineWidth', 2, 'MarkerSize', 1)
formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]);
% formulaD = vpa(formula)
df=diff(formula);
lengthOfCurve(i) = double(int((sqrt(1+df^2)),min(y_),max(y_)));
end
结果:
您可以使用 regionprops
to estimate the perimeter of each region (i.e. arc) and then dividing that by 2. Here's how you would do this (requires the Image Processing Toolbox):
获得很好的弧长近似值
img = imread('6khWw.png'); % Load sample RGB image
bw = ~imbinarize(rgb2gray(img)); % Convert to grayscale, then binary, then invert it
data = regionprops(bw, 'PixelList', 'Perimeter'); % Get perimeter (and pixel coordinate
% list, for plotting later)
lens = [data.Perimeter]./2; % Compute lengths
imshow(bw) % Plot image
hold on;
for iLine = 1:numel(data),
xy = mean(data(iLine).PixelList); % Get mean of coordinates
text(xy(1), xy(2), num2str(lens(iLine), '%.2f'), 'Color', 'r'); % Plot text
end
这是情节:
作为完整性检查,我们可以使用一个简单的测试图像来查看这给我们的近似值有多好:
testImage = zeros(100); % 100-by-100 image
testImage(5:95, 5) = 1; % Add a vertical line, 91 pixels long
testImage(5, 10:90) = 1; % Add a horizontal line, 81 pixels long
testImage(2020:101:6060) = 1; % Add a diagonal line 41-by-41 pixels
testImage = logical(imdilate(testImage, strel('disk', 1))); % Thicken lines slightly
运行上面的代码在这张图片上,我们得到如下:
如您所见,水平线和垂直线的长度接近我们的预期,并且由于扩张步骤稍微延长了对角线的长度,对角线比 sqrt(2)*41
多一点。
目前我一直致力于获取曲线的长度,使用以下代码我已经设法获取图像中存在的曲线长度。
test image one curve
然后我粘贴我用来获取简单图像曲线长度的代码。我所做的如下:
- 我得到了图像的列和行
- 我得到了 x 中的列和 y 中的行
- 我根据公式得到了曲线的系数 寓言
- 构建方程式
执行弧长公式得到曲线的长度
grayImage = imread(fullFileName); [rows, columns, numberOfColorBands] = size(grayImage); if numberOfColorBands > 1 grayImage = grayImage(:, :, 2); % Take green channel. end subplot(2, 2, 1); imshow(grayImage, []); % Get the rows (y) and columns (x). [rows, columns] = find(binaryImage); coefficients = polyfit(columns, rows, 2); % Gets coefficients of the formula. % Fit a curve to 500 points in the range that x has. fittedX = linspace(min(columns), max(columns), 500); % Now get the y values. fittedY = polyval(coefficients, fittedX); % Plot the fitting: subplot(2,2,3:4); plot(fittedX, fittedY, 'b-', 'linewidth', 4); grid on; xlabel('X', 'FontSize', fontSize); ylabel('Y', 'FontSize', fontSize); % Overlay the original points in red. hold on; plot(columns, rows, 'r+', 'LineWidth', 2, 'MarkerSize', 10) formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]); % formulaD = vpa(formula) df=diff(formula); df = df^2; f= (sqrt(1+df)); i = int(f,min(columns),max(columns)); j = double(i); disp(j);
现在我有一个有n条曲线的图像2,我不知道如何才能得到每条曲线的长度
test image n curves
我认为你应该通过图像并询问是否有'1'如果有,请询问以下内容从而识别曲线的开头,获取长度并将其保存在BD中,我是代码不是很好,但这是我的想法
我试着用这个 post 但我不太了解,但是 Colours123 的想法听起来不错,这个 post 谈论 GUI https://www.mathworks.com/matlabcentral/fileexchange/24195-gui-utility-to-extract-x--y-data-series-from-matlab-figures
我建议你看看霍夫变换: https://uk.mathworks.com/help/images/hough-transform.html
您将需要图像处理工具箱。否则,你必须发展自己的逻辑。
https://en.wikipedia.org/wiki/Hough_transform
更新 1
我花了两个小时思考你的问题,但我只能提取第一条曲线。问题是定位曲线的起点。不管怎样,这是我想出的代码,希望能给你一些进一步开发的想法。
clc;clear;close all;
grayImage = imread('2.png');
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
% find edge.
bw = edge(grayImage,'canny');
imshow(bw);
[x, y] = find(bw == 1);
P = [x,y];
% For each point, find a point that is of distance 1 or sqrt(2) to it, i.e.
% find its connectivity.
cP = cell(1,length(x));
for i = 1:length(x)
px = x(i);
py = y(i);
dx = x - px*ones(size(x));
dy = y - py*ones(size(y));
distances = (dx.^2 + dy.^2).^0.5;
cP{i} = [x(distances == 1), y(distances == 1);
x(distances == sqrt(2)), y(distances == sqrt(2))];
end
% pick the first point and a second point that is connected to it.
fP = P(1,:);
Q(1,:) = fP;
Q(2,:) = cP{1}(1,:);
m = 2;
while true
% take the previous point from point set Q, when current point is
% Q(m,1)
pP = Q(m-1,:);
% find the index of the current point in point set P.
i = find(P(:,1) == Q(m,1) & P(:,2) == Q(m,2));
% Find the distances from the previous points to all points connected
% to the current point.
dx = cP{i}(:,1) - pP(1)*ones(length(cP{i}),1);
dy = cP{i}(:,2) - pP(2)*ones(length(cP{i}),1);
distances = (dx.^2 + dy.^2).^0.5;
% Take the farthest point as the next point.
m = m+1;
p_cache = cP{i}(find(distances==max(distances),1),:);
% Calculate the distance of this point to the first point.
distance = ((p_cache(1) - fP(1))^2 + (p_cache(2) - fP(2))^2).^0.5;
if distance == 0 || distance == 1
break;
else
Q(m,:) = p_cache;
end
end
% By now we should have built the ordered point set Q for the first curve.
% However, there is a significant weakness and this weakness prevents us to
% build the second curve.
更新 2
自上次更新以来还有一些工作要做。我现在可以分开每条曲线了。我在这里看到的唯一问题是要有一个好的曲线拟合。我建议使用 B 样条曲线或贝塞尔曲线而不是多项式拟合。我想我会在这里停下来,让您自己解决剩下的问题。希望这有帮助。
请注意,以下脚本使用 Image Processing Toolbox 来查找曲线的边缘。
clc;clear;close all;
grayImage = imread('2.png');
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
% find edge.
bw = edge(grayImage,'canny');
imshow(bw);
[x, y] = find(bw == 1);
P = [x,y];
% For each point, find a point that is of distance 1 or sqrt(2) to it, i.e.
% find its connectivity.
cP =[0,0]; % add a place holder
for i = 1:length(x)
px = x(i);
py = y(i);
dx = x - px*ones(size(x));
dy = y - py*ones(size(y));
distances = (dx.^2 + dy.^2).^0.5;
c = [find(distances == 1); find(distances == sqrt(2))];
cP(end+1:end+length(c),:) = [ones(length(c),1)*i, c];
end
cP (1,:) = [];% remove the place holder
% remove duplicates
cP = unique(sort(cP,2),'rows');
% seperating curves
Q{1} = cP(1,:);
for i = 2:length(cP)
cp = cP(i,:);
% search for points in cp in Q.
for j = 1:length(Q)
check = ismember(cp,Q{j});
if ~any(check) && j == length(Q) % if neither has been saved in Q
Q{end+1} = cp;
break;
elseif sum(check) == 2 % if both points cp has been saved in Q
break;
elseif sum(check) == 1 % if only one of the points exists in Q, add the one missing.
Q{j} = [Q{j}, cp(~check)];
break;
end
end
% review sets in Q, merge the ones having common points
for j = 1:length(Q)-1
q = Q{j};
for m = j+1:length(Q)
check = ismember(q,Q{m});
if sum(check)>=1 % if there are common points
Q{m} = [Q{m}, q(~check)]; % merge
Q{j} = []; % delete the merged set
break;
end
end
end
Q = Q(~cellfun('isempty',Q)); % remove empty cells;
end
% each cell in Q represents a curve. Note that points are not ordered.
figure;hold on;axis equal;grid on;
for i = 1:length(Q)
x_ = x(Q{i});
y_ = y(Q{i});
coefficients = polyfit(y_, x_, 3); % Gets coefficients of the formula.
% Fit a curve to 500 points in the range that x has.
fittedX = linspace(min(y_), max(y_), 500);
% Now get the y values.
fittedY = polyval(coefficients, fittedX);
plot(fittedX, fittedY, 'b-', 'linewidth', 4);
% Overlay the original points in red.
plot(y_, x_, 'r.', 'LineWidth', 2, 'MarkerSize', 1)
formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]);
% formulaD = vpa(formula)
df=diff(formula);
lengthOfCurve(i) = double(int((sqrt(1+df^2)),min(y_),max(y_)));
end
结果:
您可以使用 regionprops
to estimate the perimeter of each region (i.e. arc) and then dividing that by 2. Here's how you would do this (requires the Image Processing Toolbox):
img = imread('6khWw.png'); % Load sample RGB image
bw = ~imbinarize(rgb2gray(img)); % Convert to grayscale, then binary, then invert it
data = regionprops(bw, 'PixelList', 'Perimeter'); % Get perimeter (and pixel coordinate
% list, for plotting later)
lens = [data.Perimeter]./2; % Compute lengths
imshow(bw) % Plot image
hold on;
for iLine = 1:numel(data),
xy = mean(data(iLine).PixelList); % Get mean of coordinates
text(xy(1), xy(2), num2str(lens(iLine), '%.2f'), 'Color', 'r'); % Plot text
end
这是情节:
作为完整性检查,我们可以使用一个简单的测试图像来查看这给我们的近似值有多好:
testImage = zeros(100); % 100-by-100 image
testImage(5:95, 5) = 1; % Add a vertical line, 91 pixels long
testImage(5, 10:90) = 1; % Add a horizontal line, 81 pixels long
testImage(2020:101:6060) = 1; % Add a diagonal line 41-by-41 pixels
testImage = logical(imdilate(testImage, strel('disk', 1))); % Thicken lines slightly
运行上面的代码在这张图片上,我们得到如下:
如您所见,水平线和垂直线的长度接近我们的预期,并且由于扩张步骤稍微延长了对角线的长度,对角线比 sqrt(2)*41
多一点。