How calculate fiber length - computer-vision

I need help calculating fiber length. I found all the coordinate values of center line of fiber by using regional maximal of euclidean distance. Here is the image that I got after applying regional maximal of euclidean distance. Now I want to draw a line on each fiber by using these points how can I do that so that I can extract each fiber length automatically. I tried to do it by using spline curve fitting. But the problem is I was not able to initiate the starting and ending point of fiber. How can I calculate each fiber length?
close all;
clear all;
clc
ima=imread('ecm61.png');
ima=bwareaopen(ima,50);
[rowsInImage,columnImage]=size(ima);
skel= bwmorph(ima,'skel',Inf);
figure
imshow(skel)
B = bwmorph(skel, 'branchpoints');
E = bwmorph(skel, 'endpoints');
[x,y] = find(E);
%plot(x,y,'+')
B_loc = find(B);
Dmask = false(size(skel));
for k = 1:numel(y)
D = bwdistgeodesic(skel,y(k),x(k));
distanceToBranchPt = min(D(B_loc));
Dmask(D < distanceToBranchPt) =true;
end
skelD = skel - Dmask;
figure
imshow(skelD);
hold all;
[x,y] = find(B); plot(y,x,'ro')
numberOfEndpoints=length(y);
% Label the image. Gives each separate segment a unique ID label number.
[labeledImage, numberOfSegments] = bwlabel(skelD);
fprintf('There are %d endpoints on %d segments.\n', numberOfEndpoints, numberOfSegments);
% Get the label numbers (segment numbers) of every endpoint.
for k = 1 : numberOfEndpoints
thisRow = x(k);
thisColumn = y(k);
%line([endPointRows(k),endPointColumns(k)],[endPointRows(k+1),endPointColumns(k+1)])
% Get the label number of this segment
theLabels(k) = labeledImage(thisRow, thisColumn);
fprintf('Endpoint #%d at (%d, %d) is in segment #%d.\n', k, thisRow, thisColumn, theLabels(k));
end
% For each endpoint, find the closest other endpoint
% that is not in the same segment
for k = 1 : numberOfEndpoints
thisRow = x(k);
thisColumn =y(k);
% Get the label number of this segment
thisLabel = theLabels(k);
otherEndpointIndexes = setdiff(1:numberOfEndpoints, k);
%if mustBeDifferent
% If they want to consider joining only end points that reside on different segments
% then we need to remove the end points on the same segment from the "other" list.
% Get the label numbers of the other end points.
%otherLabels = theLabels(otherEndpointIndexes);
%onSameSegment = (otherLabels == thisLabel); % List of what segments are the same as this segment
%otherEndpointIndexes(onSameSegment) = []; % Remove if on the same segment
%end
% Now get a list of only those end points that are on a different segment.
otherCols = y(otherEndpointIndexes);
otherRows = x(otherEndpointIndexes);
% Compute distances
distances = sqrt((thisColumn - otherCols).^2 + (thisRow - otherRows).^2);
% Find the min
[minDistance, indexOfMin] = min(distances);
nearestX = otherCols(indexOfMin);
nearestY = otherRows(indexOfMin);
%if minDistance < longestGapToClose;
if minDistance < rowsInImage
% Draw line from this endpoint to the other endpoint.
line([thisColumn, nearestX], [thisRow, nearestY], 'Color', 'g', 'LineWidth', 2);
fprintf('Drawing line #%d, %.1f pixels long, from (%d, %d) on segment #%d to (%d, %d) on segment #%d.\n', ...
k, minDistance, thisColumn, thisRow, theLabels(k), nearestX, nearestY, theLabels(indexOfMin));
end
end
title('Endpoints Linked by Green Lines', 'FontSize', 12, 'Interpreter', 'None');
after using edge linking

I would do this:
Skeletonize
Pruning
Find the different path at each intersection. It will give you the different segments, and you can reconnect them using the orientation.

Related

Levenshtein distance with substitution, deletion and insertion count

