Scale 2D coordinates with respect to the centroid

20 views (last 30 days)
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!
Alberto Acri
Alberto Acri on 3 Jan 2023
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).

Sign in to comment.

Accepted Answer

Mathieu NOE
Mathieu NOE on 3 Jan 2023
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)
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;
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);
Image Analyst
Image Analyst on 6 Jan 2023
@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?

Sign in to comment.

More Answers (2)

William Rose
William Rose on 3 Jan 2023
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 = 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 = 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 on 3 Jan 2023
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;
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().
% 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.
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');
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
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;
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.
Image Analyst
Image Analyst on 8 Jan 2023
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.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!