Stereo-Image and Depthmap to 3D-Scatterplot with Python and Matplotlib - python

I have a stereo-image and a depthmap of said image. I would like to make a scatterplot representing a 3d-Image of the picture. This is what i tried, but I get several errors, like the dimensions not fitting, etc.
The Problem is: the Scatter plot wants quadratic inputs. So I use the same length and widht. When i plot the picture I only see a line of points instead of the picture. What am I doing wrong?
import matplotlib as mpl
import numpy as np
import matplotlib.pyplot as plt
import cv2
from mpl_toolkits.mplot3d import Axes3D
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
img = cv2.imread('helmet.jpg', 1)
dmap = cv2.imread('dmap_real.png', 1)
xarr = np.arange(3632)
yarr = np.arange(3632)
c = img[xarr,yarr,:] / 256
z = dmap[xarr, yarr, 0]
ax.scatter(xarr, xarr, z, c=c, label='point cloud')
ax.legend()
plt.show()
Here are the used Pictures as reference:
depthmap: http://i.imgur.com/1OzNBIn.png
stereo-image: http://i.imgur.com/LMiek3H.jpg

The numpy function meshgrid might be what you're looking for. That will give you the x and y values for a grid the size of your image. If you plot every point in the image with scatter, you won't see your original image and it will be slow. Here's an example of plotting points from an image over an image:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
# Example image
image_file = cbook.get_sample_data('grace_hopper.png')
image = plt.imread(image_file)
(r, c, b) = np.shape(image)
# X and Y coordinates of points in the image, spaced by 10.
(X, Y) = np.meshgrid(range(0, c, 10), range(0, r, 10))
# Display the image
plt.imshow(image)
# Plot points from the image.
plt.scatter(X, Y, image[Y,X])
plt.show()

Related

matplotlib plot numpy array of images as markers

There are a lot of posts on plotting pre-saved png images as scatter plot markers but I'm wondering if there's a way to take an array of 2D arrays (lets naively call them images) and, given x and y coordinates, use them as scatter markers without having to save out as pngs and then read in.
For example, say you have these rather dull 'images':
import numpy as np
images = np.random.uniform(0,1,(5,10,10))
... that is, we have 5 lots of 10 by 10, 2D images.
If we want to plot these 'images' as markers at the following 5 locations specified by x and y coordinates:
x, y, = np.array([0, 2, -3, 6, 6.5]), np.array([10, 3, -2, -1, 0.2])
... what is the best way to go about doing this?
Closest example I have tried but failed to make work:
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage
# Convert the images into PIL images
# How? Using: https://stackoverflow.com/a/62144323/8188120
# Why? Maybe PIL images are nice and easy for plotting as markers.. I'm grasping at straws really
pil_images = []
for i in range(images.shape[0]):
pil_images.append(Image.fromarray(np.uint8(images[i])).convert('RGB'))
# Try plotting the images as markers
# Why this method? Saw it in this thread and continued grasping for more straws: https://stackoverflow.com/a/53851017/8188120
fig, ax = plt.subplots()
for i in range(len(pil_images)):
ab = AnnotationBbox(OffsetImage(pil_images[i]), x[i], y[i], frameon=False)
ax.add_artist(ab)
fig.savefig(image_path + 'funny_markers.png')
plt.close('all')
You need to set the limits of the axis accordingly, or they would default to just (0,1):
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
fig, ax = plt.subplots()
for x0, y0, img in zip(x, y, images):
ab = AnnotationBbox(OffsetImage(img, zoom=5, cmap='gray'), (x0, y0), frameon=False)
ax.add_artist(ab)
plt.xlim(x.min(), x.max()+1)
plt.ylim(y.min(), y.max()+1)
plt.show()
Output:

Plotting and assigning axes to a PNG-file in Python

I have several png-files showing some 2d-graphs which I would like to apply axes to. I already know the extent of the files (i.e. x-range and y-range), but do not know how to properly add axes. My current approach is to load the image using
import matplotlib.image as mpimg
img = mpimg.imread('fig_6a.png')
which gives me an rgba-matrix. In addition I generate two vectors
import numpy as np
x_shape = img.shape[1]
y_shape = img.shape[0]
x_vals = np.linspace(x_min, x_max, x_shape)
y_vals = np.linspace(y_min, y_max, y_shape)
create a meshgrid
X, Y = np.meshgrid(x_vals, y_vals)
and would like to use functions such as
import matplotlib.pyplot as plt
fig = plt.pcolormesh(X, Y, img)
plt.show()
to create the final picture. Unfortunately, pcolormesh does not accept rgba-arrays. What would be the best approach to be able to add these axes to my image, and plot it afterwards?

Python Contour Plot/HeatMap

