Marching Square algorithm in Python - python

The following Python source code is the implementation of Marching Square algorithm:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
import cv2
from PIL import Image, ImageDraw
class Square():
A = [0, 0]
B = [0, 0]
C = [0, 0]
D = [0, 0]
A_data = 0.0
B_data = 0.0
C_data = 0.0
D_data = 0.0
def GetCaseId(self, threshold):
caseId = 0
if (self.A_data >= threshold):
caseId |= 1
if (self.B_data >= threshold):
caseId |= 2
if (self.C_data >= threshold):
caseId |= 4
if (self.D_data >= threshold):
caseId |= 8
return caseId
def GetLines(self, Threshold):
lines = []
caseId = self.GetCaseId(Threshold)
if caseId in (0, 15):
return []
if caseId in (1, 14, 10):
pX = (self.A[0] + self.B[0]) / 2
pY = self.B[1]
qX = self.D[0]
qY = (self.A[1] + self.D[1]) / 2
line = (pX, pY, qX, qY)
lines.append(line)
if caseId in (2, 13, 5):
pX = (self.A[0] + self.B[0]) / 2
pY = self.A[1]
qX = self.C[0]
qY = (self.A[1] + self.D[1]) / 2
line = (pX, pY, qX, qY)
lines.append(line)
if caseId in (3, 12):
pX = self.A[0]
pY = (self.A[1] + self.D[1]) / 2
qX = self.C[0]
qY = (self.B[1] + self.C[1]) / 2
line = (pX, pY, qX, qY)
lines.append(line)
if caseId in (4, 11, 10):
pX = (self.C[0] + self.D[0]) / 2
pY = self.D[1]
qX = self.B[0]
qY = (self.B[1] + self.C[1]) / 2
line = (pX, pY, qX, qY)
lines.append(line)
elif caseId in (6, 9):
pX = (self.A[0] + self.B[0]) / 2
pY = self.A[1]
qX = (self.C[0] + self.D[0]) / 2
qY = self.C[1]
line = (pX, pY, qX, qY)
lines.append(line)
elif caseId in (7, 8, 5):
pX = (self.C[0] + self.D[0]) / 2
pY = self.C[1]
qX = self.A[0]
qY = (self.A[1] + self.D[1]) / 2
line = (pX, pY, qX, qY)
lines.append(line)
return lines
def marching_square(xVector, yVector, Data, threshold):
linesList = []
Height = len(Data) # rows
Width = len(Data[1]) # cols
if ((Width == len(xVector)) and (Height == len(yVector))):
squares = np.full((Height - 1, Width - 1), Square())
sqHeight = squares.shape[0] # rows count
sqWidth = squares.shape[1] # cols count
for j in range(sqHeight): # rows
for i in range(sqWidth): # cols
a = Data[j + 1, i]
b = Data[j + 1, i + 1]
c = Data[j, i + 1]
d = Data[j, i]
A = [xVector[i], yVector[j + 1]]
B = [xVector[i + 1], yVector[j + 1]]
C = [xVector[i + 1], yVector[j]]
D = [xVector[i], yVector[j]]
squares[j, i].A_data = a
squares[j, i].B_data = b
squares[j, i].C_data = c
squares[j, i].D_data = d
squares[j, i].A = A
squares[j, i].B = B
squares[j, i].C = C
squares[j, i].D = D
list = squares[j, i].GetLines(threshold)
linesList = linesList + list
else:
raise AssertionError
return [linesList]
def main():
x = [i for i in range(256)]
y = [i for i in range(256)]
example_l = [[0 for i in range(256)] for j in range(256)]
for i in range(len(example_l)):
for j in range(len(example_l[0])):
example_l[i][j] = math.sin(i / 10.0)*math.cos(j / 10.0)
example = np.array(example_l)
im = Image.new('RGB', (256, 256), (128, 128, 128))
collection = marching_square(x, y, example, 0.9)
draw = ImageDraw.Draw(im)
for ln in collection:
for toup in ln:
draw.line(toup, fill=(255, 255, 0), width=1)
plt.axis("off")
plt.imshow( im )
plt.show()
if __name__ == '__main__':
main()
Output:
My question is: Why does this source code generate circular patterns?
what is the mathematical explanation of this circular pattern?

