Python: Draw Line Between Two Coordinates in a Matrix

Python: Draw line between two coordinates in a matrix

This is one simple implementation with NumPy, just computing the line equation:

import numpy as np

def draw_line(mat, x0, y0, x1, y1, inplace=False):
if not (0 <= x0 < mat.shape[0] and 0 <= x1 < mat.shape[0] and
0 <= y0 < mat.shape[1] and 0 <= y1 < mat.shape[1]):
raise ValueError('Invalid coordinates.')
if not inplace:
mat = mat.copy()
if (x0, y0) == (x1, y1):
mat[x0, y0] = 2
return mat if not inplace else None
# Swap axes if Y slope is smaller than X slope
transpose = abs(x1 - x0) < abs(y1 - y0)
if transpose:
mat = mat.T
x0, y0, x1, y1 = y0, x0, y1, x1
# Swap line direction to go left-to-right if necessary
if x0 > x1:
x0, y0, x1, y1 = x1, y1, x0, y0
# Write line ends
mat[x0, y0] = 2
mat[x1, y1] = 2
# Compute intermediate coordinates using line equation
x = np.arange(x0 + 1, x1)
y = np.round(((y1 - y0) / (x1 - x0)) * (x - x0) + y0).astype(x.dtype)
# Write intermediate coordinates
mat[x, y] = 1
if not inplace:
return mat if not transpose else mat.T

Some tests:

print(draw_line(np.zeros((5, 5)), 0, 3, 4, 2))
#[[0. 0. 0. 2. 0.]
# [0. 0. 0. 1. 0.]
# [0. 0. 1. 0. 0.]
# [0. 0. 1. 0. 0.]
# [0. 0. 2. 0. 0.]]
print(draw_line(np.zeros((5, 5)), 4, 2, 0, 3))
#[[0. 0. 0. 2. 0.]
# [0. 0. 0. 1. 0.]
# [0. 0. 1. 0. 0.]
# [0. 0. 1. 0. 0.]
# [0. 0. 2. 0. 0.]]
print(draw_line(np.zeros((5, 5)), 1, 0, 3, 4))
#[[0. 0. 0. 0. 0.]
# [2. 0. 0. 0. 0.]
# [0. 1. 1. 1. 0.]
# [0. 0. 0. 0. 2.]
# [0. 0. 0. 0. 0.]]

draw grid lines between same values in a matrix in python

Using only matplotlib :

import matplotlib.pyplot as plt

mat = [[0.2, 0.2, 0.1, 0.1, 0.1],
[0.2, 0.2, 0.1, 0.1, 0.0],
[0.2, 0.2, 0.1, 0.1, 0.0],
[0.2, 0.1, 0.1, 0.0, 0.0]]

def line(x,y):
plt.plot(x,y,marker = 'o',color = 'red',
markerfacecolor='black',markeredgecolor='black')

def draw(mat):
for i in range(len(mat)):
for k in range(len(mat[i])-1):
if mat[i][k] == mat[i][k+1] :
line([k,k+1],[len(mat)-i,len(mat)-i])
for i in range(len(mat)-1):
for k in range(len(mat[i])):
if mat[i][k] == mat[i+1][k]:
line([k,k],[len(mat)-i,len(mat)-i-1])

draw(mat)
plt.show()

In python interpolate a line of values between two points on a 2d grid of zeroes

So thanks to Ardweaden for suggesting I find a simple way to state my objective, and Mad Physicist for pointing me in the direction at the Bresenham line algorithm. After that I was able to find a couple python implementation that bridged the gap. The working code for two versions is below (if anyone has a faster way to do it I will mark that as the accepted answer):

#Starting from the line limits obtained in the original questions code
x0 = np.ceil(line_array[0][start[0]]) #first filled element on x
y0 = np.ceil(line_array[1][start[0]]) #first filled element on y

x1 = np.floor(line_array[0][end[(len(end) - 1)]]) #last filled element on x
y1 = np.floor(line_array[1][end[(len(end) - 1)]]) #last filled element on y

#The skimage implementation of Bresenham's line algorithm
# https://scikit-image.org/docs/dev/api/skimage.draw.html#skimage.draw.line
from skimage.draw import line

#Make a 2d array of 0s that is the same size as the original 2d array z
V = np.zeros((z.shape[0], z.shape[1]), dtype=np.uint8)

#This flips the y and x from how I think of it...
rr, cc = line(int(y0), int(x0), int(y1), int(x1))

#Cast the line coordinates as 1s
V[rr, cc] = 1

#Then add the new array to the old array (although could just write the line on z).
new_z = V + z

#Use numpy where to change the 2 values back to 1 values.
new_z[np.where(new_z==2)] = 1

#Show the final image
plt.imshow(new_z)


# This implementation is a short script from https://github.com/encukou/bresenham and can just be
# brought into the existing code base without importing an external library.

# The code can be modified, but as is doesn't have a return so place it into a list
new_line = list(bresenham(int(y0), int(x0), int(y1), int(x1)))

#Use list comprehension to get the arrays
x_array = np.array([item[0] for item in new_line])
y_array = np.array([item[1] for item in new_line])

#Then cast them as 1's
V[x_array, y_array] = 1

#Combine the original and the new array
new_z = V + z

#Recast the 2's to 1's
new_z[np.where(new_z==2)] = 1

#And view
plt.imshow(new_z)

How to draw lines between points in OpenCV?

Using draw contours, you can draw the shape all at once.

img = np.zeros([512, 512, 3],np.uint8)
a = np.array([(375, 193), (364, 113), (277, 20), (271, 16), (52, 106), (133, 266), (289, 296), (372, 282)])
cv2.drawContours(img, [a], 0, (255,255,255), 2)

If you don't want the image closed and want to continue how you started:

image = np.zeros([512, 512, 3],np.uint8)
pointsInside = [(375, 193), (364, 113), (277, 20), (271, 16), (52, 106), (133, 266), (289, 296), (372, 282)]

for index, item in enumerate(pointsInside):
if index == len(pointsInside) -1:
break
cv2.line(image, item, pointsInside[index + 1], [0, 255, 0], 2)

Regarding your current code, it looks like you are trying to access the next point by indexing the current point. You need to check for the next point in the original array.

A more Pythonic way of doing the second version would be:

for point1, point2 in zip(a, a[1:]): 
cv2.line(image, point1, point2, [0, 255, 0], 2)

Plotting lines connecting points

I think you're going to need separate lines for each segment:

import numpy as np
import matplotlib.pyplot as plt

x, y = np.random.random(size=(2,10))

for i in range(0, len(x), 2):
plt.plot(x[i:i+2], y[i:i+2], 'ro-')

plt.show()

(The numpy import is just to set up some random 2x10 sample data)

enter image description here



Related Topics



Leave a reply



Submit