Scale 2D coordinates with respect to the centroid

조회 수: 16 (최근 30일)
Alberto Acri
Alberto Acri 2023년 1월 3일
댓글: Image Analyst 2023년 1월 8일
I would like to scale, with respect to the centroid, curves_2.txt such that the Y (or X) coordinates of the marked points of curves_2.txt go to coincide with the Y (or X) coordinates of the marked points of curves_1.txt.
For example, in the image below:
  • the point in the green box should go from a value of X=194.887 to X=222
  • the point in the pink box must go from a value of X=320,887 to X=293
  • the point in the blue box must go from a value of Y=372.21 to Y=360
  • the point in the purple box must go from a value of Y=323.21 to Y=333
Is there any way to do this scaling operation (or something similar)? Thanks in advance!
  댓글 수: 3
Matt J
Matt J 2023년 1월 3일
편집: Matt J 2023년 1월 3일
In future, please attach your data in .mat file format, like I have done here, to make downloading easier for us. Notice that all data is in a single .mat file.
Alberto Acri
Alberto Acri 2023년 1월 3일
I edited the post with the data in .mat format.
You can find the coordinates (yellow dots) calculated in the code.
I would like to do a scaling operation so that curve_2 (red) is the same size as curve_1 (black).

댓글을 달려면 로그인하십시오.

채택된 답변

Mathieu NOE
Mathieu NOE 2023년 1월 3일
hello again Alberto
I opted for a simple x, y shrink ratios computation, sufficient to make the red curve match the black one (the new curve is the green one)
I didn't use any of your selected points , I simply used the points with max x and y distance to the centroids
I admit , a very basic approach (no need to worry about centroids shift as they are already overlaid)
load('Curves.mat')
x_curve_1 = sum(curve_1(:,1))/length(curve_1(:,1));
y_curve_1 = sum(curve_1(:,2))/length(curve_1(:,2));
G_curve_1 = [x_curve_1, y_curve_1];
x_curve_2 = sum(curve_2(:,1))/length(curve_2(:,1));
y_curve_2 = sum(curve_2(:,2))/length(curve_2(:,2));
G_curve_2 = [x_curve_2, y_curve_2];
% compute x, y shrink factors based on max ratios
x_factor = max(curve_2(:,1) - G_curve_2(1))./max(curve_1(:,1) - G_curve_1(1));
y_factor = max(curve_2(:,2) - G_curve_2(2))./max(curve_1(:,2) - G_curve_1(2));
x_curve_2new = G_curve_2(1) + (curve_2(:,1) - G_curve_2(1))/x_factor;
y_curve_2new = G_curve_2(2) + (curve_2(:,2) - G_curve_2(2))/y_factor;
figure
plot(curve_1(:,1), curve_1(:,2),'k.', 'MarkerSize', 10);
hold on
plot(curve_2(:,1), curve_2(:,2),'r.', 'MarkerSize', 10);
plot(x_curve_2new, y_curve_2new,'g.', 'MarkerSize', 10);
plot(G_curve_1(:,1), G_curve_1(:,2),'k*', 'MarkerSize', 10);
plot(G_curve_2(:,1), G_curve_2(:,2),'rd', 'MarkerSize', 10);
  댓글 수: 2
Alberto Acri
Alberto Acri 2023년 1월 6일
Hi @Mathieu NOE and thank you for your reply!
In the code you provided is it possible to know the scaling value? That is, by how much did the red curve reduce so that it became the green curve?
Image Analyst
Image Analyst 2023년 1월 6일
@Alberto Acri he used x_factor and y_factor. You could put in any factor youi want. Did you even see my answer below where I changed the size from 0.4 to 1.6?

댓글을 달려면 로그인하십시오.

추가 답변 (2개)

William Rose
William Rose 2023년 1월 3일
Let's call the curves "curve a" and "curve b". You want to map Xa1=194.887 to Xb1=222, and Xa2=320.887 to Xb2=293. Use the transformation Xb = c1 + c2*Xa:
222=c1 + c2*194.887
293=c1 + c2*320.887
which can be written
which is easily solved to get c1 and c2.
c=inv([1,194.887;1,320.887])*[222;293]
c = 2×1
112.1827 0.5635
Likewise, for the y transformation, you want to map Ya1=372.21 to Yb1=360 and Ya2=323.21 to Yb2=333, so you do the transformation Yb = d1 + d2*Ya. You determine d1 and d2 by solving
360=d1 + d2*372.21
333=d1 + d2*323.21
d=inv([1,372.21;1,323.21])*[360;333]
d = 2×1
154.9047 0.5510
Then you use c to transform all the X values from curve a to curve b. You use d to transform the Y values. Good luck!

