MATLAB: Drawing a line over a black and white image - image

What is the best way to draw a line over a black and white (binary) image in MATLAB, provided the start and end coordinates are known?
Please note, I am not trying to add an annotation line. I would like the line to become part of the image.

You may want to look at my answer to an SO question about adding a line to an image matrix. Here's a similar example to the one I have in that answer, which will make a white line running from row and column index (10, 10) to (240, 120):
img = imread('cameraman.tif'); % Load a sample black and white image
x = [10 240]; % x coordinates
y = [10 120]; % y coordinates
nPoints = max(abs(diff(x)), abs(diff(y)))+1; % Number of points in line
rIndex = round(linspace(y(1), y(2), nPoints)); % Row indices
cIndex = round(linspace(x(1), x(2), nPoints)); % Column indices
index = sub2ind(size(img), rIndex, cIndex); % Linear indices
img(index) = 255; % Set the line points to white
imshow(img); % Display the image
And here's the resulting image:

If you are bothered by exceptional cases of other methods here's a bullet-proof method that results in a line:
whose pixels always touch each other during the whole length of the line (pixels are 8-neighbors to each other),
density of the line is not dependent on the additional parameter, but is determined flexibly to accommodate guarantee from the first point.
Inputs (convenient for making function out of this code):
img - matrix that contains image,
x1, y1, x2, y2 - coordinates of the end points of the line to be drawn.
Code:
% distances according to both axes
xn = abs(x2-x1);
yn = abs(y2-y1);
% interpolate against axis with greater distance between points;
% this guarantees statement in the under the first point!
if (xn > yn)
xc = x1 : sign(x2-x1) : x2;
yc = round( interp1([x1 x2], [y1 y2], xc, 'linear') );
else
yc = y1 : sign(y2-y1) : y2;
xc = round( interp1([y1 y2], [x1 x2], yc, 'linear') );
end
% 2-D indexes of line are saved in (xc, yc), and
% 1-D indexes are calculated here:
ind = sub2ind( size(img), yc, xc );
% draw line on the image (change value of '255' to one that you need)
img(ind) = 255;
Here's the example image with three lines drawn on it:

This algorithm offers one approach.

It actually is just a modification on plesiv's answer. I'm drawing thousands of lines over an image and I need to increase the performance. The most improvement made by omitting interp1 calls and using integer variables made it slightly faster. It performs about 18% faster on my PC comparing to plesiv's code.
function img = drawLine(img, x1, y1, x2, y2)
x1=int16(x1); x2=int16(x2); y1=int16(y1); y2=int16(y2);
% distances according to both axes
xn = double(x2-x1);
yn = double(y2-y1);
% interpolate against axis with greater distance between points;
% this guarantees statement in the under the first point!
if (abs(xn) > abs(yn))
xc = x1 : sign(xn) : x2;
if yn==0
yc = y1+zeros(1, abs(xn)+1, 'int16');
else
yc = int16(double(y1):abs(yn/xn)*sign(yn):double(y2));
end
else
yc = y1 : sign(yn) : y2;
if xn==0
xc = x1+zeros(1, abs(yn)+1, 'int16');
else
xc = int16(double(x1):abs(xn/yn)*sign(xn):double(x2));
end
end
% 2-D indexes of line are saved in (xc, yc), and
% 1-D indexes are calculated here:
ind = sub2ind(size(img), yc, xc);
% draw line on the image (change value of '255' to one that you need)
img(ind) = 255;
end

If you have the Computer Vision System Toolbox, you can use insertShape.

Related

Algorithm to get all zeniths crossing a box in three dimensions, MATLAB implementation

