@@ -4,6 +4,9 @@
% figure
% imshow(fil)
% hold on
all_x_prom = zeros(size(vein_img));
all_y_prom = zeros(size(vein_img));

for i = 1:size(fil,1)
if (isOctave)
data = cpp_smooth(fil(i,:),2);
@@ -21,26 +24,42 @@

if(numel(imin) > 0)
vein_img(sub2ind(size(vein_img), y(:), imin(:))) = 1;

for promLoc = 1:length(imin)
all_x_prom(y(promLoc), imin(promLoc)) = prominences(promLoc);
end

end
end

for i = 1:size(fil,2)
if (isOctave)
data = cpp_smooth(fil(:,i), 4);
else
data = smooth(fil(:,i),4);
end
data_inv = 1.01*max(data) - data;
[~, imin] = findpeaks(data_inv);

x_len = length(imin);
x = ones(1,x_len) * i;

% for i = 1:size(fil,2)
% if (isOctave)
% data = cpp_smooth(fil(:,i), 4);
% else
% data = smooth(fil(:,i),4);
% end
% data_inv = 1.01*max(data) - data;
% [~, imin, widths, prominences] = findpeaks(data_inv);
%
% x_len = length(imin);
% x = ones(1,x_len) * i;
%
% plot(x,imin,'g*', 'markers',1)

if(numel(imin) > 0)
vein_img(sub2ind(size(vein_img), imin(:), x(:))) = 1;
end
end

%
% if(numel(imin) > 0)
% vein_img(sub2ind(size(vein_img), imin(:), x(:))) = 1;
%
% for promLoc = 1:length(imin)
% all_y_prom(imin(promLoc), x(promLoc)) = prominences(promLoc);
% end
% end
% end

if(~isOctave)
figure;
imagesc(all_x_prom,[min(min(all_x_prom(all_x_prom > 0))) max(max(all_x_prom))]); colormap(jet);
end
% imagesc(all_y_prom,[min(min(all_y_prom(all_y_prom > 0))) max(max(all_y_prom))]); colormap(jet);