You are applying the marching squares algorithm to a sample of the surface defined by:
F(x,y) = sin(x)*cos(y)
If you plot it, e.g. with google here
You get a surface that looks like eggs boxes, and your marching squares algorithm is finding the isolines ("lines following a single data level, or isovalue.") at 0.9, which are circles. You can imagine this as the intersection of that surface with a plane parallel to the XY plane and at Z = 0.9.

Related

Wrong ans given when using Python sympy with inequality

I make trying to check if a line segment (xy1) intersects with another (xy2).
Here's part of the code:
import numpy as np
from sympy import Symbol, Piecewise, lambdify, And
x1, y1 = Symbol('x1'), Symbol('y1')
x2, y2 = Symbol('x2'), Symbol('y2')
xx_u1 = 0.5
yy_u1 = 0.053
xx_u2 = 0.51
yy_u2 = 0.052
x_act1 = -2
y_act1 = 0.025
x_act2 = 0.5
y_act2 = 0.025
Ax = x1; Ay = y1; Bx = xx_u1; By = yy_u1; Cx = xx_u2; Cy = yy_u2
tmp1 = Piecewise( (1, (Cy - Ay)*(Bx - Ax) > (By - Ay)*(Cx - Ax)), (0, True))
tmp_1 = lambdify([x1,y1], tmp1, "numpy")
tmp_1_act = tmp_1(x_act1,y_act1)
Ax = x2; Ay = y2; Bx = xx_u1; By = yy_u1; Cx = xx_u2; Cy = yy_u2
tmp2 = Piecewise( (1, (Cy - Ay)*(Bx - Ax) > (By - Ay)*(Cx - Ax)), (0, True))
tmp_2 = lambdify([x2, y2], tmp2, "numpy")
tmp_2_act = tmp_2(x_act2, y_act2)
intersection_tmp1 = Piecewise( (1, tmp1 != tmp2), (0, True))
intersections1 = lambdify([x1, y1, x2, y2], intersection_tmp1, "numpy")
intersection_act1 = intersections1(x_act1, y_act1, x_act2, y_act2)
In this case, they shouldn't intersect. So intersection_act1 = 1.
However, I got 0. I only can get 1 if I use:
intersection_tmp1 = Piecewise( (1, tmp_1_act != tmp_2_act), (0, True))
instead of
intersection_tmp1 = Piecewise( (1, tmp1 != tmp2), (0, True))
Why is this so?

Rectifying the image