There's a great blog post here https://davedelong.com/blog/2015/12/01/edit-distance-and-edit-steps/ on Levenshtein distance. I'm trying to implement this to also include counts of subs, dels and ins when returning the Levenshtein distance. Just running a smell check on my algorithm.
def get_levenshtein_w_counts(s1: str, s2: str):
row_dim = len(s1) + 1 # +1 for empty string
height_dim = len(s2) + 1
# tuple = [ins, del, subs]
# Moving across row is insertion
# Moving down column is deletion
# Moving diagonal is sub
matrix = [[[n, 0, 0] for n in range(row_dim)] for m in range(height_dim)]
for i in range(1, height_dim):
matrix[i][0][1] = i
for y in range(1, height_dim):
for x in range(1, row_dim):
left_scores = matrix[y][x - 1].copy()
above_scores = matrix[y - 1][x].copy()
diagonal_scores = matrix[y - 1][x - 1].copy()
scores = [sum_list(left_scores), sum_list(diagonal_scores), sum_list(above_scores)]
min_idx = scores.index(min(scores))
if min_idx == 0:
matrix[y][x] = left_scores
matrix[y][x][0] += 1
elif min_idx == 1:
matrix[y][x] = diagonal_scores
matrix[y][x][2] += (s1[x-1] != s2[y-1])
else:
matrix[y][x] = above_scores
matrix[y][x][1] += 1
return matrix[-1][-1]
So according to the blog post if you make a matrix where the row is the first word + and empty str and the column is the 2nd word plus an empty string. You store the edit distance at each index. Then you get the smallest from the left, above and diagonal. If the min is diagonal then you know you're just adding 1 sub, if the min is from the left then you're just adding 1 insertion. If the min is from above then you're just deleting 1 character.
I think I did something wrong cause get_levenshtein_w_counts("Frank", "Fran") returned [3, 2, 2]
The problem was that Python does address passing for objects so I should be cloning the lists to the variables rather than doing a direct reference.

opencv how to get middle line of a contour

