这是约翰 BG jgb2012@sky.com
1.- 避免加倍段
如果您继续使用您在方法中使用的代码:
img=imread('001.jpg');
imshow(img);
img = rgb2gray(img);
img = medfilt2(img);
v = edge(img,'sobel','vertical');
v = bwlabel(v);
stats = regionprops(v, 'Area','BoundingBox','Image');
ids = find([stats.Area] > 30 & [stats.Area] < 2000);
vsq = ismember(v,ids);
figure;imshow(vsq)

您正在添加不应该包含的片段,添加的附加线条非常接近原始图像的线条,但不应该存在。在搜索平行线时,看起来这些非常接近的线对中的每一个都算作真正的平行线对,而实际上只有一条线
因此,请允许我提出以下建议:
2.- 获取图像,仅取 1 个颜色层,并进行二值化:
clear all;clc;close all
input_image_filename='001.jpg'
A=imread(input_image_filename);
figure(1);imshow(A)
因为所有 3 个 RGB 层都有完全相同的层,所以 1 层就足够了
A1=A(:,:,1)
th1=100
A1(A1>th1)=255;A1(A1<=th1)=0;
figure(2);imshow(A1)
3.- 使用命令 bwmorph 收缩平滑一点
A2=A1;
A2(A2>0)=1; % same as A2=imbinarize(A1);
A3=bwmorph(A2,'skel',Inf);
figure(3);imshow(A3);
% 003
A4=bwmorph(A3,'tophat',Inf); % not useful
figure(4);imshow(A4);
% 004
4.-编号计数段
A5=bwlabel(A4,8);
figure(5);imshow(A5)
% 004-2

现在,最后一个图显然与前一个图相同,但实际上现在每个段都有不同的值,尽管所有段也看起来是白色的:最右边的直线段的所有像素都有值 31,所有“白色”像素该段实际上具有相同的值 31。
整个图中没有其他段具有任何值为 31 的像素。
紧靠上述标记为 31 的片段左侧的片段具有值 30,同样,同一片段的所有像素都具有相同的值 30,同时整个图中没有其他片段具有任何像素值,既不是 31 也不是 30。
现在我们可以计算图像中有多少段,避免第 1 点中突出显示的危险加倍
range_A5=unique(A5)';
amount_segments=max(range_A5)
amount_segments =
47
有47段
5.- 短枝呢?
目标是相互比较片段并告诉它们的平行程度,成对比较。
为了保持答案简洁,让我们简化为线性段:
没有 T 形接头 没有星形或任何其他线段拓扑,如果不将笔从纸上抬起,就无法用单笔迹线绘制。
5.1.- 捕获所有段的尖端点
A5(1,:)=0;A5(end,:)=0;A5(:,1)=0;A5(:,end)=0; % make sure picture frame, all edge pixels, are black
A4(1,:)=0;A4(end,:)=0;A4(:,1)=0;A4(:,end)=0; % make sure picture frame, all edge pixels, are black
% figure(6);imshow(A5); % check that there are not white pixels right on edge of picture
[sz1_A5,sz2_A5]=size(A5) % sz2 horizontal sz1 vertical
[wx,wy,v]=find(A5);P=[wx wy]; % P: all white points
hold all % check P contains all white and only white points
for k=1:1:length(P)
plot(P(k,2),P(k,1),'r*')
end
% 004-3
PA:单元格 PA 的每个元素包含 1 段的所有像素
接下来,S 将包含每个段的所有尖端点的坐标 {[x11 y11 x12 y12] [x21 y21 x22 y22 x23 y23] ..}
S={}; % coordinates of tip points of each segment {[x11 y11 x12 y12] [x21 y21 x22 y22 x23 y23] .. }
for k=1:1:length(PA)
L0=PA{k}
% hold all % check all points in L0 define same segment
% for k10=1:1:length(L0)
% plot(L0(k10,2),L0(k10,1),'r*')
% end
T1=[]
for k2=1:1:size(L0,1)
p1=L0(k2,:) % read white point coordinates
p1y=p1(1);p1x=p1(2)
P2=[p1y-1 p1x-1; % coordinates of 8 pixels around p1
p1y-1 p1x;
p1y-1 p1x+1;
p1y p1x+1;
p1y+1 p1x+1;
p1y+1 p1x;
p1y+1 p1x-1;
p1y p1x-1];
s2=0
for k3=1:1:8
s2=s2+A4(P2(k3,1),P2(k3,2))
end
if s2==1 % there's only 1 px adjacent to p1
T1=[T1 p1x p1y]
end
end
p1_check=T1([1:2:end]) % mark all tips found for same segment
p2_check=T1([2:2:end])
hold all;
for k4=1:1:numel(p1_check)
plot(p1_check(k4),p2_check(k4),'b*')
end
% end
S{k}=T1
end
% 005
5.2.- 选择相距最远的 2 个提示作为提示点:
即使是明显或多或少的直线段也可能显示多于 1 对尖端点
% 005-2