Image Analyst
Image Analyst 2023년 1월 3일
Try this (Thanks Matt for uploading the mat file):
% Optional initialization steps
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 18;
s = load('Curves.mat')
s = struct with fields:
curve_1: [158×2 double] curve_2: [275×2 double]
x = s.curve_1(:, 1);
y = s.curve_1(:, 2);
plot(x, y, 'b.', 'MarkerSize',14)
binaryImage = false(max(y), max(x));
for k = 1 : length(x)
binaryImage(y(k), x(k)) = true;
end
imshow(binaryImage)
axis xy; % Flip image
% Get distance transform
edtImage = bwdist(binaryImage);
imshow(edtImage, []);
% threshold(1, 4, edtImage)
mask = imfill(edtImage == 1, 'holes');
% Take largest blob
mask = bwareafilt(mask, 1);
% Get edges
% Plot the borders of all the blobs in the overlay above the original grayscale image
% using the coordinates returned by bwboundaries().
imshow(mask);
% bwboundaries() returns a cell array, where each cell contains the row/column coordinates for an object in the image.
% Here is where we actually get the boundaries for each blob.
boundaries = bwboundaries(mask);
% boundaries is a cell array - one cell for each blob.
% In each cell is an N-by-2 list of coordinates in a (row, column) format. Note: NOT (x,y).
% Column 1 is rows, or y. Column 2 is columns, or x.
numberOfBoundaries = size(boundaries, 1); % Count the boundaries so we can use it in our for loop
% Here is where we actually plot the boundaries of each blob in the overlay.
hold on; % Don't let boundaries blow away the displayed image.
for k = 1 : numberOfBoundaries
thisBoundary = boundaries{k}; % Get boundary for this specific blob.
x = thisBoundary(:,2); % Column 2 is the columns, which is x.
y = thisBoundary(:,1); % Column 1 is the rows, which is y.
plot(x, y, 'r-', 'LineWidth', 2); % Plot boundary in red.
end
hold off;
caption = sprintf('%d Outlines, from bwboundaries()', numberOfBoundaries);
fontSize = 15;
title(caption, 'FontSize', fontSize);
axis('on', 'xy'); % Make sure image is not artificially stretched because of screen's aspect ratio.
% Find centroid and bounding box.
props = regionprops(mask, 'BoundingBox');
% Crop image.
mask = imcrop(mask, props.BoundingBox);
% Recompute centroid on sub image.
props = regionprops(mask, 'Centroid');
figure;
imshow(mask, 'InitialMagnification',1000);
Warning: When running MATLAB Online, InitialMagnification can only be 'fit'.
hold on
axis('on', 'image')
xCentroid = props.Centroid(1);
yCentroid = props.Centroid(2);
plot(xCentroid, yCentroid, 'r+', 'LineWidth', 2, 'MarkerSize', 120);
axis xy; % Flip image
% If you want you can get the boundary (x,y) in the new subimage coordinates.
boundaries = bwboundaries(mask);
thisBoundary = boundaries{1}; % Get boundary for this specific blob.
x = thisBoundary(:,2); % Column 2 is the columns, which is x.
y = thisBoundary(:,1); % Column 1 is the rows, which is y.
% Plot curve with a variety of magnification factors
figure
mags = 0.4 : 0.2 : 1.6;
for k = 1 : numel(mags)
thisCurvex = mags(k) * (x - xCentroid) + xCentroid;
thisCurvey = mags(k) * (y - yCentroid) + yCentroid;
plot(thisCurvex, thisCurvey, '-', 'LineWidth', 3);
hold on;
end
plot(xCentroid, yCentroid, 'r+', 'LineWidth', 2, 'MarkerSize', 120);
grid on;
You can see the curves, which has the (x,y) sorted clockwise, displayed all with the same centroid but different magnifications.
  댓글 수: 10
Alberto Acri
Alberto Acri 2023년 1월 8일
Thank you! How should I modify these lines of code so that curve_2 scales like curve_3?
xFit = scale * (x3 - xc3) + xc2;
yFit = scale * (y3 - yc3) + yc2;
Image Analyst
Image Analyst 2023년 1월 8일
To scale curve 2 so that it matched curve 3, make these changes:
scale = sqrt(area3/area2)
xFit = scale * (x2 - xc2) + xc3;
yFit = scale * (y2 - yc2) + yc3;
Basically just swap 2 and 3.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Get Started with Curve Fitting Toolbox에 대해 자세히 알아보기

제품


릴리스

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by