How can I calculate the unique centroids along with its radius range ?
3 views (last 30 days)
Show older comments
Suppose I've centroid coordinates stored in text files, and I extracted those coordinates and stored them in auxillary arrays. For example, the centroids are like these : (Also the Threshold = 2 and Radius range =4:10 )
1st array has centroids (radius 4) - 34.00 26.00
36.00 21.00
2nd array has centroids (radius 5) - 40.81 36.13
58.50 54.00
3rd array has centroids (radius 6) - 24.50 49.75
40.82 35.91
40.62 10.56
57.14 50.00
4th array has centroids (radius 7) - 24.00 49.00
40.73 35.94
40.75 10.75
5th array has centroids (radisu 8) - 40.86 35.69
6th array has centroids (radius 9) - 40.78 35.39
7th array has centroids (radius 10) - 40.71 35.20
Now, first all the centroids at every array are marked un-visited which is 0. Now we start with 1st centroid of 1st array (34.00 26.00) and checks it with other centroids from 2nd, 3rd, 4th, 5th, 6th, 7th array. The matched ones(i.e., if the distance between current centroid and other centroid is less than equal to the threshold) gets into a buffer array and the average of them are calculated and put into the text file, if no matches are found append the current centroid directly to the text file. Also, the matched centroids from every array are marked visited are turned 1. Then I move to next element (36.00 21.00) of 1st array and started checking with centroids from 2nd, 3rd, 4th, 5th, 6th, 7th array but couldn't found any matches. So, it's appended as it is in the text file. Next, I went to 2nd array and started comparing (40.81 36.13) with the un-visited centroids left in 3rd, 4th, 5th, 6th and 7th array. If found any matches put them in a buffer (for this case now the buffer wiil have - {40.81 36.13},{40.82 35.91},{40.73 35.95},{40.86 35.69},{40.78 35.39},{40.71 35.20}) calculate the average of them (for this case the average of them is coming out (40.78 35.71) and put them in the text file. Likewise, the average values that gets into the text file are called the unique centroids.
Also, I want the radius range along with the unique centroids in the text file. So, the 1st centroid of 1st array hasn't found any matches within 2nd,3rd,4th,5th,6th or 7th array. So the radius range will be 4 - 5, because the centroid belongs to radius 4 and since it has no matches so (current radius of the centroid +1). Also, for the 1st centroid of 2nd array has many matches, so its radius range is 5 - 11, becasue the centroid (40.81 36.13) belongs to radius 5 and since it has found matches upto the last array, i.e., 7th array which has the radius 10, so (last checked array radius +1).
So, my desired output coming for the above provided input of centroid arrays:
34.00 26.00 | 4 - 5
36.00 21.00 | 4 - 5
40.78 35.71 | 5 - 11
58.50 54.00 | 5 - 6
24.25 49.37 | 6 - 8
40.68 10.65 | 6 - 8
57.14 50.00 | 6 - 7
I've tried writtinf the code for the above explained logic, but I think there's some error in the logic.Here is the whole code:-
function step_stdA
centroidFiles = {'centroids1.txt','centroids2.txt','centroids3.txt','centroids4.txt','centroids5.txt','centroids6.txt','centroids7.txt'};
threshold = 2;
radiusRange = 4:10;
unique_centroids_A(centroidFiles, threshold,radiusRange);
end
function unique_centroids_A(centroidFiles, threshold,radiusRange)
% Initialize cell arrays to store centroid data and visited flags
centroidsData = cell(1, numel(centroidFiles));
visitedFlags = cell(1, numel(centroidFiles));
% Read centroid data from files and initialize visited flags
for i = 1:numel(centroidFiles)
centroidsData{i} = dlmread(centroidFiles{i}, ' ', 1, 1); % Read data
numCentroids = size(centroidsData{i}, 1);
visitedFlags{i} = zeros(numCentroids, 1);
end
uniqueCentroidsAll = cell(1, numel(centroidFiles));
for i = 1:numel(centroidFiles)
currentCentroids = centroidsData(i:end-1);
subsequentArrays = centroidsData(i+1:end);
uniqueCentroidsAll{i} = processCentroids(currentCentroids, subsequentArrays, threshold, visitedFlags, radiusRange);
end
fid = fopen('unique_centroids_A.txt', 'w');
for i = 1:numel(uniqueCentroidsAll)
uniqueCentroids = uniqueCentroidsAll{i};
for j = 1:size(uniqueCentroids, 1)
fprintf(fid, '%.2f %.2f | %d - %d\n', uniqueCentroids(j, 1), uniqueCentroids(j, 2));
end
end
fclose(fid);
end
function uniqueCentroids = processCentroids(currentCentroids, centroidsArray, threshold, visitedFlags,radiusRange)
buffer = [];
radiusRanges = zeros(size(currentCentroids, 1), 1);
order = [];
for j = 1:size(currentCentroids, 1)
currentCentroid = currentCentroids(j, :); % jth row of the current array
matches = [];
for k = 1:length(centroidsArray)
otherCentroids = centroidsArray{k};
otherRadius = radiusRange(k);
otherVisitedFlags = visitedFlags{k};
for m = 1:size(otherCentroids, 1)
if otherVisitedFlags(m) == 0
otherCentroid = otherCentroids(m, :);
distance = norm(currentCentroid - otherCentroid);
if distance <= threshold
matches = [matches; otherCentroid];
otherVisitedFlags(m) = 1; % Mark as visited
end
end
end
visitedFlags{k} = otherVisitedFlags; % Update visited flags
end
if ~isempty(matches)
averageCentroid = mean(matches);
buffer = [buffer; averageCentroid]; % Add current centroid if matches found
maxRadius = max(matches(:, 3)); % Get the maximum radius from matches
radiusRanges(j) = maxRadius; % Set radius range to maximum radius
else
buffer = [buffer; currentCentroid]; % Add current centroid if no matches found
end
% Store the order of appearance
order = [order; j];
end
% Remove duplicate centroids, if any
[~, uniqueIdx, ~] = unique(buffer, 'rows', 'stable');
uniqueCentroids = buffer(uniqueIdx, :);
% Sort unique centroids based on the order of appearance
[~, sortedOrder] = sort(order);
uniqueCentroids = uniqueCentroids(sortedOrder, :);
% Combine unique centroids with corresponding radius ranges
uniqueCentroids = [uniqueCentroids, radiusRanges];
end
It's highly appreciatable if you could come up with some help, I'm stuck with this problem for more than 2 weeks.
6 Comments
Accepted Answer
Matt J
on 18 Feb 2024
Edited: Matt J
on 18 Feb 2024
load data; threshold=2; %Example input
T=sortrows(table(Centroid, Radius),2)
Centroid=T.Centroid; Radius=T.Radius;
D=pdist2(Centroid,Centroid)<threshold;
G=findgroups(Radius);
N=histcounts(G,1:max(G)+1);
D=D&(1:width(D)>repelem(cumsum(N)',N)); %Block uppper-triangular mask
uniqueCentroid=(D*Centroid)./sum(D,2);
maxRad=max(Radius(:).'.*D,[],2);
nomatch=~any(D,2);
uniqueCentroid(nomatch,:)=Centroid(nomatch,:);
maxRad(nomatch,:)=Radius(nomatch,:);
result=table(uniqueCentroid,[Radius,maxRad+1],'Var',["Unique Centroids","Range"])
6 Comments
Matt J
on 18 Feb 2024
Edited: Matt J
on 18 Feb 2024
load data; threshold=2; %Example input
T=sortrows(table(Centroid, Radius),2);
D=pdist2(T.Centroid,T.Centroid)<threshold;
G=findgroups(T.Radius);
N=histcounts(G,1:max(G)+1);
D=D&(1:width(D)>repelem(cumsum(N)',N)); %Block uppper-triangular mask
Gr=digraph(D); Gr.Nodes=T;
T=parseGraph(Gr)
function T=parseGraph(Gr)
Centroid=Gr.Nodes.Centroid; Radius=Gr.Nodes.Radius;
buffer=[1;successors(Gr,1)];
maxrad=max(Radius(buffer))+1;
avgcentroid=mean(Centroid(buffer,:),1);
T=table(avgcentroid, [Radius(1), maxrad],'Var', ["Unique Centroids","Range"]);
Gr=rmnode(Gr,buffer);
if numnodes(Gr)==0
return
else
T=[T;parseGraph(Gr)];
end
end
More Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!