I have problem in remaping the image, I used my own millimeter sheet which contains coplanar set of points, I applied the method of direct radial alignment still the image is warped not rectified, can someone help me to find where my error is. Xw, Yw, Zw are the real world coordinates, Xf, Yf are the corresponding pixel coordinates. Cx, Cy are the coordinates of the center of distortion.
import cv2
import numpy as np
from scipy.optimize import minimize
Xd = dx*(Xf-Cx)/Sx
Yd = dy*(Yf-Cy)
n1=6
A=np.zeros((N, n1))
for i in range(N):
for j in range(n1):
A[:, 0] = Yd*Xw
A[:, 1] = Yd*Yw
A[:, 2] = Yd
A[:, 3] = -Xd*Xw
A[:, 4] = -Xd*Yw
A[:, 5] = -Xd
X = solution(A)
Sr = r1_prime**2 + r2_prime**2 + r4_prime**2 + r5_prime**2
Ty = np.sqrt(Sr-np.sqrt(Sr**2-4*(r1_prime*r5_prime-r2_prime*r4_prime)**2))/(2*(r1_prime*r5_prime-r2_prime*r4_prime)**2)
#compute the rotation matrix components:
r1 = (X[0]/X[5])*Ty
r2 = (X[1]/X[5])*Ty
r4 = (X[3]/X[5])*Ty
r5 = (X[5]/X[5])*Ty
Tx = (X[2]/X[5])*Ty
s = -np.sign(r1*r4+r2*r5)
r3 = np.sqrt(1-r1**2-r2**2)
r6 = s*np.sqrt(1-r4**2-r5**2)
r7 = np.sqrt(1-(r1**2+r4**2))
r8 = np.sqrt(1-(r2**2+r5**2))
r9 = np.sqrt(-1+Sr*Ty**2)
n11 = 2
A1=np.zeros((N, n11))
for i in range(N):
for j in range(n11):
A1[:, 0] = r4*Xw + r5*Yw +Ty
A1[:, 1] = -Yd
b1 = (r7*Xw + r8*Yw)*Yd
U1, S1, VT1 = np.linalg.svd(A1)
Sigma = np.zeros((A1.shape[0], A1.shape[1]))
Sigma[:A1.shape[1], :A1.shape[1]] = np.diag(S1)
J1 = np.zeros((A1.shape[0], A1.shape[1]))
J1[:A1.shape[1], :A1.shape[1]] = np.linalg.inv(np.diag(S1))
H1 = np.zeros((A1.shape[0], A1.shape[1]))
H1[:A1.shape[0], :A1.shape[0]] = np.linalg.multi_dot([U1, J1, VT1])
H1 = H1.T
x1 = np.dot(H1, b1)
f = x1[0]
Tz = x1[1]
R = np.array([[r1, r2, r3], [r4, r5, r6], [r7, r8, r9]])
def func(guess):
k1 = guess[0]
k2 = guess[1]
f = guess[2]
tz = guess[3]
sx = guess[4]
r = np.sqrt((dx*(Xf-Cx)/sx)**2 + (Yd)**2)
return np.sum((Yd*(1+k1*r**2 + k2*r**4)*(r7*Xw + r8*Yw + r9*Zw + tz)-f*(r4*Xw + r5*Yw + r6*Zw + Ty))**2)
x0 = np.array([0, 0, f, Tz, 1])
i = minimize(func, x0, method='COBYLA', options={'disp': True})
K1 = i.x[0]
K2 = i.x[1]
F = i.x[2]
Pz = i.x[3]
Sx = i.x[4]
dx_new = dx*Sx
nx, ny = img.shape[1], img.shape[0]
X, Y = np.meshgrid(np.arange(0, nx, 1), np.arange(0, ny, 1))
x = X.astype(np.float32)
y = Y.astype(np.float32)
rd = np.sqrt((y-Cy)**2 + (x-Cx)**2)
map_x = y*(1+K11*np.power(rd, 2)+K22*np.power(rd, 4))
map_y = x*(1+K11*np.power(rd, 2)+K22*np.power(rd, 4))
imgg = cv2.remap(img, map_x, map_y, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
enter image description here

Object values not being reset in python function

Here is my code. In the calculateOptimalLambda() function, I am attempting to declare a copy of n and
store it as m, remove one point from m, and make some calculations and a graph. Then, the loop should
restart, make a fresh copy of m, remove the next point, and so on.
However, when in the next iteration
of the loop, a point has been removed. Eventually, I run out of points to remove, and I get an error.
How do I declare a fresh copy of m so I can remove the next point?
import numpy as np
from matplotlib import pyplot as plt
class Data:
def __init__(self, points, sigma, lamda):
self.points = points
self.sigma = sigma
self.sample = np.random.uniform(-1,1, (points, 2))
self.transformedData = np.ones((points, 5))
self.weight = np.zeros((5,1))
self.lamda = lamda
def changeLamda(self,x):
self.lamda = x
def removePoint(self, x):
self.points = self.points - 1
self.sample = np.delete(self.sample, x, 0)
self.transformedData = np.delete(self.transformedData, x, 0)
def transformedFunction(self, x):
transformedData = np.ones((1, 5))
transformedData[0,1] = x
transformedData[0,2] = 0.5 * (3*x**2 -1)
transformedData[0,3]= 0.5 * (5*x**3 - 3*x)
transformedData[0,4] = 0.125 * (35*x**4 -30*x**2 + 3)
return np.dot(transformedData, self.weight)
def setY(self):
for i in range(len(self.sample[0:,0])):
self.sample[i,1] = np.random.normal(0, self.sigma) + self.sample[i,0]**2
def transform(self):
for i in range(len(self.sample[0:,0])):
self.transformedData[i,1] = self.sample[i,0]
self.transformedData[i,2] = 0.5 * (3*self.sample[i,0]**2 -1)
self.transformedData[i,3]= 0.5 * (5*self.sample[i,0]**3 - 3*self.sample[i,0])
self.transformedData[i,4] = 0.125 * (35*self.sample[i,0]**4 -30*self.sample[i,0]**2 + 3)
def calculateWeight(self):
z = n.transformedData
zProd = np.linalg.inv(np.matmul(np.transpose(z), z) + np.identity(5)*self.lamda)
next1 = np.matmul(zProd,np.transpose(z))
a = self.sample[0:,1]
a = a.reshape((-1, 1))
print(a)
self.weight = np.matmul(next1,a)
def calculateError(self):
error= (np.matmul(self.transformedData, self.weight) - self.sample[1,0:])
return error/self.points
def calculateOptimalLambda(n, L):
a = 0
for i in range(len(L)):
n.changeLamda(L[i])
for x in range(n.getPoints()):
a+=1
plt.subplot(4,5,a)
m = n
m.removePoint(x)
m.calculateWeight()
weight = m.getWeight()
error = m.calculateError()
twoD_plot(m)
print(error)
def twoD_plot(n):
t = np.linspace(-1, 1, 400)
x = np.square(t)
plt.plot(t,x,'b')
error = 0
y = x
for i in range(len(t)):
y[i] = n.transformedFunction(t[i])
error += (y[i] - t[i]**2)**2
"""print(error/len(t))"""
plt.plot(t,y,'r')
plt.scatter(n.getSample()[0:,0],n.getSample()[0:,1], c = 'g', marker = 'o')
n = Data(5,0.1,0)
n.setY()
n.transform()
n.calculateWeight()
L = [1, 0.01, 0.00001, 0]
calculateOptimalLambda(n, L)
plt.show()

How to auto-indent python code using keyboard shortcuts

I have following code:
for im_fn in tqdm(im_fns):
try:
_, fn = os.path.split(im_fn)
bfn, ext = os.path.splitext(fn)
if ext.lower() not in ['.jpg', '.png']:
continue
gt_path = os.path.join(DATA_FOLDER, "label", 'gt_' + bfn + '.txt')
img_path = os.path.join(DATA_FOLDER, "image", im_fn)
img = cv.imread(img_path)
img_size = img.shape
im_size_min = np.min(img_size[0:2])
im_size_max = np.max(img_size[0:2])
im_scale = float(600) / float(im_size_min)
if np.round(im_scale * im_size_max) > 1200:
im_scale = float(1200) / float(im_size_max)
new_h = int(img_size[0] * im_scale)
new_w = int(img_size[1] * im_scale)
new_h = new_h if new_h // 16 == 0 else (new_h // 16 + 1) * 16
new_w = new_w if new_w // 16 == 0 else (new_w // 16 + 1) * 16
re_im = cv.resize(img, (new_w, new_h), interpolation=cv.INTER_LINEAR)
re_size = re_im.shape
polys = []
with open(gt_path, 'r') as f:
lines = f.readlines()
for line in lines:
splitted_line = line.strip().lower().split(',')
x1, y1, x2, y2, x3, y3, x4, y4 = map(float, splitted_line[:8])
poly = np.array([x1, y1, x2, y2, x3, y3, x4, y4]).reshape([4, 2])
poly[:, 0] = poly[:, 0] / img_size[1] * re_size[1]
poly[:, 1] = poly[:, 1] / img_size[0] * re_size[0]
poly = orderConvex(poly)
polys.append(poly)
# cv.polylines(re_im, [poly.astype(np.int32).reshape((-1, 1, 2))], True,color=(0, 255, 0), thickness=2)
res_polys = []
for poly in polys:
# delete polys with width less than 10 pixel
if np.linalg.norm(poly[0] - poly[1]) < 10 or np.linalg.norm(poly[3] - poly[0]) < 10:
continue
res = shrink_poly(poly)
# for p in res:
# cv.polylines(re_im, [p.astype(np.int32).reshape((-1, 1, 2))], True, color=(0, 255, 0), thickness=1)
res = res.reshape([-1, 4, 2])
for r in res:
x_min = np.min(r[:, 0])
y_min = np.min(r[:, 1])
x_max = np.max(r[:, 0])
y_max = np.max(r[:, 1])
res_polys.append([x_min, y_min, x_max, y_max])
cv.imwrite(os.path.join(OUTPUT, "image", fn), re_im)
with open(os.path.join(OUTPUT, "label", bfn) + ".txt", "w") as f:
for p in res_polys:
line = ",".join(str(p[i]) for i in range(4))
f.writelines(line + "\r\n")
for p in res_polys:
cv.rectangle(re_im,(p[0],p[1]),(p[2],p[3]),color=(0,0,255),thickness=1)
cv.imshow("demo",re_im)
cv.waitKey(0)
except:
print("Error processing {}".format(im_fn))
In the above code I want to remove the uppermost for loop, try and except statement.
for im_fn in tqdm(im_fns):
try:
except:
print("Error processing {}".format(im_fn))
How ever after removing this I don't want to manually go in the remaining code and press backspace and manually put the indentations. IS there any key board shortcut which will auto indent the existing code after removing the for loop.
Select all the code you need to indent. With tab you will indent "in" and with Shift+tab you will indent it "out"
shift + tab works in the above scenario

How to draw Buddhabrot fractal?

I'm trying to implement Buddhabrot fractal in Python. I read a lot of articles and posts but I think that I missunderstood something (just see the image). Someone can write a pseudocode?
My code is this:
from multiprocessing import Pool
from random import randrange
import matplotlib.pyplot as plt
import numpy as np
from math import ceil
maxiter = 1000
points = 1000
xmin, xmax = -2, 1
ymin, ymax = -2, 1
cores = 4
width, height = 200, 200
maxn = width * height
incrx, incry = abs(xmax - xmin) / width, abs(ymax - ymin) / height
def randomComplexGenerator():
for i in range(points):
n = randrange(maxn)
yield complex(n // height * incrx, n % width * incry)
def buddhabrot(c):
m, z, i = np.zeros((width, height)), c, 0
while i < maxiter and abs(z) < 2:
x, y = ceil(z.real / incrx), ceil(z.imag / incry)
m[x, y] += 1
z = z ** 2 + c
i += 1
return m if i == maxiter else 0
if __name__ == '__main__':
a = np.linspace(xmin, xmax, width)
b = np.linspace(ymin, ymax, height)
with Pool(cores) as p:
ms = p.map(buddhabrot, (c for c in randomComplexGenerator()))
res = 0
for m in ms:
res += m
plt.axis('off')
plt.imshow(res)
plt.show()
The image generated with my code is this (lel):
After days, this is the code that I created, which seems to generate appropriately the fractal. Any performance suggestion is welcome.
from multiprocessing import Pool
from random import randrange
import matplotlib.pyplot as plt
import numpy as np
cores = 4
maxiter = 10000
points = 1000000
width, height = 200, 200
rdom, idom = (-2, 2), (-2, 2)
xdom, ydom = (0, width - 1), (0, height - 1)
def randomComplex():
r = np.interp(randrange(xdom[0], xdom[1]), xdom, rdom)
i = np.interp(randrange(ydom[0], ydom[1]), ydom, idom)
return (r, i)
def complex2pixel(c):
x = int(np.interp(c[0], rdom, xdom))
y = int(np.interp(c[1], idom, ydom))
return (x, y)
def escapedPixels(c):
pixels, z = {}, c
for i in range(maxiter):
z2 = (z[0] * z[0], z[1] * z[1])
if z2[0] + z2[1] > 4: break
p = complex2pixel(z)
try: pixels[p] += 1
except: pixels[p] = 1
z = (z2[0] - z2[1] + c[0], 2 * z[0] * z[1] + c[1])
return pixels if i < maxiter - 1 else {}
if __name__ == '__main__':
with Pool(cores) as p:
ds = p.map(escapedPixels, (randomComplex() for i in range(points)))
m = np.zeros((width, height))
for d in ds:
for p in d:
m[p] += d[p]
plt.axis('off')
plt.imshow(m)
plt.show()

Categories

Resources