Convert 3D .stl file to JPG image with Python - python

How do I convert a 3D object in any STL file into a JPG or PNG image.
I tried searching a little bit online but I wasn't been able to arrive at finding any possible solutions.
Can anyone help me with the code that can do this straight forward task with Python? IS there any libraries that can help with that?
EDIT :
Code Sample:
from mpl_toolkits import mplot3d
from matplotlib import pyplot
import pathlib
DIR = str(pathlib.Path(__file__).parent.resolve()).replace('\\', '/')
path = f'{DIR}/any_stl_file.stl'
# Create a new plot
figure = pyplot.figure()
axes = mplot3d.Axes3D(figure)
# Load the STL files and add the vectors to the plot
your_mesh = mesh.Mesh.from_file(path)
axes.add_collection3d(mplot3d.art3d.Poly3DCollection(your_mesh.vectors))
# Auto scale to the mesh size
scale = your_mesh.points.flatten()
axes.auto_scale_xyz(scale, scale, scale)
pyplot.savefig(f"{DIR}/the_image.jpg")```

Take a look at https://pypi.org/project/numpy-stl/
This code snippet is from the link above:
from stl import mesh
from mpl_toolkits import mplot3d
from matplotlib import pyplot
# Create a new plot
figure = pyplot.figure()
axes = mplot3d.Axes3D(figure)
# Load the STL files and add the vectors to the plot
your_mesh = mesh.Mesh.from_file('tests/stl_binary/HalfDonut.stl')
axes.add_collection3d(mplot3d.art3d.Poly3DCollection(your_mesh.vectors))
# Auto scale to the mesh size
scale = your_mesh.points.flatten()
axes.auto_scale_xyz(scale, scale, scale)
# Show the plot to the screen
pyplot.show()
To save a pyplot object as an image:
pyplot.savefig("file_name.jpg")

Related

Possible to reconstruct audio only with spectrogram image?

So I'm creating some spectrograms with librosa to be saved as images, after which I intend to make modifications to the image directly (ie. add random noise, etc), then I would like to reconstruct the audio from that image.
Anyway, some research led me to examples of similar processes (see here or here) but nothing quite like I'm trying to do, which is take a png/jpg image of a spectrogram and convert it back to an usable audio file.
Here's the full code I'm using to generate the spec images:
import librosa
from librosa import display
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
filename = librosa.util.example_audio_file()
y, sr = librosa.load(filename)
window_size = 1024
window = np.hanning(window_size)
stft = librosa.core.spectrum.stft(y, n_fft=window_size, hop_length=512, window=window)
out = 2 * np.abs(stft) / np.sum(window)
fig = plt.Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
fig.subplots_adjust(left=0,right=1,bottom=0,top=1)
ax.axis('tight')
ax.axis('off')
p = librosa.display.specshow(librosa.amplitude_to_db(out, ref=np.max), ax=ax, y_axis='log', x_axis='time')
fig.savefig('spectrogram.png')
Which would produce this exact image:
spectrogram.png
But functions like librosa.istft or librosa.griffinlim expect the output of librosa.core.spectrum.stft, and I haven't been able to reverse that entire process coming from just the image file. Assuming I had this picture, is there any way to build the audio back again (even if it's lossy)? What kind of other information would be necessary, and how could I do it?
Thanks in advance.

How to project GeoTIFF to specified area extent?

I am trying to display GeoTIFF file in specified area. What I want to do is project multiband GeoTIFF file to specified area.
My GeoTIFF is satellite image containing 3 bands over area of Europe. I want to project it to area of Central Europe (extent defined by lat/lot). I have been trying to solve this using rasterio but I've been unlucky so far. This is what I get after executing:
import georaster
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib.pyplot import figure
#define path to geotiff
file = "/home/lubomir/Desktop/Sentinel3_OLCI/RGB/OLCI_201812140859_Natural_Color.tif"
m = Basemap(epsg=3395,llcrnrlat=45,urcrnrlat=55,\
llcrnrlon=5,urcrnrlon=25,lat_ts=15,resolution='f')
m.drawcoastlines(linewidth=0.5, color='g')
m.fillcontinents(color='beige')
m.drawcountries(linewidth=0.5, color='m')
#load GeoTIFF multiband file
image = georaster.MultiBandRaster(file)
plt.imshow(image.r, extent=image.extent, zorder=10)
plt.savefig('test.tiff')
plt.show()
without_geotiff
As you can see, generated image does not contain my GeoTIF. Any idea how to solve this ?
In order to make use of the Basemap's projection, you must use
m.imshow(image.r, extent=image.extent, zorder=10)
in place of
plt.imshow(image.r, extent=image.extent, zorder=10)
Hope it helps.

Cartopy Image from Grib2 file does not align with Coastlines and Borders in same CRS

This seems like it's going to be something simple that will fix my code but I think I've just looked at the code too much at the moment and need to get some fresh eyes on it. I'm simply trying to bring in a Grib2 file that I've downloaded from NCEP for the HRRR model. According to their information the grid type is Lambert Conformal with the extents of (21.13812, 21.14055, 47.84219, 47.83862) for the latitudes of the corners and (-122.7195, -72.28972, -60.91719, -134.0955) for the longitudes of the corners for the models domain.
Before even trying to zoom into my area of interest I just wanted to simply display an image in the appropriate CRS however when I try to do this for the domain of the model I get the borders and coastlines to fall within that extent but the actual image produced from the Grib2 file is just zoomed into. I've tried to use extent=[my domain extent] but it always seems to crash the notebook I'm testing it in. Here is my code and the associated image that I get from it.
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy
from mpl_toolkits.basemap import Basemap
from osgeo import gdal
gdal.SetConfigOption('GRIB_NORMALIZE_UNITS', 'NO')
plt.figure()
filename='C:\\Users\\Public\\Documents\\GRIB\\hrrr.t18z.wrfsfcf00.grib2'
grib = gdal.Open(filename, gdal.GA_ReadOnly)
z00 = grib.GetRasterBand(47)
meta00 = z00.GetMetadata()
band_description = z00.GetDescription()
bz00 = z00.ReadAsArray()
latitude_south = 21.13812 #38.5
latitude_north = 47.84219 #50
longitude_west = -134.0955 #-91
longitude_east = -60.91719 #-69
fig = plt.figure(figsize=(20, 20))
title= meta00['GRIB_COMMENT']+' at '+meta00['GRIB_SHORT_NAME']
fig.set_facecolor('white')
ax = plt.axes(projection=ccrs.LambertConformal())
ax.add_feature(cartopy.feature.BORDERS, linestyle=':')
ax.coastlines(resolution='110m')
ax.imshow(bz00,origin='upper',transform=ccrs.LambertConformal())
plt.title(title)
plt.show()
Returns Just Grib File
If I change:
ax = plt.axes(projection=ccrs.LambertConformal()
to
ax = plt.axes(projection=ccrs.LambertConformal(central_longitude=-95.5,
central_latitude=38.5,cutoff=21.13)
I get my borders but my actual data is not aligned and it creates what I'm dubbing a Batman plot.
Batman Plot
A similar issue occurs even when I do zoom into the domain and still have my borders present. The underlying data from the Grib file doesn't change to correspond to what I'm trying to get.
So as I've already said this is probably something that is an easy fix that I'm just missing but if not, it would be nice to know what step or what process I'm screwing up that I can learn from so that I don't do it in the future!
Updated 1:
I've added and changed some code and am back to getting only the image to show without the borders and coastlines showing up.
test_extent = [longitude_west,longitude_east,latitude_south,latitude_north]
ax.imshow(bz00,origin='upper',extent=test_extent)
This gives me the following image.
Looks exactly like image 1.
The other thing that I'm noticing which maybe the root cause of all of this is that when I'm printing out the value for plt.gca().get_ylim() and plt.gca().get_xlim() I'm getting hugely different values depending on what is being displayed.
It seems that my problem arises from the fact that the Grib file regardless of whether or not it can be displayed properly in other programs just doesn't play nicely with Matplotlib and Cartopy out of the box. Or at the very least does not with the Grib files that I was using. Which for sake of this perhaps helping others in the future are from the NCEP HRRR model that you can get here or here.
Everything seems to work nicely if you convert the file from Grib2 format to NetCDF format and I was able to get what I wanted with the borders, coastlines, etc. on the map. I've attached the code and the output below to show how it worked. Also I hand picked a single dataset that I wanted to display to test versus my previous code so incase you want to look at the rest of datasets available in the file you'll need to utilize ncdump or something similar to view the information on the datasets.
import numpy as np
from netCDF4 import Dataset
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy
import cartopy.feature as cfeature
from osgeo import gdal
gdal.SetConfigOption('GRIB_NORMALIZE_UNITS', 'NO')
nc_f = 'C:\\Users\\Public\\Documents\\GRIB\\test.nc' # Your filename
nc_fid = Dataset(nc_f, 'r') # Dataset is the class behavior to open the
# file and create an instance of the ncCDF4
# class
# Extract data from NetCDF file
lats = nc_fid.variables['gridlat_0'][:]
lons = nc_fid.variables['gridlon_0'][:]
temp = nc_fid.variables['TMP_P0_L1_GLC0'][:]
fig = plt.figure(figsize=(20, 20))
states_provinces = cfeature.NaturalEarthFeature(category='cultural', \
name='admin_1_states_provinces_lines',scale='50m', facecolor='none')
proj = ccrs.LambertConformal()
ax = plt.axes(projection=proj)
plt.pcolormesh(lons, lats, temp, transform=ccrs.PlateCarree(),
cmap='RdYlBu_r', zorder=1)
ax.add_feature(cartopy.feature.BORDERS, linestyle=':', zorder=2)
ax.add_feature(states_provinces, edgecolor='black')
ax.coastlines()
plt.show()
Final Preview of Map

Display x,y coordinates for loaded image file

I need to load an image file with matplotlib and see the coordinates of points within it, as if it were a simple x,y scatter plot.
I can assume that the x axis extension is [0, 1], and the y axis follows the same scaling. I can load the above image file with
from PIL import Image
im = Image.open("del.png")
im.show()
but this uses ImageMagick (I'm on a Linux system) to display the image, and no coordinates are shown in the bottom left part of the plot window as would for a simple data plot:
Use pyplot for that:
from matplotlib import pyplot as plt
plt.imshow(plt.imread('del.png'))

Reading matplotlib graphs from file

Is it possible to read (say) 4 .jpeg graphs produced by matplotlib into matplotlib again so that they can be replotted as subplots? If so, how would I do it?
If you really want to do it by reading jpeg files of existing plots (noting the comments), one way might be to read in the graphs in with scipy.misc.imread. I've set the axis labels off assuming you saved the original graphs with labels and everything.
import matplotlib.pyplot as plt
from scipy.misc import imread
# Create a figure with 2x2 arranged subplots
fig, ax = plt.subplots(2,2)
# Plot images one by one here
# (Just using the same jpeg file in this example...)
im1 = imread("graph1.jpg")
ax[0,0].imshow(im1)
ax[0,0].axis('off')
ax[0,1].imshow(im1)
ax[0,1].axis('off')
ax[1,0].imshow(im1)
ax[1,0].axis('off')
ax[1,1].imshow(im1)
ax[1,1].axis('off')
fig.show()

Categories

Resources