I have an image from which I get the contour of using findContours. This products something that looks like the following: (showing the "inner and outer contour").
Is there a way for me to get the "midpoint" of these two contours? ie some kind of polyline that would fit exactly in between the two lines seen in the image, such that the distance at any point on the resultant time is the same from it to the top contour as is from it to the bottom contour?
More complicated example would be something as follows:
Please note, that it doesnt matter too much what happens at intersections, so long as nothing traces back on itself, so the result of the more complicated example would need multiple lines.
There is a way to get the "midpoint" of the two contours, but I don't think there is an existing OpenCV solution.
You may use the following stages:
Convert image to Grayscale, and apply binary threshold.
You may use cvtColor(... COLOR_BGR2GRAY) and threshold(...) OpenCV functions.
Fill the pixels outsize the area between lines with white color.
You may use floodFill OpenCV function.
Apply "distance transform" to the binary image.
You may use distanceTransform OpenCV function.
Use CV_DIST_L2 for euclidean distance.
Apply Dijkstra's algorithm for finding the shortest paths between most left and most right nodes.
Representing "distance transform" result (image) as weighted graph and applying Dijkstra's algorithm is the most challenging stage.
I implemented the solution in MATLAB.
The MATLAB implemented is used as a "proof of concept".
I know you were expecting C++ implementation, but it requires a lot of work.
The MATLAB implementation uses im2graph function, I downloaded from here.
Here is the MATLAB implementation:
origI = imread('two_contours.png'); % Read input image
I = rgb2gray(origI); % Convert RGB to Grayscale.
BW = imbinarize(I); % Convert from Grayscale to binary image.
% Fill pixels outsize the area between lines.
BW2 = imfill(BW, ([1, size(I,2)/2; size(I,1), size(I,2)/2]));
% Apply "distance transform" (find compute euclidean distance from closest white pixel)
D = bwdist(BW2);
% Mark all pixels outsize the area between lines with zero.
D(BW2 == 1) = 0;
figure;imshow(D, []);impixelinfo % Display D matrix as image
[M, N] = size(D);
% Find starting point and end point - assume we need to find a path from left side to right side.
x0 = 1;
[~, y0] = max(D(:, x0));
x1 = N;
[~, y1] = max(D(:, x1));
% https://www.mathworks.com/matlabcentral/fileexchange/46088-dijkstra-lowest-cost-for-images
StartNode = y0;
EndNode = M*N - (M-y1-1);
conn = 8;%4 or 8 - connected neighborhood for linking pixels
% Use 100 - D, because graphshortestpath searches for minimum weight (and we are looking for maximum weight path).
CostMat = 100 - D;
G = im2graph(CostMat, conn);
%Find "shortest" path from StartNode to EndNode
[dist, path, pred] = graphshortestpath(G, StartNode, EndNode);
% Mark white path in image J image
J = origI;R = J(:,:,1);G = J(:,:,2);B = J(:,:,3);
R(path) = 255;G(path) = 255;B(path) = 255;
J = cat(3, R, G, B);
figure;imshow(J);impixelinfo % Display J image
Result:
D - Result of distance transform:
J - Original image with "path" marked with white color:
Update:
For the new example you can define three paths.
The solution becomes more complicated.
The example is not generalized to solve all the cases.
There must be a simpler solution, I just can't think of one.
tmpI = imread('three_contours.png'); % Read input image
origI = permute(tmpI, [2, 1, 3]); % Transpose image
I = rgb2gray(origI); % Convert RGB to Grayscale.
BW = imbinarize(I); % Convert from Grayscale to binary image.
% Fill pixels outsize the area between lines.
%BW2 = imfill(BW, ([1, size(I,2)/2; size(I,1), size(I,2)/2]));
BW2 = imfill(BW, ([1, 1; size(I,1), size(I,2); size(I,2)/2, 1]));
% Apply "distance transform" (find compute euclidean distance from closest white pixel)
D = bwdist(BW2);
% Mark all pixels outsize the area between lines with zero.
D(BW2 == 1) = 0;
figure;imshow(D, []);impixelinfo % Display D matrix as image
[M, N] = size(D);
% Find starting point and end point - assume we need to find a path from left side to right side.
x0 = 1;
[~, y0a] = max(D(1:M/2, x0));
% Y coordinate of second point
[~, y0b] = max(D(M/2:M, x0));
y0b = y0b + M/2;
x1 = N;
[~, y1] = max(D(:, x1));
% https://www.mathworks.com/matlabcentral/fileexchange/46088-dijkstra-lowest-cost-for-images
StartNodeA = y0a;
StartNodeB = y0b;
EndNode = M*N - (M-y1-1);
conn = 8;%4 or 8 - connected neighborhood for linking pixels
% Use 100 - D, because graphshortestpath searches for minimum weight (and we are looking for maximum weight path).
D(D==0) = -10000; % Increase the "cost" where D is zero
CostMat = 1000 - D;
G = im2graph(CostMat, conn);
%Find "shortest" path from StartNode to EndNode
[dist, pathA, pred] = graphshortestpath(G, StartNodeA, EndNode);
[dist, pathB, pred] = graphshortestpath(G, StartNodeB, EndNode);
[dist, pathC, pred] = graphshortestpath(G, StartNodeA, StartNodeB);
% Mark white path in image J image
J = origI;R = J(:,:,1);G = J(:,:,2);B = J(:,:,3);
R(pathA) = 255;
G(pathB) = 255;
B(pathC) = 255;
J = cat(3, R, G, B);
J = permute(J, [2, 1, 3]); % Transpose image
figure;imshow(J);impixelinfo % Display J image
Three lines:

Why polyxpoly does not work in GNU octave

