I'm trying to plot an svg image but it's showing up inverted, would anyone know how to fix this?
Input
<img src="https://static.wikia.nocookie.net/ptstarwars/images/9/9d/Jedi_symbol.svg" alt="drawing" style="width:200px;"/>
Code
import svgpathtools
import numpy as np
import matplotlib.pyplot as plt
svgpaths, attributes = svgpathtools.svg2paths('./jedi_symbol.svg')
paths = []
for n, (attrs, svgpath) in enumerate(zip(attributes, svgpaths)):
path = []
for segment in svgpath:
num_steps = int(segment.length()/0.5)
tt = np.linspace(0, 1, num_steps)
xy = np.array([segment.point(t) for t in tt])
if len(xy) > 0:
if path and xy[0] == path[-1]:
xy = xy[1:]
path.extend(xy)
paths.append(np.array(path))
paths = np.array(paths)
x_table, y_table = paths[0].real, paths[0].imag
# Simple method to center the image
x_table = x_table - min(x_table)
y_table = y_table - min(y_table)
x_table = x_table - max(x_table) / 2
y_table = y_table - max(y_table) / 2
fig, ax = plt.subplots(figsize=(5, 5))
ax.set_aspect('equal', 'datalim')
ax.plot(x_table, y_table)
Output
It just multiply the y by -1
ax.plot(x_table, -1*y_table)
I've a 2D numpy array initialized to 0 and I've picked 4 points in that array. I want to interpolate values between them to create a closed shape and fill that shape with value 1. Here's the code
a = np.zeros((256, 256))
depth = np.random.randint(50, 200)
corner1 = np.random.randint(0, 100)
corner2 = np.random.randint(150, 250)
top_max = depth - np.random.randint(10, 25)
bottom_max = depth + np.random.randint(10, 25)
top_max_loc = np.random.randint(corner1 + 10, corner2 - 10)
bottom_max_loc = np.random.randint(corner1 + 10, corner2 - 10)
left_point = (depth, corner1)
right_point = (depth, corner2)
top_point = (top_max, top_max_loc)
bottom_point = (bottom_max, bottom_max_loc)
a[left_point] = 1
a[right_point] = 1
a[top_point] = 1
a[bottom_point] = 1
print(left_point)
print(right_point)
print(top_point)
print(bottom_point)
and here's the plot of the points
What I am looking for is to fill the array with some random shape and get results as follows (just the yellow colored shape)
It looks like you're looking for the convex hull given a set of points, i.e the smallest shape that encloses them all. For that you can use skimage.morphology.convex_hull_image. Since you have only one shape, you can reduce the search to the bounding box of the set of points. For multiple objects you might be interested in convex_hull_object.
Here's an example generated with your code:
from skimage.morphology import convex_hull_image
x,y = np.where(a)
x_min, x_max = x.min(), x.max()
y_min, y_max = y.min(), y.max()
plt.figure(figsize=(10,10))
plt.imshow(a[x_min:x_max+1, y_min:y_max+1])
Now obtain the convex hull of the sliced image, and assign back to the array with:
a[x_min:x_max+1, y_min:y_max+1] = convex_hull_image(a[x_min:x_max+1, y_min:y_max+1])
Resulting in:
plt.figure(figsize=(10,10))
plt.imshow(a)
How do I downsample an image of any resolution to a quarter of the size by averaging the pixels in numpy?
What I came up through research only works for images that are square (i.e 512 X 512 down to 128 X 128) but will not work for images that are different dimensions (i.e 2400 X 1800 down to 600 X 450). In those cases I get a IndexError: index 450 is out of bounds for axis 1 with size 450.
I am trying to perform this task with numpy array manipulation and without installing other packages and libraries.
I researched a function
numpy.mean()
but I don't know how to use it in reference to this problem.
import cv2
import numpy as np
def quarter_res_avg(im):
original_width = im.shape[1]
original_height = im.shape[0]
width = original_width / 4
height = original_height / 4
resized_image = np.zeros(shape=(width, height, 3), dtype=np.uint8)
scale = 4
for i in range(width):
for j in range(height):
temp = np.array([0, 0, 0])
for x in range(scale):
for y in range(scale):
temp += im[i*scale+x, j*scale+y]
resized_image[i, j] = temp/(scale*scale)
return resized_image
im = cv2.imread('Lenna_test_image.png', 1)
cv2.imwrite('Lenna_test_image_avg.png', quarter_res_avg(im))
Any ideas are much appreciated.
Thanks.
import numpy as np
import skimage.measure
your_array = np.random.rand(2400, 800)
new_array = skimage.measure.block_reduce(your_array, (4,4), np.mean)
print(new_array.shape)
Out[18]: (600, 450)
First reshape your M x N image into a (M//4) x 4 x (N//4) x 4 array, then use np.mean in the second and last dimensions.
from typing import Tuple
import numpy as np
def downsample_by_averaging(img: np.ndarray, window_shape: Tuple[int, int]) -> np.ndarray:
return np.mean(
img.reshape((
*img.shape[:-2],
img.shape[-2] // window_shape[-2], window_shape[-2],
img.shape[-1] // window_shape[-1], window_shape[-1],
)),
axis=(-1, -3),
)
downsample_by_averaging(img, (4, 4))
The answer that worked for me with the help from #MarkSetchell in the comments of the question.
Without using np.mean()
def quarter_res_avg(im):
original_width = im.shape[1]
original_height = im.shape[0]
width = original_width / 4
height = original_height / 4
resized_image = np.zeros(shape=(height, width, 3), dtype=np.uint8)
scale = 4
for i in range(height):
for j in range(width):
temp = np.array([0, 0, 0])
for x in range(scale):
for y in range(scale):
temp += im[i*scale + x, j*scale + y]
resized_image[i, j] = temp/(scale*scale)
return resized_image
im = cv2.imread('Lenna_test_image.png', 1)
cv2.imwrite('Lenna_test_image_resized.png', quarter_res_avg(im))
By using np.mean() replace the for loops with:
for i in range(0, original_height, scale):
for j in range(0, original_width, scale):
resized_image[i/scale, j/scale] = np.mean(im[i:i + scale, j:j+scale], axis=(0,1))
I have an array A size of 64x64. An ROI region has pixels intensities is 100 if the pixels are inside ROI. Outside of ROI is zero
import numpy as np
A= np.zeros((64,64))
A[16:48,26:48]=100
I want to change the intensity value of inside ROI to a Gaussian distribution with the mean is 100 and variance is 1. How can I do it? I tried the below code but it is not correct because np.random.normal for whole array, instead of the ROI
noise_value = np.random.normal(0, 1, size=A.shape)
A = A*noise_value + A
try this:
import numpy as np
import matplotlib.pyplot as plt
def gaus(x, a, m, s):
return np.sqrt(a)*np.exp(-(x-m)**2/(2*s**2))
# if you want it normalized:
#return 1/(np.sqrt(2*np.pi*s**2))*np.exp(-(x-m)**2/(2*s**2))
xx, yy = np.meshgrid(np.arange(100), np.arange(100))
gaus2d = gaus(xx, 100, 50, 10)*gaus(yy, 100, 50, 10)
plt.figure()
plt.imshow(gaus2d)
plt.colorbar()
The region you're multiplying noise_value by needs to be the same shape as noise_value. Try:
A[16:48,26:48] = A[16:48,26:48] * noise_value + A[16:48,26:48]
also, your formula A = A * noise_value + A, doesn't seem to match the intensity distribution you describe. If that's the case, you might just:
A = np.zeros((64,64))
A[16:48,26:48] = np.random.normal(100, 1, size=[32,22])
I'm trying to plot several surfaces, each of a different color, in Plotly for Python.
Specifically, a surface shows the predicted reward function for taking an action at different points in phase space. Since I have several possible actions at each point, each is a different surface. I'd like to color each surface uniquely, but independent of the x,y, or z coordinate.
I've tried to follow answer in R, but I can't figure out what I've done wrong. I always get the same blue color. Since I'm using PyPlot in other parts of my code, I'm choosing colors from the default matplotlib tableau.
Here's a basic example with toy data.
import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objs as go
import plotly.offline as off
off.init_notebook_mode()
make_int = np.vectorize(int)
cmap = plt.get_cmap("tab10")
saddle = np.array([[x**2-y**2 for x in np.arange(-10,11)] for y in np.arange(-10,11)])
paraboloid = np.array([[x**2 + y**2-100 for x in np.arange(-10,11)] for y in np.arange(-10,11)])
mycolors_a = make_int(256*np.array(cmap(1)[0:3])).reshape((1, 1,-1)).repeat(21, axis = 0).repeat(21, axis =1)
mycolors_b = make_int(256*np.array(cmap(2)[0:3])).reshape((1, 1,-1)).repeat(21, axis = 0).repeat(21, axis =1)
trace_a = go.Surface(z = saddle, surfacecolor = mycolors_a, opacity = .7, showscale = False, name = "Trace A")
trace_b = go.Surface(z = paraboloid, surfacecolor = mycolors_b, opacity = .7, showscale = False, name = "Trace B")
data = [trace_a, trace_b]
off.iplot(data)
Produces the following:
I should see a blue saddle and an orange paraboloid, but I don't. Note that even if I change the argument to cmap, I always get the same blue color. Thanks for your help!
The documentation is a bit cryptic here.
surfacecolor
(list, numpy array, or Pandas series of numbers, strings, or datetimes.)
Sets the surface color values, used for setting a color scale independent of z.
I never managed to put a list of strings, i.e. color values like 'rgb(0.3, 0.5, 0)', or RGB tuples in it.
But you can define your own color scale with the needed colors.
colorscale = [[0, 'rgb' + str(cmap(1)[0:3])],
[1, 'rgb' + str(cmap(2)[0:3])]]
and then provide a numeric array with the same dimensions as your plotted values.
colors_saddle = np.zeros(shape=saddle.shape)
All values are set to 0 and will therefore map to the first color in your colorscale. The same for the next color.
In addition you need to set cmax and cmin manually.
Complete code
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objs as go
import plotly.offline as off
off.init_notebook_mode()
make_int = np.vectorize(int)
cmap = plt.get_cmap("tab10")
saddle = np.array([[x**2-y**2 for x in np.arange(-10,11)] for y in np.arange(-10,11)])
paraboloid = np.array([[x**2 + y**2-100 for x in np.arange(-10,11)] for y in np.arange(-10,11)])
colors_saddle = np.zeros(shape=saddle.shape)
colors_paraboloid = np.ones(shape=paraboloid.shape)
colorscale = [[0, 'rgb' + str(cmap(1)[0:3])],
[1, 'rgb' + str(cmap(2)[0:3])]]
trace_a = go.Surface(z=saddle,
surfacecolor=colors_saddle,
opacity=.7,
name="Trace A",
cmin=0,
cmax=1,
colorscale=colorscale)
trace_b = go.Surface(z=paraboloid,
surfacecolor=colors_paraboloid,
opacity=.7,
name="Trace B",
cmin=0,
cmax=1,
showscale=False,
colorscale=colorscale)
data = [trace_a, trace_b]
off.iplot(data)
You can combine all surfaces in one and set in colorscale range for each surface
It can also resolve overlapping problem, so you would see the line of surfaces intersection clearly like here
import numpy as np
import plotly.graph_objs as go
# normalize values to range [start,end] for getting color from cmap
def norm_v_in_range(v,start,end):
v_min = v.min()
v_max = v.max()
range_length = (end - start)
if v_min-v_max == 0 :
v.fill(range_length/5 + start)
return v
return (v-v_min)/(v_max-v_min)*range_length + start
def combine_all_surfaces_in_one(X,Y,*Z) :
# prepare colors and ranges for diffrent surfaces
colors = [ 'rgb(180, 110, 20)', 'rgb( 20, 180, 110)', 'rgb(110, 20, 180)',
'rgb(180, 180, 20)', 'rgb( 20, 180, 180)', 'rgb(180, 20, 180)',
'rgb(180, 20, 20)', 'rgb( 20, 180, 20)', 'rgb( 20, 20, 180)',
'rgb(180, 110, 20)', 'rgb( 20, 180, 110)', 'rgb(110, 20, 180)',
'rgb(255, 127, 127)', 'rgb(127, 255, 127)']
N = len(Z)
points = np.linspace(0, 1, N + 1)
custom_colorscale = []
ranges = []
for i in range(1,N+1) :
ranges.append([points[i-1],points[i]-0.05])
custom_colorscale.append([points[i-1], colors[i]])
custom_colorscale.append([points[i]-0.05,'rgb(255, 250, 220)'])
custom_colorscale.append([1, 'rgb(220, 250, 220)'])
# transparent connection between grahps: np.nan in z prevent ploting points
transparen_link = np.empty_like(X[0], dtype=object)
transparen_link.fill(np.nan)
# include first graph
combined_X = X
combined_Y = Y
combined_Z = Z[0]
# prepare collor matrix for first graph (Z[0])
start = ranges[0][0]
end = ranges[0][1]
custom_surfacecolor = norm_v_in_range(Z[0],start,end)
# second aray combined with first in backward direction, so connection would on one side of graphs, not intersect them
direction = -1
range_index = 1
for next_Z in Z[1:] :
combined_X = np.vstack([combined_X, combined_X[-1], X[::direction][0], X[::direction][0], X[::direction]])
combined_Y = np.vstack([combined_Y, combined_Y[-1], Y[::direction][0], Y[::direction][0], Y[::direction]])
combined_Z = np.vstack([combined_Z, combined_Z[-1], transparen_link, next_Z[::direction][0], next_Z[::direction]])
# prepare collors for next Z_
start = ranges[range_index][0]
end = ranges[range_index][1]
next_surfacecolor = norm_v_in_range(next_Z,start,end)
custom_surfacecolor = np.vstack([custom_surfacecolor,custom_surfacecolor[-1], transparen_link, next_surfacecolor[::direction][0], next_surfacecolor[::direction]])
# change direction
direction *= -1
range_index += 1
return combined_X, combined_Y, combined_Z, custom_surfacecolor, custom_colorscale
X = np.arange(-1.2, 1.06, 0.1)
Y = np.arange(0.2, 1.06, 0.1)
X, Y = np.meshgrid(X, Y)
Z1 = 2*np.sin(np.sqrt(20*X**2+20*Y**2))
Z2 = 2*np.cos(np.sqrt(20*X**2+20*Y**2))
Z3 = X*2+0.5
Z4 = Y*0+1.0
Z5 = Y*0-1.0
Z6 = Y*0+0.0
x,y,z,custom_surfacecolor,custom_colorscale = combine_all_surfaces_in_one(X,Y,Z1,Z2,Z3,Z4,Z5)
# opacity =0.9 - many overlaped areas, better witot it
fig = go.Figure(data=[go.Surface(x=x, y=y, z=z,
surfacecolor=custom_surfacecolor, cmin=0, cmax = 1,
colorscale=custom_colorscale,showscale=False,
)] )
fig.show()