I have a 3D geometry problem and I am not certain of the best approach to solve it. I have a model with two boxes, one above the others. They have the same dimension, L (length) * p (depth) * e (thickness), and are separated by a height of h. They are perfectly superposed, with no offset between them.
For each point of my bottom box, I want to get the zenith of all lines that can cross the top box and arrive to this point. It doesn't matter if the line crosses the top box by the top or the side.
The zenith is the angle of "looking up". In our case, a zenith of 0 represents the point directly above the point P, and an angle of 90 is directly looking in front. A zenith of 180 would be looking below the point, but for our use, it's useless. The zeniths we look for are between 0 and 90°.
For a more intuitive visualization, let's say that I have a hole in the ceiling, and that I want to map the zenith of all light that crosses this hole and reaches the floor.
This is what it looks like:
For any point P of the bottom box, I want an array containing the zeniths of all "rays" that cross the top box before arriving on P. The red lines are the "edges", the last zeniths I would get for each corner.
I am working on a way to code it in MATLAB and I was wondering if there was a better algorithm that I am not seeing. My approach, in pseudocode, would be this:
bottomBox = [1:L, 1:p, 1:e];
topBox = [1:L, 1:p, 1+h:e+h];
results = zeros(L:p) * NaN; % Array of results, one per "case" on the bottom box
zeniths = zeros(L:p) * NaN; % Array of zeniths for each result case
for i = 1:L
for j = 1:p % Browsing the bottom box case by case
for k = 1:L
for l = 1:p
for m = 1:e % For each bottom box case, browsing the top box case by case
p1 = topBox(k,l,m); % p1 is each case on the top box
p2 = bottomBox(i,j,1); % p2 is the current bottom box case, z doesn't mattter
p3 = topBox(i,j,m); % p3 is the projection of p2 on the top box (zenith = 0)
v1 = p1 - p2;
v2 = p3 - p2;
zeniths(k,l) = rad2deg(atan2(norm(cross(p1, p2)), dot(p1, p2)));
end
end
end
results(i,j) = zeniths;
end
end
I tried to implement this and I couldn't get it to work. More specifically, the angle calculation doesn't seem to work, I have an error stating:
Error using cross;
A and B must be of length 3 in the dimension in which the cross product is taken.
I am looking for advice on how to build the algorithm.
Please tell me if the question is better suited for another StackExchange community, such as Math.
I'll get you started showing you one way to do it for 1 point and I'll let you build the final loop to do the calc for all your points.
As expressed in the comment, for the purpose of these calculations, you do not need to consider the thickness of your plates, you can model them simply with two parallel planes separated by a distance H.
I don't know the size of your plates nor the grid size you want so I'll keep it simple for this example:
H = 5 ; % distance between the planes
[X,Y] = meshgrid(-3:3,-2:2) ;
GridSize = size(X) ;
Zb = zeros(GridSize) ;
Zt = zeros(GridSize) + H ;
This gives you 4 matrices, defining 2 planes. The bottom plane is composed of [X,Y,Zb] and the top plane is formed by [X,Y,Zt].
If you want to visualise them, you can run the following code (optional):
%% Display planes
figure ;
ht = surf(X,Y,Zt, 'FaceColor',[.8 .8 .8],'DisplayName','Top plate') ;
hold on
hb = surf(X,Y,Zb, 'FaceColor',[.6 .6 .6],'DisplayName','Bottom plate') ;
xlabel('X') ; ylabel('Y') ; zlabel('Z') ;
axis equal ; legend show
Now for the rest of the example, I selected a point P, at coordinate [-2,1,0]. This choice is completely arbitrary, just for the example. In your final algorythm you will still have to loop over several points Pi (although remember that your problem is symetric so if your domain is too large you can reduce your computations by using the symetries of your model).
%% This will have to be embedded into a loop over the points Pi
% Assuming points P=(-2,1,0)
p = [-2;1;0] ;
zn = [0;0;1] ; % unitary vector, oriented Oz
dx = X - p(1) ; % `x` distance between all points of the plane and P
dy = Y - p(2) ; % `y` distance between all points of the plane and P
dz = zeros(size(X)) + H ; % `z` distance (all the same)
V = [dx(:) dy(:) dz(:)].' ; % to obtain list of vector V = [dx;dy;dz] ;
nv = size(V,2) ; % number of points/angle to calculate
zenith = zeros(nv,1) ; % preallocate result matrix (always good!)
for k=1:nv
% [u] is the vector going from `P` to the current point considered on the top plane
u = V(:,k) ;
% determine the angle between [u] and [zn]
zenith(k) = atan2( norm(cross(u,zn)) , dot(u,zn) ) ;
end
% Reshape "zenith" from vector to matrix so it matches the base grid system
zenith = reshape( zenith , GridSize ) ;
You now have, for this point P, a matrix of angle with every other point of the top plane:
>> rad2deg(zenith)
ans =
32.31 30.96 32.31 35.80 40.32 45.00 49.39
24.09 21.80 24.09 29.50 35.80 41.81 47.12
15.79 11.31 15.79 24.09 32.31 39.51 45.56
11.31 0 11.31 21.80 30.96 38.66 45.00
15.79 11.31 15.79 24.09 32.31 39.51 45.56
Once again, completely optionally, if you want to visualise the vectors which were used for the calculations:
for k=1:nv
hp(k) = plot3([p(1) X(k)],[p(2) Y(k)],[0 H],'Marker','o','MarkerFaceColor','k') ;
end
will yield:
Now for your final result, remember you have a 2D matrix for each point P of your bottom plane, so your final result will either be a collection of 2D matrices or a large 3D matrix.
Zenith angle is just
atan2(h, sqrt(dx^2+dy^2))
where dx, dy are coordinate differences along L and p axes (i-k and j-l in your loops)
Perhaps h+m (m as your variable for m = 1:e) instead of h if you need points inside top box

