% MERGESEG - Line segment merging function. % % Usage: newseglist = mergeseg(seglist, angtol, linkrad) % % Arguments: seglist - an Nx4 array storing line segments in the form % [x1 y1 x2 y2 % x1 y1 x2 y2 % . . . ] etc % % angtol - Angle tolerance used when attempting to merge line % segements (radians). % linkrad - Maximum distance between end points of line segments % for segments to be elegible for linking (pixels). % % Function scans through the list of line segments seeking to merge segments % together. Segments are merged if the orientation difference is less than % angtol and if the ends of the segments are within linkrad of each other. % The comparison is performed by first sorting line segments by angle, then % each line segment is only tested against other line segments that satisfy % the orientation constraint. % % See also: EDGELINK, LINESEG, MAXLINEDEV, DRAWSEG % % Copyright (c) 2000-2005 Peter Kovesi % School of Computer Science & Software Engineering % The University of Western Australia % http://www.csse.uwa.edu.au/ % % Permission is hereby granted, free of charge, to any person obtaining a copy % of this software and associated documentation files (the "Software"), to deal % in the Software without restriction, subject to the following conditions: % % The above copyright notice and this permission notice shall be included in % all copies or substantial portions of the Software. % % The Software is provided "as is", without warranty of any kind. % March 2000 - Original version % November 2005 - Bug fix for case Nseg < 4 (thanks to Ming Luo) % May 2006 - Bug fix for termination of while loop (thanks to Martin Labrecque) function newseglist = mergeseg(seglist, angtol, linkrad, linedevtol) Nseg = size(seglist,1); if Nseg <= 1 % Nothing to merge newseglist = seglist; return; end cosAngTol = cos(angtol); % Build up some data in the following form % [x1 y1 x2 y2 dx dy angle merged] seg = zeros(Nseg,8); seg(:,1:4) = seglist; seg(:,5:6) = seg(:,3:4)-seg(:,1:2); % delta x and delta y seg(:,7) = atan2(seg(:,6), seg(:,5)); % =segment angle [-pi ... pi] neg = seg(:,7) < 0; % compress angle range [0...pi] seg(:,7) = seg(:,7) + neg*pi; [Y,I] = sort(seg(:,7)); % sort by angle seg = seg(I,:); seg(:,7) = 2*seg(:,7); % double the angles TotalSegs = Nseg; for s1 = 1:Nseg % fprintf('Merging Segment %d/%d\r',s1,Nseg); if ~seg(s1,8) % if segment s1 has not already been merged s2 = s1+1; if s2>Nseg, s2=s2-Nseg; end % `modulo' arithetic ang1 = seg(s1,7); ang2 = seg(s2,7); deltaSin = sin(ang1)*cos(ang2) - cos(ang1)*sin(ang2); deltaCos = cos(ang1)*cos(ang2) + sin(ang1)*sin(ang2); deltaAng = 0.5*abs(atan2(deltaSin,deltaCos)); while (s2 ~= s1) && (deltaAng < angtol) if ~seg(s2,8) % if segment s2 has not already been merged [newseg, merged] = compareseg(seg(s1,:), seg(s2,:),linkrad, ... linedevtol); if merged seg(s1,1:4) = newseg; % update delta x, delta y, and angle ? (I think not) seg(s2,8) = merged; % eliminate s2; TotalSegs = TotalSegs - 1; end end s2 = s2+1; if s2>Nseg, s2=s2-Nseg; end ang2 = seg(s2,7); deltaSin = sin(ang1)*cos(ang2) - cos(ang1)*sin(ang2); deltaCos = cos(ang1)*cos(ang2) + sin(ang1)*sin(ang2); deltaAng = 0.5*abs(atan2(deltaSin,deltaCos)); end end end % fprintf('\n'); % Now clean up list by extracting the unmerged entries newseglist = zeros(TotalSegs,4); newNseg = 0; for s = 1:Nseg if ~seg(s,8) % if this segment has not been merged newNseg = newNseg+1; % store it in the final list. newseglist(newNseg,:) = seg(s,1:4); end end %---------------------------------------------------------------------- % Internal function that does all the work. % Two segments, that already meet the angle constraint, are tested for end % point proximity. If they meet this constraint they then tested to see % what the maximum line deviation would be if they were merged. If this % is within tolerance they are merged. %---------------------------------------------------------------------- function [newseglist, merged] = compareseg(seg1, seg2, linkrad, linedevtol) s1p1 = seg1(1:2); % point1 of segment1 s1p2 = seg1(3:4); % point2 of segment1 s2p1 = seg2(1:2); % point1 of segment2 s2p2 = seg2(3:4); % point2 of segment2 dir1 = seg1(5:6); dir2 = seg2(5:6); cosAng = dot(dir1,dir2); if cosAng < 0 % Reverse order of points on seg2 so that both % segments are in the `same' direction tmp = s2p1; s2p1 = s2p2; s2p2 = tmp; end merged = 0; % Default result: not merged newseglist = [seg1; seg2]; % and segments left unchanged if norm(s1p2-s2p1) < linkrad % If we satisfy endpoint proximity rc = [s1p1; s1p2; s2p1; s2p2]; [maxdev, index, D] = maxlinedev(rc(:,1),rc(:,2)); % test line deviation if maxdev < linedevtol newseglist = [s1p1 s2p2]; % Merge the segments one way merged = 1; end elseif norm(s2p2-s1p1) < linkrad rc = [s2p1; s2p2; s1p1; s1p2]; [maxdev, index, D] = maxlinedev(rc(:,1),rc(:,2)); if maxdev < linedevtol newseglist = [s2p1 s1p2]; % ... or merge the other way. merged = 1; end end