因此,让我们首先通过选择仅一对点作为分段提示来解决此问题,从上述点中选择,选择那些最远的设备。
T2=[0 0 0 0]
for k=1:1:size(S,2)
L1=S{k}
ptx=L1([1:2:end]) % mark all tips found for same segment
pty=L1([2:2:end])
if numel(ptx)>2 more_than_2_tips=1; end
if numel(ptx)==2 more_than_2_tips=0; end
if numel(ptx)<2 more_than_2_tips=NaN; end % error
switch more_than_2_tips
case 1
D=((ptx-ptx').^2+(pty-pty').^2).^.5 % distance matrix
maxD=max(max(D))
[nrow,ncol,v]=find(D==maxD)
ptipx1=ptx(nrow(1))
ptipx2=ptx(nrow(2))
ptipy1=pty(ncol(1))
ptipy2=pty(ncol(2))
hold all;
plot([ptipx1 ptipx2],[ptipy2 ptipy1],'ro','MarkerSize',10,'LineWidth',2)
plot([ptipx1 ptipx2],[ptipy2 ptipy1],'r','MarkerSize',10,'LineWidth',2)
D(nrow,ncol)
T2=[T2;ptipx1 ptipy2 ptipx2 ptipy1]
case 0
D=((ptx(1)-ptx(2))^2+(pty(1)-pty(2))^2)^.5
hold all;
plot([ptx(1) ptx(2)],[pty(1) pty(2)],'ro','MarkerSize',10,'LineWidth',2)
plot([ptx(1) ptx(2)],[pty(1) pty(2)],'r','MarkerSize',10,'LineWidth',2)
T2=[T2;ptx(1) pty(1) ptx(2) pty(2)]
otherwise
end
end
T2(1,:)=[]
T2 包含所有尖端点,每段 2 个
% check
ptnx=T2(:,[1 3])
ptny=T2(:,[2 4])
plot(ptnx,ptny,'yo','MarkerSize',10,'LineWidth',2)
评论:这个检查是“更多的 MATLAB”之类的。
确实不需要上面使用的某些 for 循环。有些习惯很难改掉。

T2:分段提示
M2:分段坡度
6.- 如何定义、测量和比较 2 个给定 2D 段之间的平行度。
T2
M2=(T2(:,4)-T2(:,2))./(T2(:,3)-T2(:,1))
7.-考虑直线度和平行度等效:
平行度的测量与所比较的段的直线度密切相关
在 2D 中,坡度或直线度 Inf 或 -Inf 相同
M2(find(M2==-Inf))=Inf
那么问题是在所有段之间比较 M2
PAR=M2-M2'
段数上的平行度
figure(6);stem(M2);grid on
% 007-1
figure(7);histogram(M2)
% 007-2
然而,与其将 M2 视为并行度的直接衡量标准,或许在问题的上下文中,已经提到它与车牌识别有关,但样本图像看起来更像是一个生物实验室。 petry,也许作为平行度的角度会更合适:
PAR_angle=atand(M2)-atand(M2)'
角度以度为单位,而不是弧度。
figure(7);stem(atand(M2));grid on
% 007-3
figure(8);histogram(atand(M2),35)
% 007-4

观察:没有绝对(角度)>100º的线段
评论:线段对之间平行度比较的矩阵PAR是对称的,只需要对角线的一侧。
如果有兴趣,我可以展示如何添加标准或自定义颜色图,映射到 M2 斜率或 atand(M2) 角度,以在视觉上将具有相似平行度的段配对
cmap=colormap(jet)
..
到目前为止,问题已得到解答,以下几点是未解决的评论和替代解决方案,如果读者认为可能有任何帮助,请完成:
%%%%%%%%%%%%%%%%%%%%%%%%%%
8.- 让我们避免混淆,例如 Taylor Hobson 的并行器的行业定义
https://www.taylor-hobson.com/-/media/ametektaylorhobson/files/learning%20zone/training%20material/straightness%20and%20%20parallelism.pdf?la=en
008
在 Taylor Hobson,他们使用以下标准:
D1-D2 越接近零,D1 D2 是 2 个线段的尖端之间的距离但是 TH 称它为线段越平行,但这比 2D 线段更能衡量对称性。
考虑到大量的段,如果尖端被交叉并且 D1 D2 错误地显示比它们应该的大怎么办?
**9.- 平行线的欧几里得定义:
平面上不相交的一对直线。**
评论:允许为直线段保留单词“line”,相邻像素与直接相邻像素保持相同的斜率。
我找到了与欧几里得并行性等效的定义:
**如果连接 2 个“等效”或“配对”像素的所有光束(不同段中的每个像素)满足以下条件,则该问题初始图中的任何 2 个段都可以被认为是高度平行的:
a.- 所有梁具有相同的坡度
b.- 所有梁的长度相同**

这样有 2 个整形片段,其中一个是另一个的翻译副本,例如 (SS CC LL),相对旋转为零,这与相同的姿态和相同数量的像素相同:这样的原始副本和翻译副本将最大程度地平行.
但是根据欧几里得定义或平行线,两个同心圆是平行的,但无论考虑的点如何,它们都不是直的。
要测量任意一对线段之间的梁斜率和长度,必须首先解决 2 个障碍:
避免钉子和 T 形接头产生过多和不必要的光束
9.1.- 移除钉子
9.2.- 段的长度不同
为了在提供此答案时减少工作量,我将这一点 9.2 限制为以下起始图,此过程可以轻松升级到问题所附初始图中的其余部分:
10.- 测量横梁角度(坡度)和长度
由于第 7 点已经提供了对并行度的准确测量。
我将关闭此答案,将第 8、9、10 点留给任何读者的兴趣,如果联系到这些点,将相应地开发。
%%%%%%%%%
发送紧凑的脚本,只需通过电子邮件告诉我在哪里。
如果您发现此答案有用,请考虑将我的答案标记为已接受的答案吗?
对于任何其他读者,如果您发现此答案有用,请考虑单击箭头投票链接
提前感谢您的时间和关注
约翰·BG
jgb2012@sky.com