% disp('finished')
end
@@ -0,0 +1,377 @@
function [d_min, varargout] = p_poly_dist(xp, yp, xv, yv, varargin)
%**************************************************************************
%p_poly_dist Find minimum distances from points to a polyline or to a
% closed polygon.
%
% Description:
% Compute the distances from each one of a set of np points p(1), p(2),...
% p(np) on a 2D plane to a polyline or a closed polygon. Polyline is
% defined as a set of nv-1 segments connecting nv ordered vertices v(1),
% v(2), ..., v(nv). The polyline can optionally be treated as a closed
% polygon.
% Distance from point j to a segment k is defined as a distance from this
% point to a straight line passing through vertices v(k) and v(k+1), when
% the projection of point j on this line falls INSIDE segment k; and to
% the closest of v(k) or v(k+1) vertices, when the projection falls OUTSIDE
% segment k. Distance from point j to a polyline is defined as a minimum of
% this point's distances to all segments.
% In a case when the projected point fall OUTSIDE of all polyline segments,
% the distance to a closest vertex of the polyline is returned
%
% Input arguments:
% Required:
% [d_min, varargout] = p_poly_dist(xp, yp, xv, yv)
% xp - vector of points X coordinates (1 X np)
% yp - vector of points Y coordinates (1 X np)
% xv - vector of polygon vertices' X coordinates (1 X nv)
% yv - vector of polygon vertices' Y coordinates (1 X nv)
%
% Optional:
% [d_min, varargout] = p_poly_dist(xp, yp, xv, yv, find_in_out)
%
% find_in_out - logical flag. When true, the polyline is treated as a
% closed polygon, and each input point is checked wether it is inside or
% outside of this polygon. In such case, an open polyline is automatically
% closed by adding a last point identical to a first one.
% Note: when this function is called with ver. 1.0 signature, i.e:
% d = p_poly_dist(xp, yp, xv, yv)
% the flag find_in_out is assumed to be true, to keep the functionality
% compatible with a previous version.
%
% Output arguments:
% Required:
% d_min = p_poly_dist(xp, yp, xv, yv, varargin)
%
% d_min - vector of distances (1 X np) from points to polyline. This is
% defined as either a distance from a point to it's projection on a line
% that passes through a pair of consecutive polyline vertices, when this
% projection falls inside a segment; or as a distance from a point to a
% closest vertex, when the projection falls outside of a segment. When
% find_in_out input flag is true, the polyline is assumed to be a closed
% polygon, and distances of points INSIDE this polygon are defined as
% negative.
%
% Optional:
% [d_min, x_d_min, y_d_min, is_vertex, xc, yc, idx_c, Cer, Ppr] =
% p_poly_dist(xp, yp, xv, yv, varargin);
%
% x_d_min - vector (1 X np) of X coordinates of the closest points of
% polyline.
%
% y_d_min - vector (1 X np) of Y coordinates of the closest points of
% polyline.
%
% is_vertex - logical vector (1 X np). If is_vertex(j)==true, the closest
% polyline point to a point (xp(j), yp(j)) is a vertex. Otherwise, this
% point is a projection on polyline's segment.
%
% idx_c - vector (1 X np) of indices of segments that contain the closest
% point. For instance, idx_c(2) == 4 means that the polyline point closest
% to point 2 belongs to segment 4
%
% xc - an array (np X nv-1) containing X coordinates of all projected
% points. xc(j,k) is an X coordinate of a projection of point j on a
% segment k
%
% yc - an array (np X nv-1) containing Y coordinates of all projected
% points. yc(j,k) is Y coordinate of a projection of point j on a
% segment k
%
% is_in_seg - logical array (np X nv-1). If is_in_seg(j,k) == true, the
% projected point j with coordinates (xc(j,k), yc(j,k)) lies INSIDE the
% segment k
%
% Cer - a 3D array (2 X 2 X nv-1). Each 2 X 2 slice represents a rotation
% matrix from an input Cartesian coordinate system to a system defined
% by polyline segments.
%
% Ppr - 3D array of size 2 X np X (nv-1). Ppr(1,j,k) is an X coordinate
% of point j in coordinate systems defined by segment k. Ppr(2,j,k) is its
% Y coordinate.
%
% Routines: p_poly_dist.m
% Revision history:
% Oct 2, 2015 - version 2.0 (Michael Yoshpe). The original ver. 1.0
% function was completely redesigned. The main changes introduced in
% ver. 2.0:
% 1. Distances to polyline (instead of a closed polygon in ver. 1.0) are
% returned. The polyline can optionally be treated as a closed polygon.
% 2. Distances from multiple points to the same polyline can be found
% 3. The algorithm for finding the closest points is now based on
% coordinate system transformation. The new algorithm avoids numerical
% problems that ver. 1.0 algorithm could experience in "ill-conditioned"
% cases.
% 4. Many optional output variables were added. In particular, the closest
% points on polyline can be returned.
% 5. Added input validity checks
% 7/9/2006 - case when all projections are outside of polygon ribs
% 23/5/2004 - created by Michael Yoshpe
% Remarks:
%**************************************************************************

find_in_out = false;

if(nargin >= 5)
find_in_out = varargin{1};
elseif((nargin==4) && (nargout==1)) % mimic ver. 1.0 functionality
find_in_out = true;
end

% number of points and number of vertices in polyline
nv = length(xv);
np = length(xp);

if(nv < 2)
error('Polyline must have at least 2 vertices');
end

if((find_in_out == true) && (nv < 3))
error('Polygon must have at least 3 vertices');
end