I have x and y coordinates in a df from LoL matches and i want to create a contour plot or heat map to show where the player normally moves in a match.
Does any one know how can I do it?
A contour plot or heat map needs 3 values. You have to provide x, y and z values in order to plot a contour since x and y give the position and z gives the value of the variable you want to show the contour of as a variable of x and y.
If you want to show the movement of the players as a function of time you should look at matplotlib's animations. Or if you want to show the "players density field" you have to calculate it.
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import scipy
from scipy.stats.kde import gaussian_kde
from scipy import ndimage
from matplotlib import cm
#select the x and y coordinates
x = df['x']
y = df['y']
nbins= 512
k = gaussian_kde(np.vstack([x,y]))
xi, yi = np.mgrid[0:512, 0:512] #size of the image/map in px
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
im = mpimg.imread("map.png")#Put he background image
fig = plt.figure(figsize=(9,9))
ax2 = fig.add_subplot()
ax2.contourf(xi, yi, zi.reshape(xi.shape), alpha=0.5, cmap=cm.jet, extent=[1, -1, 1, -1])
ax2.set_xlim(0, 512)
ax2.set_ylim(0, 512)
ax2.axis('off')
plt.imshow(im, extent=[0, 512, 0, 512])
plt.savefig(f'Enemies/Clausura/{team}/{team} Stats/{summoner[1]} Early.png', dpi=None, bbox_inches='tight', pad_inches=0)

Modifying matplotlib patchcollecton3d data

How do I modify the xyz data of a 3d scatter plot in matplotlib for fast on-line animations? In other words where do matplotlib patchcollection3d objects save the xyz coordinates, and how do I set them? For example:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import numpy as np
## generate some random data
pts = np.random.uniform(0,10,(10,20,30))
plt.close('all')
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
patch_collection_instance = ax.scatter(pts[:,0],pts[:,1],pts[:,2], c='m', marker='o')
What do I do next with patch_collection_instance if, for example, I want to translate all points by a random amount?
The coordinates are stored in the attribute _offsets3d. While there is a get_offsets() method and a set_offsets() method, those appear to be inherited from the 2d version and don't work properly for 3d. _offsets3d contains a tuple of x, y, and z coordinate tuples. Let's say you want to shift every point by 10 in the x direction. You'd add 10 to every number in the x-coordinate tuple, then set the _offsets3d to the new tuple.
I am not sure if this is faster than just clearing the figure and calling scatter again with new coordinates, which should have the same effect.
Example code:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import numpy as np
from copy import copy
## generate some random data
pts = np.random.uniform(0,10,(10,20,30))
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
patch_collection_instance = ax.scatter(pts[:,0],pts[:,1], pts[:,2], c='m', marker='o')
x, y, z = patch_collection_instance._offsets3d
print x
x = [i + 10 for i in x]
offsets = (x, y, z)
patches2 = copy(patch_collection_instance)
patches2._offsets3d = offsets
patches2._facecolor3d = [[0, 0, 1, 1]]
ax.add_collection3d(patches2)
plt.xlim(0, 20)
plt.show()

matplotlib scatterplot: adding 4th dimension by the marker shape

I would like to add a fourth dimension to the scatter plot by defining the ellipticity of the markers depending on a variable. Is that possible somehow ?
EDIT:
I would like to avoid a 3D-plot. In my opinion these plots are usually not very informative.
You can place Ellipse patches directly onto your axes, as demonstrated in this matplotlib example. To adapt it to use eccentricity as your "third dimension") keeping the marker area constant:
from pylab import figure, show, rand
from matplotlib.patches import Ellipse
import numpy as np
import matplotlib.pyplot as plt
N = 25
# ellipse centers
xy = np.random.rand(N, 2)*10
# ellipse eccentrities
eccs = np.random.rand(N) * 0.8 + 0.1
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
A = 0.1
for pos, e in zip(xy, eccs):
# semi-minor, semi-major axes, b and a:
b = np.sqrt(A/np.pi * np.sqrt(1-e**2))
a = A / np.pi / b
ellipse = Ellipse(xy=pos, width=2*a, height=2*b)
ax.add_artist(ellipse)
ax.set_xlim(0, 10)
ax.set_ylim(0, 10)
show()
Of course, you need to scale your marker area to your x-, y- values in this case.
You can use colorbar as the 4th dimension to your 3D plot. One example is as shown below:
import matplotlib.cm as cmx
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
def scatter3d(x,y,z, cs, colorsMap='jet'):
cm = plt.get_cmap(colorsMap)
cNorm = matplotlib.colors.Normalize(vmin=min(cs), vmax=max(cs))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(x, y, z, c=scalarMap.to_rgba(cs))
scalarMap.set_array(cs)
fig.colorbar(scalarMap,label='Test')
plt.show()
x = np.random.uniform(0,1,50)
y = np.random.uniform(0,1,50)
z = np.random.uniform(0,1,50)
so scatter3D(x,y,z,x+y) produces:
with x+y being the 4th dimension shown in color. You can add your calculated ellipticity depending on your specific variable instead of x+y to get what you want.
To change the ellipticity of the markers you will have to create them manually as such a feature is not implemented yet. However, I believe you can show 4 dimensions with a 2D scatter plot by using color and size as additional dimensions. You will have to take care of the scaling from data to marker size yourself. I added a simple function to handle that in the example below:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.rand(60,4)
def scale_size(data, data_min=None, data_max=None, size_min=10, size_max=60):
# if the data limits are set to None we will just infer them from the data
if data_min is None:
data_min = data.min()
if data_max is None:
data_max = data.max()
size_range = size_max - size_min
data_range = data_max - data_min
return ((data - data_min) * size_range / data_range) + size_min
plt.scatter(data[:,0], data[:,1], c=data[:,2], s=scale_size(data[:,3]))
plt.colorbar()
plt.show()
Result:

Categories