I have a code for plotting radial gradients with numpy. So far it looks like this:
import numpy as np
import matplotlib.pyplot as plt
arr = np.zeros((256,256,3), dtype=np.uint8)
imgsize = arr.shape[:2]
innerColor = (0, 0, 0)
outerColor = (255, 255, 255)
for y in range(imgsize[1]):
for x in range(imgsize[0]):
#Find the distance to the center
distanceToCenter = np.sqrt((x - imgsize[0]//2) ** 2 + (y - imgsize[1]//2) ** 2)
#Make it on a scale from 0 to 1innerColor
distanceToCenter = distanceToCenter / (np.sqrt(2) * imgsize[0]/2)
#Calculate r, g, and b values
r = outerColor[0] * distanceToCenter + innerColor[0] * (1 - distanceToCenter)
g = outerColor[1] * distanceToCenter + innerColor[1] * (1 - distanceToCenter)
b = outerColor[2] * distanceToCenter + innerColor[2] * (1 - distanceToCenter)
# print r, g, b
arr[y, x] = (int(r), int(g), int(b))
plt.imshow(arr, cmap='gray')
plt.show()
Is there any way to optimize this code with numpy functions and improve speed?
It should look like this afterwards:
You can use vectorization to very efficiently calculate the distance without the need for a for-loop:
x_axis = np.linspace(-1, 1, 256)[:, None]
y_axis = np.linspace(-1, 1, 256)[None, :]
arr = np.sqrt(x_axis ** 2 + y_axis ** 2)
or you can use a meshgrid:
x_axis = np.linspace(-1, 1, 256)
y_axis = np.linspace(-1, 1, 256)
xx, yy = np.meshgrid(x_axis, y_axis)
arr = np.sqrt(xx ** 2 + yy ** 2)
and interpolate between inner and outer colors using broadcasting again
inner = np.array([0, 0, 0])[None, None, :]
outer = np.array([1, 1, 1])[None, None, :]
arr /= arr.max()
arr = arr[:, :, None]
arr = arr * outer + (1 - arr) * inner
Because of symmetry, actually just need to calculate one-fourth of image 256*256 which is 64*64, then rotate it with 90 degrees piece by piece and combine them. In this way, the total time is 1/4 times than calculating 256*256 pixel.
the following is example.
import numpy as np
import matplotlib.pyplot as plt
##Just calculate 64*64
arr = np.zeros((64,64,3), dtype=np.uint8)
imgsize = arr.shape[:2]
innerColor = (0, 0, 0)
outerColor = (255, 255, 255)
for y in range(imgsize[1]):
for x in range(imgsize[0]):
#Find the distance to the corner
distanceToCenter = np.sqrt((x) ** 2 + (y - imgsize[1]) ** 2)
#Make it on a scale from 0 to 1innerColor
distanceToCenter = distanceToCenter / (np.sqrt(2) * imgsize[0])
#Calculate r, g, and b values
r = outerColor[0] * distanceToCenter + innerColor[0] * (1 - distanceToCenter)
g = outerColor[1] * distanceToCenter + innerColor[1] * (1 - distanceToCenter)
b = outerColor[2] * distanceToCenter + innerColor[2] * (1 - distanceToCenter)
# print r, g, b
arr[y, x] = (int(r), int(g), int(b))
#rotate and combine
arr1=arr
arr2=arr[::-1,:,:]
arr3=arr[::-1,::-1,:]
arr4=arr[::,::-1,:]
arr5=np.vstack([arr1,arr2])
arr6=np.vstack([arr4,arr3])
arr7=np.hstack([arr6,arr5])
plt.imshow(arr7, cmap='gray')
plt.show()
Related
We have two terms, two parameters (h, h0) and a variable T. We can define a certain value of T, where the difference of the two terms divided by L is equal to zero.
With this T value, we can calculate g0, gc and gs operators, and then witness1 and witness2.
Then we make this whole calculation with running parameters (from 0.03 to 3): h0=0.03, h=0.03; h0=0.06, h=0.03; ...; h0=3, h=0.03; h0=0.03, h=0.06; ...; h0=3, h=3
Then we select the witness with the lower value, and put it to the proper place in the matrix.
The values can be both positive and negative. We are interested in where will be the result negative, and from which witness we got the result. I have plotted the results from the matrix, the negative values with yellow, and the positive with white. Now I would like to plot the negative numbers from witness1 with blue, and the negative numbers from witness2 with yellow. Then I would like to norm the graph from 0-100 to 0-3.
How can I make this?
import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
def g0operator(T, gamma, h, L):
k = -math.pi
d=2*math.pi/L
g0=0
while k <= math.pi:
g0 = g0 + (((math.tanh(math.sqrt(((gamma * math.sin(k)) ** 2) + (h - math.cos(k)) ** 2) / T))) * (
1 / (math.sqrt(
((gamma * math.sin(k)) ** 2) + (h - math.cos(k)) ** 2))) * ((h - math.cos(k))))
k = k + d
g0 = g0 / L
return g0
def gsoperator(T, gamma, h, L):
gs=0
k = -math.pi
d=2*math.pi/L
while k <= math.pi:
gs = gs + ((math.tanh(math.sqrt(((gamma * math.sin(k)) ** 2) + (h - math.cos(k)) ** 2) / T)) * (1 /
(math.sqrt(((gamma * math.sin(k)) ** 2) + (h - math.cos(k)) ** 2))) * (
((math.sin(k)) ** 2)))
k = k + d
gs = -(gs / L) * gamma
return gs
def gcoperator(T, gamma, h, L):
d=2*math.pi/L
gc=0
k = -math.pi
while k <= math.pi:
gc = gc + ((math.tanh(np.sqrt(((gamma * np.sin(k)) ** 2) + (h - np.cos(k)) ** 2) / T)) * (1 /
np.sqrt(((gamma * np.sin(k)) ** 2) + (h - np.cos(k)) ** 2))) * (np.cos(k) * ((np.cos(k) - h)))
k = k + d
gc = gc / L
return gc
def first_term(gamma, h, T, L):
c=-math.pi
d=2*math.pi/L
first=0
while c <= math.pi:
first = first + (math.tanh(math.sqrt(((gamma * math.sin(c)) ** 2) + (h - math.cos(c)) ** 2) / T) * math.sqrt(
((gamma * math.sin(c))
** 2) + (h - math.cos(c)) ** 2))
c=c+d
return first
def second_term(h, h0, gamma, L):
second=0
c=-math.pi
d=2*math.pi/L
while c<=math.pi:
second = second + abs(((math.cos(c) - h0) * (math.cos(c) - h) + ((gamma * math.sin(c)) ** 2)) / (
math.sqrt(((gamma * math.sin(c)) ** 2) + (h0 - math.cos(c)) ** 2)))
c = c + d
return second
def witness1(gs, g0, gc):
W = (-1 / 4) * (2 * abs(gs) + ((g0) ** 2) - ((gc) ** 2) + ((gs) ** 2) - 1)
return W
def witness2(gs, g0, gc):
w=-(1/4)*(-(g0**2)+(gc**2)-(gs**2)-1+2*math.sqrt((g0**2)+(gc**2)))
return w
h=0.03
h0=0.03
T=2.5
gamma=0.6
K=2.5
L=100000
matrix=np.zeros((100,100))
for i in range(100):
for b in range(100):
K = 2.5
T = 2.5
result=1
while abs(result) > 10 ** (-12):
c = -math.pi
first = first_term(gamma, h, T, L)
second = second_term(h, h0, gamma, L)
result = (first - second) / L
if result > 0:
T = T + K / 2
elif result < 0:
T = T - K / 2
K = K / 2
gc = gcoperator(T, gamma, h, L)
gs = gsoperator(T, gamma, h, L)
g0 = g0operator(T, gamma, h, L)
W = witness1(gs, g0, gc)
w = witness2(gs, g0, gc)
if W < w:
matrix[i, b] = W
else:
matrix[i, b] = w
h0=h0+0.03
h=h+0.03
h0=0.03
np.savetxt('matrixgamma=0.6.txt', matrix)
a=np.loadtxt('matrixgamma=0.6.txt')
cmap=colors.ListedColormap(['yellow', 'white'])
bounds=[-2, 0, 2]
norm=colors.BoundaryNorm(bounds, cmap.N)
img=plt.imshow(a, interpolation='nearest', origin='lower', cmap=cmap, norm=norm)
plt.colorbar(img, cmap=cmap, norm=norm, boundaries=bounds)
plt.show()
I'm sorry but I have simplified a little bit your witnessN functions, but I hope that you can adapt my solution, in which the key points are
to save the values for the grid evaluations of witnessN
to use Numpy's logical functions
to use the fact that Booleans can be used as 0 or 1 integers,
With respect to plotting, you can omit the plt.contourf statement, but I like the additional lines subdividing the fields.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import BoundaryNorm, ListedColormap
witness1 = lambda X, Y: np.sin(X-Y/2)
witness2 = lambda X, Y: np.cos(X/2+2*Y)
x = np.linspace(-6, 6, 241)
X, Y = np.meshgrid(x, x)
W = witness1(X, Y)
w = witness2(X, Y)
Wp, wp, Wgtw = W>0, w>0, W>w
values = np.where(Wgtw, W, w)
colors = np.where(np.logical_and(1-Wgtw, 1-wp), 0, 0)
colors += np.where(np.logical_and( Wgtw, 1-Wp), 1, 0)
colors += np.where(np.logical_and( Wgtw, Wp), 2, 0)
colors += np.where(np.logical_and(1-Wgtw, wp), 3, 0)
# change colors to your taste
# w<0, W<0, W>0, w>0
cm = ListedColormap([ 'y', 'b', 'r', 'g'])
norm=BoundaryNorm([-0.5, 0.5, 1.5, 2.5, 3.5], 4)
pc = plt.pcolor(X, Y, colors, norm=norm, cmap=cm)
ct = plt.contour(X, Y, values, [-.9, -0.1, 0.1, 0.9], colors='k')
lb = plt.clabel(ct)
cf = plt.contourf(X, Y, colors, norm=norm, cmap=cm, alpha=0.6)
cb = plt.colorbar(pc)
cb.set_ticks([0, 1, 2, 3])
cb.set_ticklabels(['w<0', 'W<0', 'W>0', 'w>0'])
plt.show()
I am trying to inverse a set of maps using this answer here. I used two of his methods so there is more detail as to how they work in his answer. I also left some comments out to shorten the code.
I have my own camera matrix and distortion coeff's that I use to create an x and y map with cv2.initUndistortRectifyMap(), but when I pass them to invert_maps() I get an out-of-bounds error shown below.
None of this (except the bottom part) is my code and its pretty advanced stuff so I have no clue how to debug it. And I dont have enough credit to comment on the orignal answer. Anyone got a solution?
import numpy as np
import cv2 as cv2
from scipy import ndimage as ndi
from matplotlib import pyplot as plt
import glob
def bilinear_inverse(p, vertices, numiter=4):
p = np.asarray(p)
v = np.asarray(vertices)
sh = p.shape[1:]
if v.ndim == 2:
v = np.expand_dims(v, axis=tuple(range(2, 2 + len(sh))))
# Start in the center
s = .5 * np.ones((2,) + sh)
s0, s1 = s
for k in range(numiter):
# Residual
r = v[0] * (1 - s0) * (1 - s1) + v[1] * s0 * (1 - s1) + v[2] * s0 * s1 + v[3] * (1 - s0) * s1 - p
# Jacobian
J11 = -v[0, 0] * (1 - s1) + v[1, 0] * (1 - s1) + v[2, 0] * s1 - v[3, 0] * s1
J21 = -v[0, 1] * (1 - s1) + v[1, 1] * (1 - s1) + v[2, 1] * s1 - v[3, 1] * s1
J12 = -v[0, 0] * (1 - s0) - v[1, 0] * s0 + v[2, 0] * s0 + v[3, 0] * (1 - s0)
J22 = -v[0, 1] * (1 - s0) - v[1, 1] * s0 + v[2, 1] * s0 + v[3, 1] * (1 - s0)
inv_detJ = 1. / (J11 * J22 - J12 * J21)
s0 -= inv_detJ * (J22 * r[0] - J12 * r[1])
s1 -= inv_detJ * (-J21 * r[0] + J11 * r[1])
return s
def invert_map(xmap, ymap, diagnostics=False):
"""
Generate the inverse of deformation map defined by (xmap, ymap) using inverse bilinear interpolation.
"""
# Generate quadrilaterals from mapped grid points.
quads = np.array([[ymap[:-1, :-1], xmap[:-1, :-1]],
[ymap[1:, :-1], xmap[1:, :-1]],
[ymap[1:, 1:], xmap[1:, 1:]],
[ymap[:-1, 1:], xmap[:-1, 1:]]])
# Range of indices possibly within each quadrilateral
x0 = np.floor(quads[:, 1, ...].min(axis=0)).astype(int)
x1 = np.ceil(quads[:, 1, ...].max(axis=0)).astype(int)
y0 = np.floor(quads[:, 0, ...].min(axis=0)).astype(int)
y1 = np.ceil(quads[:, 0, ...].max(axis=0)).astype(int)
# Quad indices
i0, j0 = np.indices(x0.shape)
# Offset of destination map
x0_offset = x0.min()
y0_offset = y0.min()
# Index range in x and y (per quad)
xN = x1 - x0 + 1
yN = y1 - y0 + 1
# Shape of destination array
sh_dest = (1 + x1.max() - x0_offset, 1 + y1.max() - y0_offset)
# Coordinates of destination array
yy_dest, xx_dest = np.indices(sh_dest)
xmap1 = np.zeros(sh_dest)
ymap1 = np.zeros(sh_dest)
TN = np.zeros(sh_dest, dtype=int)
# Smallish number to avoid missing point lying on edges
epsilon = .01
# Loop through indices possibly within quads
for ix in range(xN.max()):
for iy in range(yN.max()):
# Work only with quads whose bounding box contain indices
valid = (xN > ix) * (yN > iy)
# Local points to check
p = np.array([y0[valid] + ix, x0[valid] + iy])
# Map the position of the point in the quad
s = bilinear_inverse(p, quads[:, :, valid])
# s out of unit square means p out of quad
# Keep some epsilon around to avoid missing edges
in_quad = np.all((s > -epsilon) * (s < (1 + epsilon)), axis=0)
# Add found indices
ii = p[0, in_quad] - y0_offset
jj = p[1, in_quad] - x0_offset
ymap1[ii, jj] += i0[valid][in_quad] + s[0][in_quad]
xmap1[ii, jj] += j0[valid][in_quad] + s[1][in_quad]
# Increment count
TN[ii, jj] += 1
ymap1 /= TN + (TN == 0)
xmap1 /= TN + (TN == 0)
if diagnostics:
diag = {'x_offset': x0_offset,
'y_offset': y0_offset,
'mask': TN > 0}
return xmap1, ymap1, diag
else:
return xmap1, ymap1
# cam matrix and dist coeff's that I brought
cam_matrix = np.array([ [1223.07784, 0, 926.80065],
[ 0, 1231.71291, 546.10496],
[ 0, 0, 1]], dtype='float32')
distortion_profile = np.array([-0.32077, 0.15041, 0.001004, 0.00028, -0.04252], dtype='float32')
# get current maps
mapx, mapy = cv2.initUndistortRectifyMap(cam_matrix, distortion, None, cam_matrix, (1920, 1080), 5)
# invert the maps
mapx_invert, mapy_invert = invert_map(mapx, mapy)
# apply mapping to image
inversed = cv2.remap(img, mapx_invert, mapy_invert ,cv2.INTER_LINEAR)
cv2.imwrite('inversed.png', inversed)
Error:
File "c:\Users\...\redist_image2.py", line 121, in invert_map
ymap1[ii, jj] += i0[valid][in_quad] + s[0][in_quad]
IndexError: index 1382 is out of bounds for axis 1 with size 1020
I watched some tutorials and tried to create a Perlin noise generator in python.
It takes in a tuple for the number of vectors in the x and y directions and a scale for the distance in pixels between the arrays, then calculates the dot product between each pixel and each of the 4 arrays surrounding it, It then interpolates them bilinearly to get the pixel's value.
here's the code:
from PIL import Image
import numpy as np
scale = 16
size = np.array([8, 8])
vectors = []
for i in range(size[0]):
for j in range(size[1]):
rand = np.random.rand() * 2 * np.pi
vectors.append(np.array([np.cos(rand), np.sin(rand)]))
interpolated_map = np.zeros(size * scale)
def interpolate(x1, x2, w):
t = (w % scale) / scale
return (x2 - x1) * t + x1
def dot_product(a, b):
return a[0] * b[0] + a[1] * b[1]
for i in range(size[1] * scale):
for j in range(size[0] * scale):
dot_products = []
for m in range(4):
corner_vector_x = round(i / scale) + (m % 2)
corner_vector_y = round(j / scale) + int(m / 2)
x = i - corner_vector_x * scale
y = j - corner_vector_y * scale
if corner_vector_x >= size[0]:
corner_vector_x = 0
if corner_vector_y >= size[1]:
corner_vector_y = 0
corner_vector = vectors[corner_vector_x + corner_vector_y * (size[0])]
distance_vector = np.array([x, y])
dot_products.append(dot_product(corner_vector, distance_vector))
x1 = interpolate(dot_products[0], dot_products[1], i)
x2 = interpolate(dot_products[2], dot_products[3], i)
interpolated_map[i][j] = (interpolate(x1, x2, j) / 2 + 1) * 255
img = Image.fromarray(interpolated_map)
img.show()
I'm getting this image:
but I should be getting this:
I don't know what's going wrong, I've tried watching multiple different tutorials, reading a bunch of different articles, but the result is always the same.
I need to draw a circle that's not perfect, I mean at some points on the circle the radius needs to change (be greater or lower) in order to cause the desired deformation.
This image for instance shows a circle with 1 single deformation:
The number of the deformations is random and the positions also.
I am using the code below to draw a normal circle :
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2*np.pi, 200)
radius = 0.4
a = radius * np.cos(theta)
b = radius * np.sin(theta)
figure, axes = plt.subplots(1)
axes.plot(a, b)
axes.set_aspect(1)
plt.show()
Do you have any ideas how can I achieve this?
Making the radius depend on theta, we could have a function f such that:
When further than 2 steps away from an angle theta1: f(t) = 1
At 1 and 2 steps away f(1) = f(2) = 1
At theta1 there is a deformation such that f(0) = k, for some k
At 0 and 2, the tangent to the deformation should be zero
For negative t, we can use f on the absolute value
If f would be a polynomial, it could be of degree 4, so f = a*t**4 + b*t**3 + c*t**2 + d*t + e. The symbolic math library, sympy, can find suitable values for these parameters with the given constraints.
from sympy import Eq, solve
from sympy.abc import a, b, c, d, e, t, k
f = a * t ** 4 + b * t ** 3 + c * t ** 2 + d * t + e
eq1 = Eq(f.subs(t, 0), k)
eq2 = Eq(f.subs(t, 1), 1)
eq3 = Eq(f.subs(t, 2), 1)
eq4 = Eq(f.diff(t).subs(t, 0), 0)
eq5 = Eq(f.diff(t).subs(t, 2), 0)
sol = solve([eq1, eq2, eq3, eq4, eq5], (a, b, c, d, e))
This generates (after some rewriting), the following expression for f:
k + (2 * t ** 2 - 9 * t + 11) * t ** 2 * (1 - k) / 4
Now, use this function to draw the deformed circle:
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(0, 2 * np.pi)
k = 0.8
theta1 = 80 * np.pi / 180 # a deformation at theta 80 degrees
alpha = 36 * np.pi / 180 # have a special point every 36 degrees (10 on the circle)
th = theta - theta1 # the difference between the angles, still needs to be careful to make this difference symmetrical to zero
t = np.abs(np.where(th < np.pi, th, th - 2 * np.pi)) / alpha # use absolute value and let alpha represent a step of 1
r = np.where(t > 2, 1, k + (2 * t ** 2 - 9 * t + 11) * t ** 2 * (1 - k) / 4) # the deformed radius
plt.plot(np.cos(theta), np.sin(theta), ':r')
plt.plot(r * np.cos(theta), r * np.sin(theta), '-b')
plt.fill(r * np.cos(theta), r * np.sin(theta), color='blue', alpha=0.2)
for i in range(-5, 5):
plt.plot(np.cos(theta1 + i * alpha), np.sin(theta1 + i * alpha), 'xk')
plt.axis('equal')
plt.show()
I am trying to calculate g(x_(i+2)) from the value g(x_(i+1)) and g(x_i), i is an integer, assuming I(x) and s(x) are Gaussian function. If we know x_i = 100, then the summation from 0 to 100, I don't know how to handle g(x_i) with the subscript in python, knowing the first and second value, we can find the third value, after n cycle, we can find the nth value.
Equation:
code:
import numpy as np
from matplotlib import pyplot as p
from math import pi
def f_s(x, mu_s, sig_s):
ss = -np.power(x - mu_s, 2) / (2 * np.power(sig_s, 2))
return np.exp(ss) / (np.power(2 * pi, 2) * sig_s)
def f_i(x, mu_i, sig_i):
ii = -np.power(x - mu_i, 2) / (2 * np.power(sig_i, 2))
return np.exp(ii) / (np.power(2 * pi, 2) * sig_i)
# problems occur in this part
def g(x, m, mu_s, sig_s, mu_i, sig_i):
for i in range(1, m): # specify the number x, x_1, x_2, x_3 ......X_m
h = (x[i + 1] - x[i]) / e
for n in range(0, x[i]): # calculate summation
sum_f = (f_i(x[i], mu_i, sig_i) - f_s(x[i] - n, mu_s, sig_s) * g_x[n]) * np.conj(f_s(n +
x[i], mu_s, sig_s))
g_x[1] = 1 # initial value
g_x[2] = 5
g_x[i + 2] = h * sum_f + 2 * g_x[i + 1] - g_x[i]
return g_x[i + 2]
x = np.linspace(-10, 10, 10000)
e = 1
d = 0.01
m = 1000
mu_s = 2
sig_s = 1
mu_i = 1
sig_i = 1
p.plot(x, g(x, m, mu_s, sig_s, mu_i, sig_i))
p.legend()
p.show()
result:
I(x) and s(x)