I want to plot Det curve and roc curve Why polyxpoly does not work?
I plotted a DET curve based on the following steps: First, I changed the threshold and count the number of false rejections and false acceptances. Second, I use plot MATLAB function to draw FAR and FRR.
function [TPR,FPR] = DETCurve(G,I)
#load('G.dat');
#load('I.dat');
#load data from the column 4 fscore
i0=find(Fscore(:,end)==0);
i1=find(Fscore(:,end)==1);
D0=Fscore(i0,end-1);
D1=Fscore(i1,end-1);
% Creates a matrix
TPR = zeros(1, 1000);
FPR = zeros(1, 1000);
#number of positive responses and negative responses in ground truth
P = length(i1);
N = length(i0);
index = 0;
% Assume the threshold as 0.01
for threshold = 0:0.001:1
TP = 0;
FP = 0;
%Provides the D1 count
for i = 1:length(i1)
if (D1(i) >= threshold) TP = TP + 1;
end
end
% Provides the D0count
for i1 = length(i0)
if(D0(i1) >= threshold)
FP = FP + 1;
end
end
index = index + 1;
% Calculating true positive rate
TPR(index) = TP/P;
% Calculating false positive rate
FPR(index) = FP/N;
end
% Calculating false negative rate(FNR) using TPR+FNR=1
FNR = (1-TPR);
x = 0:0.1:1;
y = x;
#[x(i),y(i)] = polyxpoly(x,y,FPR,FNR);
fprintf('EER(X): %d n', x(i));
fprintf('EER(Y): %d n', y(i));
plot(FPR,FNR,'LineWidth',2, 'color','g');
hold on;
plot(x,y,x,1-y, 'color','r');
plot (x(i),y(i),'X','MarkerSize',10, 'LineWidth', 2,'Color','b');
hold off;
title('DET CURVE');
xlabel('False Positive Rate (FPR) ');
ylabel('False Neagtive Rate (FNR) ');
end

Creating Huge Sparse Matrices in python

I have been using normal matrices from numpy to store a Matrix for a physics project. The size of the matrix is determined by the physical system.
So for instance if the system has parameters:
L=4 and N =2, then the matrix is of dimension 4C2 = 6, so the matrix is a 6x6 matrix.
This is fine except for now I need larger size i.e 20C10 = 184,756. So the matrix required is now a 184756x184756 matrix, which when I try to create an empty matrix of this size gives me a memory error. (with 16GB of RAM)
The resultant matrix is mostly just diagonal and off diagonal terms, so there are a huge amount of zeroes in the large size matrices. Hence Sparse Matrices seem like the correct approach.
I have tried to get it to work by looking at other answers and just trying by myself from the python libraries, but to no avail.
Below is the code for my normal matrix:
def HamGen(L,N,delta,J):
"""
Will Generate the hamiltonian matrix,
Takes parameters:
L : Number of sites
N : Number of spin downs
delta : anistropy
Each term is gotten by getting H(i,j) = <Set(i)|H|Set(j)>
The term will be a number
Where H is an operator that acts on elements of the set
"""
D = BS.dimension(L,N) # Gets the dimension of the matrix, i.e NxN matrix
Hamiltonian = np.zeros((D,D)) # Creates empty matrix
count1 = 0
Set = BS.getSet(L,N) # The set of states to construct the hamiltonian
for alpha in Set: #loop through the set (i)
count2 = 0
for beta in Set: # j
"""
Compute ab = <alpha|Hamiltonian|beta>
Then let Hamiltonian[a][b] = ab
"""
if (alpha == beta):
for i in range(L-1):
# Sz is just a function
Hamiltonian[count1][count2] += (J*delta*Sz(beta,i)*Sz(beta,i+1))
b = check(alpha,beta)
if b:
del b[0]
for j in b:
Hamiltonian[count1][count2] += (J*0.5*(Sp(beta,j)*Sm(beta,j+1) + Sm(beta,j)*Sp(beta,j+1)))
count2 += 1
count1 += 1
return (np.asmatrix(Hamiltonian))
I mostly just need to know how to make the matrix without having to use as much memory, and then how to put the terms I calculate into the matrix.
Here is my attempt to make the matrix as a sparse matrix.
def SPHamGen(L,N,delta):
"""
Will Generate the hamiltonian matrix,
Takes parameters:
L : Number of sites
N : Number of spin downs
delta : anistropy
"""
start = timeit.default_timer()
D = BS.dimension(L,N)
Ham = sp.coo_matrix((D,D))
print Ham
#data = ([0])*D
count1 = 0
Set = BS.getSet(L,N)
data = ([0])*(D*D)
rows = ([0])*(D*D)
cols = ([0])*(D*D)
for alpha in Set:
count2 = 0
for beta in Set:
"""
Compute ab = <alpha|Hamiltonian|beta>
Then let Hamiltonian[a][b] = ab
"""
if (alpha == beta):
for i in range(L-1):
#Hamiltonian[count1][count2] += (J*delta*Sz(beta,i)*Sz(beta,i+1))
data[count2] += (J*delta*Sz(beta,i)*Sz(beta,i+1))
rows[count2] = count1
cols[count2] = count2
b = check(alpha,beta)
if b:
del b[0]
for j in b:
#Hamiltonian[count1][count2] += (J*0.5*(Sp(beta,j)*Sm(beta,j+1) + Sm(beta,j)*Sp(beta,j+1)))
data[count2] += (J*0.5*(Sp(beta,j)*Sm(beta,j+1) + Sm(beta,j)*Sp(beta,j+1)))
rows[count2] = count1
cols[count2] = count2
count2 += 1
count1 += 1
Ham = Ham + sp.coo_matrix((data,(rows,cols)), shape = (D,D))
time = (timeit.default_timer() - start)
print "\n"+str(time) +"s to calculate H"
#return Ham
return sparse.csr_matrix(Ham)
Thanks, Phil.

