﻿ Python: Draw Line Between Two Coordinates in a Matrix - ITCodar

# 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 npdef draw_line(mat, x0, y0, x1, y1, inplace=False):    if not (0 <= x0 < mat.shape and 0 <= x1 < mat.shape and            0 <= y0 < mat.shape and 0 <= y1 < mat.shape):        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 pltmat = [[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 codex0 = np.ceil(line_array[start]) #first filled element on xy0 = np.ceil(line_array[start]) #first filled element on yx1 = np.floor(line_array[end[(len(end) - 1)]]) #last filled element on xy1 = np.floor(line_array[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.linefrom skimage.draw import line#Make a 2d array of 0s that is the same size as the original 2d array zV = np.zeros((z.shape, z.shape), 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 1sV[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 imageplt.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 listnew_line = list(bresenham(int(y0), int(x0), int(y1), int(x1)))#Use list comprehension to get the arraysx_array = np.array([item for item in new_line])y_array = np.array([item for item in new_line])#Then cast them as 1'sV[x_array, y_array] = 1#Combine the original and the new arraynew_z = V + z#Recast the 2's to 1'snew_z[np.where(new_z==2)] = 1#And viewplt.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 npimport matplotlib.pyplot as pltx, 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) 