matlab - Find a bounding box which can cover a character in image

An image represents a Korean character. All values of the image are composed of 0 or 255.
Then I wanna get a bounding box which can perfectly cover the character in the image.
For example:
Input image
Output image(What I want is to get the vertices of the red box.)
I have an idea to do this but I think that is not good:
Step 1. Find the leftmost and uppermost index in the image, say (l, up)
Step 2. Find the rightmost and lowermost index in the image, say (r, low)
Step 3. Then the square(bounding box) whose one of vertices is (l, up) and (r, low) can cover a character in an image.
Is there a good idea or matlab library for this?
Even without the Matlab image processing toolbox, you could extract the left,right,top,bottom boundary indices of the input image using find.
Assuming the image is a binary matrix (logical 1 or 0) called "input":
leftBoundary = find(input,1,'first');
rightBoundary = find(input,1,'last');
topBoundary = find(input',1,'first');
BotBoundary = find(input',1,'last');
Keep in mind these are linear indices. You can use other summoning methods of find to get normal subscripts if needed
[row,col] = find(___)
You can accomplish this by using the function any to find logical indices for the rows and columns that contain any part of your character, then find to get the row and column indices of the extremities:
img = imread('Y2ZIW.png'); % Load RGB image you posted
bw = ~im2bw(img); % Convert to binary and negate
rowIndex = any(bw, 2); % N-by-1 logical index for rows
colIndex = any(bw, 1); % 1-by-N logical index for columns
boundBox = [find(colIndex, 1, 'first') find(rowIndex, 1, 'first'); ...
find(colIndex, 1, 'last') find(rowIndex, 1, 'last')];
This gives us the following 2-by-2 matrix for boundBox, which we can use as indices into your image to crop just the region containing the character:
boundBox =
71 57 % Left and upper corner index
214 180 % Right and lower corner index
subRegion = bw(boundBox(1, 2):boundBox(2, 2), boundBox(1, 1):boundBox(2, 1));
imshow(subRegion);
And here's the plot of the cropped region:
If you want a minimum one-pixel border around your cropped region, you can modify the calculation for boundBox like so:
boundBox = [find(colIndex, 1, 'first')-1 find(rowIndex, 1, 'first')-1; ...
find(colIndex, 1, 'last')+1 find(rowIndex, 1, 'last')+1];
I1 = imread('Y2ZIW.png') ;
I = rgb2gray(I1) ;
[y,x] = find(I==0) ;
%% Bounding box
x0 = min(x) ; x1 = max(x) ;
y0 = min(y) ; y1 = max(y) ;
B = abs(x1-x0) ;
L = abs(y1-y0) ;
BB = [x0 y0 ; x0 y0+L ; x0+B y0+L ; x0+B y0 ; x0 y0] ;
imshow(I1) ;
hold on
plot(BB(:,1),BB(:,2),'r')

How to get the length of n curves present in an image in Matlab?

Currently I have been working on obtaining the length of a curve, with the following code I have managed to get the length of a curve present in an image.
test image one curve
Then I paste the code that I used to get the length of the curve of a simple image. What I did is the following:
I got the columns and rows of the image
I got the columns in x and the rows in y
I obtained the coefficients of the curve, based on the formula of the
parable
Build the equation
Implement the arc length formula to obtain the length of the curve
grayImage = imread(fullFileName);
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
subplot(2, 2, 1);
imshow(grayImage, []);
% Get the rows (y) and columns (x).
[rows, columns] = find(binaryImage);
coefficients = polyfit(columns, rows, 2); % Gets coefficients of the formula.
% Fit a curve to 500 points in the range that x has.
fittedX = linspace(min(columns), max(columns), 500);
% Now get the y values.
fittedY = polyval(coefficients, fittedX);
% Plot the fitting:
subplot(2,2,3:4);
plot(fittedX, fittedY, 'b-', 'linewidth', 4);
grid on;
xlabel('X', 'FontSize', fontSize);
ylabel('Y', 'FontSize', fontSize);
% Overlay the original points in red.
hold on;
plot(columns, rows, 'r+', 'LineWidth', 2, 'MarkerSize', 10)
formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]);
% formulaD = vpa(formula)
df=diff(formula);
df = df^2;
f= (sqrt(1+df));
i = int(f,min(columns),max(columns));
j = double(i);
disp(j);
Now I have the image 2 which has n curves, I do not know how I can do to get the length of each curve
test image n curves
I suggest you to look at Hough Transformation:
https://uk.mathworks.com/help/images/hough-transform.html
You will need Image Processing Toolbox. Otherwise, you have to develop your own logic.
https://en.wikipedia.org/wiki/Hough_transform
Update 1
I had a two-hour thinking about your problem and I'm only able to extract the first curve. The problem is to locate the starting points of the curves. Anyway, here is the code I come up with and hopefully will give you some ideas for further development.
clc;clear;close all;
grayImage = imread('2.png');
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
% find edge.
bw = edge(grayImage,'canny');
imshow(bw);
[x, y] = find(bw == 1);
P = [x,y];
% For each point, find a point that is of distance 1 or sqrt(2) to it, i.e.
% find its connectivity.
cP = cell(1,length(x));
for i = 1:length(x)
px = x(i);
py = y(i);
dx = x - px*ones(size(x));
dy = y - py*ones(size(y));
distances = (dx.^2 + dy.^2).^0.5;
cP{i} = [x(distances == 1), y(distances == 1);
x(distances == sqrt(2)), y(distances == sqrt(2))];
end
% pick the first point and a second point that is connected to it.
fP = P(1,:);
Q(1,:) = fP;
Q(2,:) = cP{1}(1,:);
m = 2;
while true
% take the previous point from point set Q, when current point is
% Q(m,1)
pP = Q(m-1,:);
% find the index of the current point in point set P.
i = find(P(:,1) == Q(m,1) & P(:,2) == Q(m,2));
% Find the distances from the previous points to all points connected
% to the current point.
dx = cP{i}(:,1) - pP(1)*ones(length(cP{i}),1);
dy = cP{i}(:,2) - pP(2)*ones(length(cP{i}),1);
distances = (dx.^2 + dy.^2).^0.5;
% Take the farthest point as the next point.
m = m+1;
p_cache = cP{i}(find(distances==max(distances),1),:);
% Calculate the distance of this point to the first point.
distance = ((p_cache(1) - fP(1))^2 + (p_cache(2) - fP(2))^2).^0.5;
if distance == 0 || distance == 1
break;
else
Q(m,:) = p_cache;
end
end
% By now we should have built the ordered point set Q for the first curve.
% However, there is a significant weakness and this weakness prevents us to
% build the second curve.
Update 2
Some more work since the last update. I'm able to separate each curve now. The only problem I can see here is to have a good curve fitting. I would suggest B-spline or Bezier curves than polynomial fit. I think I will stop here and leave you to figure out the rest. Hope this helps.
Note that the following script uses Image Processing Toolbox to find the edges of the curves.
clc;clear;close all;
grayImage = imread('2.png');
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
% find edge.
bw = edge(grayImage,'canny');
imshow(bw);
[x, y] = find(bw == 1);
P = [x,y];
% For each point, find a point that is of distance 1 or sqrt(2) to it, i.e.
% find its connectivity.
cP =[0,0]; % add a place holder
for i = 1:length(x)
px = x(i);
py = y(i);
dx = x - px*ones(size(x));
dy = y - py*ones(size(y));
distances = (dx.^2 + dy.^2).^0.5;
c = [find(distances == 1); find(distances == sqrt(2))];
cP(end+1:end+length(c),:) = [ones(length(c),1)*i, c];
end
cP (1,:) = [];% remove the place holder
% remove duplicates
cP = unique(sort(cP,2),'rows');
% seperating curves
Q{1} = cP(1,:);
for i = 2:length(cP)
cp = cP(i,:);
% search for points in cp in Q.
for j = 1:length(Q)
check = ismember(cp,Q{j});
if ~any(check) && j == length(Q) % if neither has been saved in Q
Q{end+1} = cp;
break;
elseif sum(check) == 2 % if both points cp has been saved in Q
break;
elseif sum(check) == 1 % if only one of the points exists in Q, add the one missing.
Q{j} = [Q{j}, cp(~check)];
break;
end
end
% review sets in Q, merge the ones having common points
for j = 1:length(Q)-1
q = Q{j};
for m = j+1:length(Q)
check = ismember(q,Q{m});
if sum(check)>=1 % if there are common points
Q{m} = [Q{m}, q(~check)]; % merge
Q{j} = []; % delete the merged set
break;
end
end
end
Q = Q(~cellfun('isempty',Q)); % remove empty cells;
end
% each cell in Q represents a curve. Note that points are not ordered.
figure;hold on;axis equal;grid on;
for i = 1:length(Q)
x_ = x(Q{i});
y_ = y(Q{i});
coefficients = polyfit(y_, x_, 3); % Gets coefficients of the formula.
% Fit a curve to 500 points in the range that x has.
fittedX = linspace(min(y_), max(y_), 500);
% Now get the y values.
fittedY = polyval(coefficients, fittedX);
plot(fittedX, fittedY, 'b-', 'linewidth', 4);
% Overlay the original points in red.
plot(y_, x_, 'r.', 'LineWidth', 2, 'MarkerSize', 1)
formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]);
% formulaD = vpa(formula)
df=diff(formula);
lengthOfCurve(i) = double(int((sqrt(1+df^2)),min(y_),max(y_)));
end
Result:
You can get a good approximation of the arc lengths using regionprops to estimate the perimeter of each region (i.e. arc) and then dividing that by 2. Here's how you would do this (requires the Image Processing Toolbox):
img = imread('6khWw.png'); % Load sample RGB image
bw = ~imbinarize(rgb2gray(img)); % Convert to grayscale, then binary, then invert it
data = regionprops(bw, 'PixelList', 'Perimeter'); % Get perimeter (and pixel coordinate
% list, for plotting later)
lens = [data.Perimeter]./2; % Compute lengths
imshow(bw) % Plot image
hold on;
for iLine = 1:numel(data),
xy = mean(data(iLine).PixelList); % Get mean of coordinates
text(xy(1), xy(2), num2str(lens(iLine), '%.2f'), 'Color', 'r'); % Plot text
end
And here's the plot this makes:
As a sanity check, we can use a simple test image to see how good an approximation this gives us:
testImage = zeros(100); % 100-by-100 image
testImage(5:95, 5) = 1; % Add a vertical line, 91 pixels long
testImage(5, 10:90) = 1; % Add a horizontal line, 81 pixels long
testImage(2020:101:6060) = 1; % Add a diagonal line 41-by-41 pixels
testImage = logical(imdilate(testImage, strel('disk', 1))); % Thicken lines slightly
Running the above code on this image, we get the following:
As you can see the horizontal and vertical line lengths come out close to what we expect, and the diagonal line is a little bit more than sqrt(2)*41 due to the dilation step extending its length slightly.
I try with this post but i don´t understand so much, but the idea Colours123 sounds great, this post talk about GUI https://www.mathworks.com/matlabcentral/fileexchange/24195-gui-utility-to-extract-x--y-data-series-from-matlab-figures
I think that you should go through the image and ask if there is a '1' if yes, ask the following and thus identify the beginning of a curve, get the length and save it in a BD, I am not very good with the code , But that's my idea