The process to get a observation signal

First, a small number of active users from a total of K users are set to respectively transmit a frame of convolutionally-encoded binary bits, optionally interleaved, then mapped following the Binary Phase-Shift Keying (BPSK) constellation. Inactive users are set to transmit all-zero frames, thus forming an augmented BPSK constellation {0, ±1}. All frames to be transmitted are then spread using bipolar-valued Pseudo-Noise (PN) spreading sequences before they go through their respective wireless channels (modeled as i.i.d. Rayleigh distributed channels with an exponentially-decaying power delay profile where the expected decay is known). The superposition of these signals through channels is considered to be the observation y the aggregated node or gateway receives
enter code here
%%%%%%%%%
clc
clear
format long;
K=128 ; % the number of users
Ns=K/4; %spreading factor
Lh=6; %channel tap
L=104;
Pactive=0.02; %the active possibility of uers
nTx=K*Pactive;
nBlocks = 10; % number of blocks for each SNR
SNR = 0:5:25; % dB
X_origin=[];
for iSNR = 1:length(SNR)
for iBlock = 1:nBlocks
for i=1:K
r_K=randperm(L);
x=zeros(L,1);
for j=1:nTx
x(r_K(j))=1;
end;
X_origin=[X_origin;x]; % signal vector
end;
inSignals=pskmod(X_origin ,2); %bpsk modulation
cH = RayleighChannel(Ns*L+Lh-1,K*L); %channel matrix
rH = RVD(cH);
cB = cH*inSignals;
cY = awgn(cB,SNR(iSNR),'measured'); % add noise, n~(0,sigma2)
rY = RVD(cY);
spower = mean(abs(cY(:)).^2);
cG = cH'*cH;
rG = rH'*rH;
sigma2 = spower/(10^(SNR(iSNR)/10));
cW = cG+eye(K*L)*sigma2;
rW = RVD(cW);
invW = inv(rW);
rYBar = rH'*rY;
rSHat = invW*rYBar;
A=rH*rSHat;
S= CS_gOMP( rY,A,nTx);
% X_reconstuction=rSHat*X_r;
[~,vBer1(iBlock)] = biterr(X_origin,S);
end;
% ber(iSNR) = mean(vBer);
ber1(iSNR) = mean(vBer1);
SNR(iSNR)
ber1(iSNR)
end;
semilogy( SNR,ber1,'go--');
%set(P1,'Linewidth',[2]);
grid on;
title (['\fontsize{12}\bfCS—MUD :\rm','16-QAM,N=',int2str(K*L),',K=',int2str(K)]);
xlabel ('SNR'); ylabel ('BER');
legend('SMV-CS-MUD');