% if finding wether the points are inside or outsite the polygon is
% required, make sure the verices represent a closed polygon
if(find_in_out)
% If (xv,yv) is not closed, close it.
nv = length(xv);
if ((xv(1) ~= xv(nv)) || (yv(1) ~= yv(nv)))
xv = [xv(:)' xv(1)];
yv = [yv(:)' yv(1)];
nv = nv + 1;
end
end

% Cartesian coordinates of the polyline vertices
Pv = [xv(:) yv(:)];

% Cartesian coordinates of the given points
Pp = [xp(:) yp(:)];

% matrix of distances between all points and all vertices
% dpv(j,k) - distance from point j to vertex k
dpv(:,:) = hypot((repmat(Pv(:,1)', [np 1])-repmat(Pp(:,1), [1 nv])),...
(repmat(Pv(:,2)', [np 1])-repmat(Pp(:,2), [1 nv])));

% Find the vector of minimum distances to vertices.
[dpv_min, I_dpv_min] = min(abs(dpv),[],2);

% coordinates of consecutive vertices
P1 = Pv(1:(end-1),:);
P2 = Pv(2:end,:);
dv = P2 - P1;

% vector of distances between each pair of consecutive vertices
vds = hypot(dv(:,1), dv(:,2));

% check for identical points
idx = find(vds < 10*eps);
if(~isempty(idx))
error(['Points ' num2str(idx) ' of the polyline are identical']);
end

% check for a case when closed polygon's vertices lie on a stright line,
% i.e. the distance between the last and first vertices is equal to the sum
% of all segments except the last
if(find_in_out)
s = cumsum(vds);
if((s(end-1) - vds(end)) < 10*eps)
error('Polygon vertices should not lie on a straight line');
end
end

% Each pair of consecutive vertices P1(j), P2(j) defines a rotated
% coordinate system with origin at P1(j), and x axis along the vector
% (P2(j)-P1(j)).
% Build the rotation matrix Cer from original to rotated system
ctheta = dv(:,1)./vds;
stheta = dv(:,2)./vds;
Cer = zeros(2,2,nv-1);
Cer(1,1,:) = ctheta;
Cer(1,2,:) = stheta;
Cer(2,1,:) = -stheta;
Cer(2,2,:) = ctheta;

% Build the origin translation vector P1r in rotated frame by rotating the
% P1 vector
P1r = [(ctheta.*P1(:,1) + stheta.*P1(:,2)),...
-stheta.*P1(:,1) + ctheta.*P1(:,2)];

Cer21 = zeros(2, nv-1);
Cer22 = zeros(2, nv-1);

Cer21(:,:) = Cer(1,:,:);
Cer22(:,:) = Cer(2,:,:);

% Ppr is a 3D array of size 2 * np * (nv-1). Ppr(1,j,k) is an X coordinate
% of point j in coordinate systems defined by segment k. Ppr(2,j,k) is its
% Y coordinate.

% Rotation. Doing it manually, since Matlab cannot multiply 2D slices of ND
% arrays.
Ppr(1,:,:) = Pp*Cer21;
Ppr(2,:,:) = Pp*Cer22;

% translation
Ppr(1,:,:) = Ppr(1,:,:) - permute(repmat(P1r(:,1), [1 1 np]), [2 3 1]);
Ppr(2,:,:) = Ppr(2,:,:) - permute(repmat(P1r(:,2), [1 1 np]), [2 3 1]);

% Pcr is a 3D array of size 2 * np * (nv-1) that holds the projections of
% points on X axis of rotated coordinate systems. Pcr(1,j,k) is an X
% coordinate of point j in coordinate systems defined by segment k.
% Pcr(2,j,k) is its Y coordinate, which is identically zero for projected
% point.
Pcr = zeros(size(Ppr));
Pcr(1, :, :) = Ppr(1,:,:);
Pcr(2, :, :) = 0;

% Cre is a rotation matrix from rotated to original system
Cre = permute(Cer, [2 1 3]);

% Pce is a 3D array of size 2 * np * (nv-1) that holds the projections of
% points on a segment in original coordinate systems. Pce(1,j,k) is an X
% coordinate of the projection of point j on segment k.
% Pce(2,j,k) is its Y coordinate
Pce = zeros(2,np,(nv-1));
Pce(1,:,:) = Pcr(1,:,:).*repmat(Cre(1,1,:), [1 np 1]) + ...
Pcr(2,:,:).*repmat(Cre(1,2,:), [1 np 1]);
Pce(2,:,:) = Pcr(1,:,:).*repmat(Cre(2,1,:), [1 np 1]) + ...
Pcr(2,:,:).*repmat(Cre(2,2,:), [1 np 1]);

% Adding the P1 vector
Pce(1,:,:) = Pce(1,:,:) + permute(repmat(P1(:,1), [1 1 np]), [2 3 1]);
Pce(2,:,:) = Pce(2,:,:) + permute(repmat(P1(:,2), [1 1 np]), [2 3 1]);

% x and y coordinates of the projected (cross-over) points in original
% coordinate frame
xc = zeros(np, (nv-1));
yc = zeros(np, (nv-1));
xc(:,:) = Pce(1,:,:);
yc(:,:) = Pce(2,:,:);

r = zeros(np,(nv-1));
cr = zeros(np,(nv-1));
r(:,:) = Ppr(1,:,:);
cr(:,:) = Ppr(2,:,:);

% Find the projections that fall inside the segments
is_in_seg = (r>0) & (r<repmat(vds(:)', [np 1 1]));

% find the minimum distances from points to their projections that fall
% inside the segments (note, that for some points these might not exist,
% which means that closest points are vertices)
B = NaN(np,nv-1);
B(is_in_seg) = cr(is_in_seg);

[cr_min, I_cr_min] = min(abs(B),[],2);

% Build the logical index which is true for members that are vertices,
% false otherwise. Case of NaN in cr_min means that projected point falls
% outside of a segment, so in such case the closest point is vertex.

% point's projection falls outside of ALL segments
cond1 = isnan(cr_min);

% point's projection falls inside some segments, find segments for which
% the minimum distance to vertex is smaller than to projection
cond2 = ((I_cr_min ~= I_dpv_min) & (cr_min - dpv_min)> 0);

is_vertex = (cond1 | cond2);

% build the minimum distances vector
d_min = cr_min;
d_min(is_vertex) = dpv_min(is_vertex);

% mimic the functionality of ver. 1.0 - make all distances negative for
% points INSIDE the polygon
if(find_in_out)
in = inpolygon(xp, yp, xv, yv);
d_min(in) = -d_min(in);
end

% initialize the vectors of minimum distances to the closest vertices
nz = max(np, nv);

vtmp = zeros(nz, 1);
vtmp(1:nv) = xv(:);
x_d_min = vtmp(I_dpv_min);

vtmp = zeros(nz, 1);
vtmp(1:nv) = yv(:);
y_d_min = vtmp(I_dpv_min);

% replace the minimum distances with those to projected points that fall
% inside the segments
idx_pr = sub2ind(size(xc), find(~is_vertex), I_cr_min(~is_vertex));
x_d_min(~is_vertex) = xc(idx_pr);
y_d_min(~is_vertex) = yc(idx_pr);

% find the indices of segments that contain the closest points
% note that I_dpv_min contains indices of closest POINTS. To find the
% indices of closest SEGMENTS, we have to substract 1
idx_c = I_dpv_min-1;
[ii,jj] = ind2sub(size(xc), idx_pr);
idx_c(ii) = jj;

% assign optional outputs
switch nargout
case 0
case 1
case 2
varargout{1} = x_d_min;
case 3
varargout{1} = x_d_min;
varargout{2} = y_d_min;
case 4
varargout{1} = x_d_min;
varargout{2} = y_d_min;
varargout{3} = is_vertex;
case 5
varargout{1} = x_d_min;
varargout{2} = y_d_min;
varargout{3} = is_vertex;
varargout{4} = idx_c;
case 6
varargout{1} = x_d_min;
varargout{2} = y_d_min;
varargout{3} = is_vertex;
varargout{4} = idx_c;
varargout{5} = xc;
case 7
varargout{1} = x_d_min;
varargout{2} = y_d_min;
varargout{3} = is_vertex;
varargout{4} = idx_c;
varargout{5} = xc;
varargout{6} = yc;
case 8
varargout{1} = x_d_min;
varargout{2} = y_d_min;
varargout{3} = is_vertex;
varargout{4} = idx_c;
varargout{5} = xc;
varargout{6} = yc;
varargout{7} = is_in_seg;
case 9
varargout{1} = x_d_min;
varargout{2} = y_d_min;
varargout{3} = is_vertex;
varargout{4} = idx_c;
varargout{5} = xc;
varargout{6} = yc;
varargout{7} = is_in_seg;
varargout{8} = Cer;
case 10
varargout{1} = x_d_min;
varargout{2} = y_d_min;
varargout{3} = is_vertex;
varargout{4} = idx_c;
varargout{5} = xc;
varargout{6} = yc;
varargout{7} = is_in_seg;
varargout{8} = Cer;
varargout{9} = Ppr;
otherwise
error('Invalid number of output arguments, must be between 1 and 9');
end

end
@@ -0,0 +1,235 @@
function [d_min, xc_is, yc_is, idxc_is, is_vertex] = poly_poly_dist(xv1, yv1, xv2, yv2)
%poly_poly_dist Find minimum distance between two polylines.
%
% Description:
% Polyline is defined as a set of nv-1 segments connecting nv ordered
% vertices v(1), v(2), ..., v(nv).
% Distance between 2 non-intersecting polylines poly1 and poly2 is defined
% as a minimum of distances of poly1 vertices to poly2 segments, or poly2
% segments to poly1 vertices.
% If polylines intersect, the distance is set to zero, and the coordinates
% of intersection points are returned.
%
% Input arguments:
% xv1 - vector of X coordinates of the first polyline vertices (1 X nv1)
% yv1 - vector of Y coordinates of the first polyline vertices (1 X nv1)
% xv2 - vector of X coordinates of the second polyline vertices (1 X nv2)
% yv2 - vector of Y coordinates of the second polyline vertices (1 X nv2)
%
%
% Output arguments:
%
% d_min - distance between 2 polyline (scalar). If polylines interesect,
% d_min is set to zero
%
% xc_is - X coordinates of closest points (nc_is X 2), where nc_is is a
% number of closest or intersection points. nc_is can be greater than 1 in
% case when there are more than 1 points with SAME minimum distance.
% xc_is(:,1)contains X coordinates of closest or intersection points
% belonging to the first polyline, xc_is(:,2) - to the second polyline. If
% polylines intersect (d_min==0), xc_is contains the coordinates of
% intersection points, and xc_is(:,1) = xc_is(:,2).
%
% yc_is - Y coordinates of closest or intersection points (nc_is X 2)
%
% idxc_is - indices of polyline segments that contain the closest or
% interesection points (nc_is X 2). idxc_is(:,1) contains the indices of
% first polyline's segments, idxc_is(:,2) - of second polyline's segments.
%
% is_vertex - logical array (nc_is X 2). If is_vertex(j,1) is true, the
% closest or intersection point j that belongs to poly1 is a vertex. If
% is_vertex(j,2) is true, the closest or intersection point j that belongs
% to poly2 is a vertex
%
% Revision history:
% Oct 28, 2015 - Created (Michael Yoshpe).
%**************************************************************************

% some inputs sanity checks
nv1 = length(xv1);
nv2 = length(xv2);

if(nv1 < 2)
error('Polyline 1 must have at least 2 vertices');
end

if(nv2 < 2)
error('Polyline 2 must have at least 2 vertices');
end

% number of vertices in each polyline
xmin1 = min(xv1);
xmax1 = max(xv1);

ymin1 = min(yv1);
ymax1 = max(yv1);

xmin2 = min(xv2);
xmax2 = max(xv2);

ymin2 = min(yv2);
ymax2 = max(yv2);

% distance from vertices of poly1 to segments or vertices of poly 2
[d_min12, x_d_min12, y_d_min12, is_vertex12, idx_c12, xc12, yc12, is_in_seg12, Cer12, Ppr12] = ...
p_poly_dist(xv1, yv1, xv2, yv2, false);

% crude test for intersection of polylines
if((xmax1 < xmin2) | (xmin1 > xmax2) | (ymax1 < ymin2) | (ymin1 > ymax2))
% polylines definitely don't intersect, set intersection flag to false
is_flag = false;
else
% polyline could still intersect, check for possible intersection
% points of poly1 in rotated coordinate systems defined by segments of
% poly2
xpr = zeros(nv1, (nv2-1));
ypr = zeros(nv1, (nv2-1));
xpr(:,:) = Ppr12(1,:,:);
ypr(:,:) = Ppr12(2,:,:);
idx_is = (sign(ypr(1:(end-1),:)) ~= sign(ypr(2:end,:)));

if(any(any(idx_is)))
% some vertices of poly1 have opposite Y coordinates, when
% transformed to coordinate systems defined by segments of poly2
% Continue checking for intersection
[ii1, jj1] = find(idx_is);
idxl1 = sub2ind(size(ypr), ii1, jj1);
idxl2 = sub2ind(size(ypr), ii1+1, jj1);

% x coordinates of a lines connecting poly1 vertices in rotated
% system. To intersect, they should fall WITHIN poly2 segments
xr_is = (xpr(idxl1).*ypr(idxl2) - xpr(idxl2).*ypr(idxl1))./(ypr(idxl2) - ypr(idxl1));

% poly2 segments lengths
vds_is2 = hypot((xv2(jj1+1)-xv2(jj1)), (yv2(jj1+1)-yv2(jj1)));
ii_is = find((xr_is >= 0) & (xr_is(:) <= vds_is2(:)));

if(~isempty(ii_is)) % intersection points found
is_flag = true;
n_is = length(ii_is); % number of segments intersections
% Polylines definitely interesect, since some segments of
% poly1 cross segments of poly2. Translate the intersection
% points into original coordinate system

Pcr = zeros([2 n_is]);
Pcr(1, :) = xr_is(ii_is);
Pcr(2, :) = 0;

% Cre is a rotation matrix from rotated to original system
Cre = permute(Cer12(:,:,jj1(ii_is)), [2 1 3]);

Cre1 = zeros(2, n_is);
Cre2 = zeros(2, n_is);

Cre1(:,:) = Cre(1, :, :);
Cre2(:,:) = Cre(2, :, :);

% coordinates of consecutive vertices
P1 = [xv2(:) yv2(:)];

% Pce is a 2D array of size 2 * n_is that holds the coordinates of
% intersection points in original coordinate systems. Pce(1,j) is
% an X coordinate of the intersection of point, Pce(2,j) is its
% Y coordinate
Pce = zeros(2, n_is);

Pce(1,:) = Cre1(1,:).*Pcr(1,:) + Cre1(2,:).*Pcr(2,:);
Pce(2,:) = Cre2(1,:).*Pcr(1,:) + Cre2(2,:).*Pcr(2,:);

% Adding the P1 vector
Pce(1,:) = Pce(1,:) + P1(jj1(ii_is),1)';
Pce(2,:) = Pce(2,:) + P1(jj1(ii_is),2)';

% x and y coordinates of the projected (cross-over) points in
% original coordinate frame
d_min = 0;
xc_is = zeros(n_is, 2);
yc_is = zeros(n_is, 2);
xc_is(:,1) = Pce(1,:);
xc_is(:,2) = Pce(1,:);
yc_is(:,1) = Pce(2,:);
yc_is(:,2) = Pce(2,:);
idxc_is = [ii1(ii_is) jj1(ii_is)];

% If polylines intersect, intersection points are most often lie
% INSIDE segments, initialize is_vertex to false
is_vertex = false(n_is, 2);

% check for corner cases, where polylines intersect at vertices

% check if interesection points are close to poly1 vertices
cond_poly1 = ((abs(xv1(idxc_is(:,1))'-xc_is(:,1)) < 5*eps) & ...
(abs(yv1(idxc_is(:,1))'-yc_is(:,1)) < 5*eps)) | ...
((abs(xv1(idxc_is(:,1)+1)'-xc_is(:,1)) < 5*eps) & ...
(abs(yv1(idxc_is(:,1)+1)'-yc_is(:,1)) < 5*eps));

% check if interesection points are close to poly2 vertices
cond_poly2 = (Pcr(1, :) < 10*eps) | (Pcr(1, :) > vds_is2(ii_is)-10*eps);

is_vertex(:, 1) = cond_poly1;
is_vertex(:, 2) = cond_poly2;
else
% polylines don't interesect
is_flag = false;
end
else
% polylines don't interesect
is_flag = false;
end


end

% Plylines don't intersect, find the minimum distance
if(~is_flag)
% distance from vertices of poly1 to segments or vertices of poly2
[d_min21, x_d_min21, y_d_min21, is_vertex21, idx_c21, xc21, yc21, is_in_seg21, Cer21, Ppr21] = ...
p_poly_dist(xv2, yv2, xv1, yv1, false);

% find minimum distance
[dm12, im12] = min(d_min12);
[dm21, im21] = min(d_min21);

[d_min, imj] = min([dm12, dm21]);

% find closest points (could be more than 1 for each polyline, with same
% distance)
im1 = find(abs(d_min12-d_min)<5*eps);
im2 = find(abs(d_min21-d_min)<5*eps);

xc_is1 = [x_d_min21(im2) xv2(im2)';...
xv1(im1)' x_d_min12(im1)];

yc_is1 = [y_d_min21(im2) yv2(im2)';...
yv1(im1)' y_d_min12(im1)];

% note that im1 and im2 are indices of closest POINTS. To find the
% indices of closest SEGMENTS, we have to substract 1
im1s = im1;
im2s = im2;

if(~isempty(im1))
im1s = im1 - 1;
end

if(~isempty(im2))
im2s = im2 - 1;
end

idxc_is1 = [idx_c21(im2) im2s;...
im1s idx_c12(im1)];

% remove possible duplicates
[idxc_is, ia, ic] = unique(idxc_is1, 'rows');

xc_is = xc_is1(ia,:);
yc_is = yc_is1(ia,:);

is_vertex1 = [is_vertex21(im2) true(length(im2),1);
true(length(im1),1) is_vertex12(im1)];

is_vertex = is_vertex1(ia, :);

end

end