A story about image processing and drawing by only matrix calculation without relying on the image processing library. Also possible with Pythonista
** Click here for basics **
Instead of relying on Open CV or Pillow, I will actually write various image processing using numpy and matplotlib. It's a combination that can also be used with the iOS app Pythonista.
import numpy as np
import matplotlib.pyplot as plt
In addition, the following functions are convenient for displaying images. (For details, Basics)
def img_show(img : np.ndarray, cmap = 'gray', vmin = 0, vmax = 255, interpolation = 'none') -> None:
'''np.Display an image with array as an argument.'''
#Set dtype to uint8
img = np.clip(img,vmin,vmax).astype(np.uint8)
#Display image
plt.imshow(img, cmap = cmap, vmin = vmin, vmax = vmax, interpolation = interpolation)
plt.show()
plt.close()
To draw a figure, use msgid to get the coordinates on the image.
x, y = np.mgrid[:100,:100]
Note that the positive direction of $ x $ is down and the positive direction of $ y $ is right.
x, y = np.mgrid[:100,:100]
x_0, y_0 = (50, 60) #Central point
x_size, y_size = (10, 20) #Rectangle size
#Rectangle drawing
rect = ((2*abs(x - x_0) < x_size) & (2*abs(y - y_0) < y_size)).astype(np.uint8)
img_show(rect*255)
$ \ frac {(x-x_0) ^ 2} {a ^ 2} + \ frac {(y-y_0) ^ 2} {b ^ 2} --1 <0 $ is used.
x, y = np.mgrid[:100,:100]
x_0, y_0 = (20, 40) #Central point
a, b = (5, 10)
ellipse = ((x - x_0)**2/a**2 + (y - y_0)**2/b**2 - 1<0).astype(np.uint8)
img_show(ellipse*255)
I tried using the error function of Bresenham's algorithm.
Suppose you want to draw a straight line M: $ ax + by + c = 0 $. If you set the condition $ a \ geq -b \ geq 0, a> 0 $, you can draw one point for each column and approximate the straight line M. In other words, for each $ y $, you only have to choose one $ x $ that is close enough to M.
Let A: $ (x_1, y_1) $ be the center point of a pixel Considering point B: $ \ left (-\ frac {b} {a} y-\ frac {c} {a}, y_1 \ right) $ on M where the $ y $ coordinates match, for that point A The $ x $ coordinate difference $ e $ is $-\ frac {b} {a} y_1- \ frac {c} {a} -x_1 $. Then, the condition that it is close enough to M can be written as $ 0.5 \ leq e <0.5 $. Because the same point A and point B are in the same pixel.
x,y = np.mgrid[:5,:5]
a,b,c = 2,-1,-1
e = -(b/a)*y-c/a-x
#array([[ 0.5, 1. , 1.5, 2. , 2.5],
# [-0.5, 0. , 0.5, 1. , 1.5],
# [-1.5, -1. , -0.5, 0. , 0.5],
# [-2.5, -2. , -1.5, -1. , -0.5],
# [-3.5, -3. , -2.5, -2. , -1.5]])
line = ((-0.5<=e)&(e<0.5)).astype(np.uint8)
#array([[0, 0, 0, 0, 0],
# [1, 1, 0, 0, 0],
# [0, 0, 1, 1, 0],
# [0, 0, 0, 0, 1],
# [0, 0, 0, 0, 0]], dtype=uint8)
img_show(line*255)
If you don't like floating point types, multiply $ e $ by $ 2a $. The condition that it is close enough to M can be written as $ -a \ leq e <a $.
x,y = np.mgrid[:20,:20]
a,b,c = 2,-1,-1
e = 2*(-b*y-c-a*x)
line = ((-a<=e)&(e<a)).astype(np.uint8)
img_show(line*255)
Finally, assuming that $ a == 0 \ land b == 0 $ does not exist, and when $ a \ geq -b \ geq 0, a> 0 $ is not considered, the following algorithm is appropriate. ..
x,y = np.mgrid[:20,:20]
a,b,c = 13,14,-200
e = 2*(-b*y-c-a*x)
threshold = max(abs(a),abs(b))
line = ((-threshold<=e)&(e<threshold)).astype(np.uint8)
img_show(line*255)
The shape generated by this algorithm is the same as the shape generated by Bresenham's algorithm.
I made it myself. ** Click here for details **
The above is drawing $ -3x-7y + 60 = 0 $ on a 1000 pixel square figure. The following is a straight line created by Bresenham's algorithm.
Recommended Posts