Hilbert-Peano curve to scan image of arbitrary size

I have written an implementation of Hilbert-Peano space filling curve in Python (from a Matlab one) to flatten my 2D image:
def hilbert_peano(n):
if n<=0:
x=0
y=0
else:
[x0, y0] = hilbert_peano(n-1)
x = (1/2) * np.array([-0.5+y0, -0.5+x0, 0.5+x0, 0.5-y0])
y = (1/2) * np.array([-0.5+x0, 0.5+y0, 0.5+y0, -0.5-y0])
return x,y
However, the classical Hilbert-Peano curve only works for multi-dimensionnal array whose shape is a power of two (ex: 256*256 or 512*512 in case of a 2D array (image)).
Does anybody know how to extend this to an array of arbitrary size?
I had the same problem and have written an algorithm that generates a Hilbert-like curve for rectangles of arbitrary size in 2D and 3D. Example for 55x31: curve55x31
The idea is to recursively apply a Hilbert-like template but avoid odd sizes when halving the domain dimensions. If the dimensions happen to be powers of two, the classic Hilbert curve is generated.
def gilbert2d(x, y, ax, ay, bx, by):
"""
Generalized Hilbert ('gilbert') space-filling curve for arbitrary-sized
2D rectangular grids.
"""
w = abs(ax + ay)
h = abs(bx + by)
(dax, day) = (sgn(ax), sgn(ay)) # unit major direction
(dbx, dby) = (sgn(bx), sgn(by)) # unit orthogonal direction
if h == 1:
# trivial row fill
for i in range(0, w):
print x, y
(x, y) = (x + dax, y + day)
return
if w == 1:
# trivial column fill
for i in range(0, h):
print x, y
(x, y) = (x + dbx, y + dby)
return
(ax2, ay2) = (ax/2, ay/2)
(bx2, by2) = (bx/2, by/2)
w2 = abs(ax2 + ay2)
h2 = abs(bx2 + by2)
if 2*w > 3*h:
if (w2 % 2) and (w > 2):
# prefer even steps
(ax2, ay2) = (ax2 + dax, ay2 + day)
# long case: split in two parts only
gilbert2d(x, y, ax2, ay2, bx, by)
gilbert2d(x+ax2, y+ay2, ax-ax2, ay-ay2, bx, by)
else:
if (h2 % 2) and (h > 2):
# prefer even steps
(bx2, by2) = (bx2 + dbx, by2 + dby)
# standard case: one step up, one long horizontal, one step down
gilbert2d(x, y, bx2, by2, ax2, ay2)
gilbert2d(x+bx2, y+by2, ax, ay, bx-bx2, by-by2)
gilbert2d(x+(ax-dax)+(bx2-dbx), y+(ay-day)+(by2-dby),
-bx2, -by2, -(ax-ax2), -(ay-ay2))
def main():
width = int(sys.argv[1])
height = int(sys.argv[2])
if width >= height:
gilbert2d(0, 0, width, 0, 0, height)
else:
gilbert2d(0, 0, 0, height, width, 0)
A 3D version and more documentation is available at https://github.com/jakubcerveny/gilbert
I found this page by Lutz Tautenhahn:
"Draw A Space-Filling Curve of Arbitrary Size" (http://lutanho.net/pic2html/draw_sfc.html)
The algorithm doesn't have a name, he doesn't reference anyone else and the sketch suggests he came up with it himself.
I wonder if this is possible for a z order curve and how?
[1]Draw A Space-Filling Curve of Arbitrary Size
I finally choose, as suggested by Betterdev as adaptive curves are not that straigthforward [1], to compute a bigger curve and then get rid of coordinates which are outside my image shape:
# compute the needed order
order = np.max(np.ceil([np.log2(M), np.log2(N)]))
# Hilbert curve to scan a 2^order * 2^order image
x, y = hilbert_peano(order)
mat = np.zeros((2**order, 2**order))
# curve as a 2D array
mat[x, y] = np.arange(0, x.size, dtype=np.uint)
# clip the curve to the image shape
mat = mat[:M, :N]
# compute new indices (from 0 to M*N)
I = np.argsort(mat.flat)
x_new, y_new = np.meshgrid(np.arange(0, N, dtype=np.uint), np.arange(0, M, dtype=np.uint))
# apply the new order to the grid
x_new = x_new.flat[I]
y_new = y_new.flat[I]
[1] Zhang J., Kamata S. and Ueshige Y., "A Pseudo-Hilbert Scan Algorithm for Arbitrarily-Sized Rectangle Region"

Transfer coordinates to a new system

I would like to convert a point coordinates to a new generated coordinate system
the original system start in the top left corner of the image (0,0)
The information that I have in a new system are :
1- I have the value of the new original (x0,y0) in some where in the image
2- also I have 2 points on both new axes ( 4 points in total 2 in each line)
using this I can calculate the line equation for the 2 lines of axes (y=a1x+b1) ,(y=a2x+b2)
3- I have vector for each line (Vx, Vy)
Note: sometime the new axes rotate (the lines are not exactly horizontal or vertical)
How can I convert the points coordinates to this new system
any help will be so appreciated
here is the image
First express your lines like a1*(x-x0)+b1*(y-y0)=0 and a2*(x-x0)+b2*(y-y0)=0 and their intersection x0,y0 is accounted for already in the equations.
updated signs
The transformation from x,y to z,w is
z = -sqrt(a1^2+b1^2)*(a2*(x-x0)+b2*(y-y0))/(a2*b1-a1*b2)
w = sqrt(a2^2+b2^2)*(a1*(x-x0)+b1*(y-y0))/(a1*b2-a2*b1)
and the inverse
x = x0 - b1*z/sqrt(a1^2+b1^2) + b2*w/sqrt(a2^2+b2^2)
y = y0 + a1*z/sqrt(a1^2+b1^2) - a2*w/sqrt(a2^2+b2^2)
It would be helpful to scale the coefficients such that sqrt(a1^2+b1^2)=1 and sqrt(a2^2+b2^2)=1.
Note that this works for non-orthogonal lines also. As long as they are not parallel and a2*b1-a1*b2!=0 it is going to work.
Example
The z line (-2)*(x-3) + (1)*(y-1) = 0 and w line (-1)*(x-3) + (-4)*(y-1) = 0 meet at (3,1). The coefficients are thus a1=-2, b1=1, a2=-1, b2=-4.
The coordinates (x,y)=(2,1) transform to
z = -sqrt((-2)^2+1^2) ((-1) (x-3)+(-4) (y-1))/((-1) 1-(-2) (-4)) = 0.2484
w = sqrt((-1)^2+(-4)^2) ((-2) (x-3)+1 (y-1))/((-2) (-4)-(-1) 1) = 0.9162
With the inverse
x = -1 z/sqrt((-2)^2+1^2)+(-4) w/sqrt((-1)^2+(-4)^2)+3 = 2
y = (-2) z/sqrt((-2)^2+1^2)-(-1) w/sqrt((-1)^2+(-4)^2)+1 = 1
Development
For a line a1*(x-x0)+b1*(y-y0)=0 the direction vector along the line is e1 = [e1x,e1y]= [-b1/sqrt(a1^2+b1^2),a1/sqrt(a1^2+b1^2)]. Similarly for the other line.
The screen coordinates of a local point [z,w] is found by starting at the origin x0, y0 and moving by z along the first line and then by w along the second line. So
x = x0 + e1x*z + e2x*w = x0 -b1/sqrt(a1^2+b1^2)*z - b2/sqrt(a2^2+b2^2)*w
y = y0 + e1y*z + e2y*w = y0 +a1/sqrt(a1^2+b1^2)*z + a2/sqrt(a2^2+b2^2)*w
Now I need to flip the direction of the second line to make it work per the original posting visualization, by reversing the sign of w.
To find z, w from x, y invert the above two equations.

Resources