APLpy coordinate change to pixel values - python

Does anyone know how to change the coordinate values to the pixel values of a fits file image in APLpy?

The only way I could think of is just pass in the data-array instead of the fits file. If it has no WCS information it must operate in pixel-space.
from astropy.io import fits # or import pyfits
with fits.open(filename) as hdus:
data = hdus[0].data
f1 = aplpy.FITSFigure(data)
# ... whatever you want to do thereafter.
I haven't used APLpy maybe there is a better way but I haven't found anything in the documentation.

Related

Voxelization of STL-file; writing into np.array

I would like to voxelise a .stl file and write it into an np.array. The resolution of the voxels should be adjustable.
Here is my code for this:
component_path = r"C:\Users\User\documents\components\Test_1.stl"
mesh = o3d.io.read_triangle_mesh(component_path)
voxel_grid = o3d.geometry.VoxelGrid.create_from_triangle_mesh(mesh, voxel_size = 3)
ply_path = "voxel.ply"
o3d.io.write_voxel_grid(ply_path, voxel_grid, True,True,True)
pcd = o3d.io.read_point_cloud(ply_path)
list_path = "list.xyz"
o3d.io.write_point_cloud(list_path, pcd)
Then I read the coordinate points from the list, write them into a 3D array and plot them. When plotting, the border is not displayed for certain voxel sizes, as can be seen in the image (although it is present in the original). Is there a solution for this so that it doesn't happen no matter what voxel size?
voxelized picture with missing border
In addition, the voxel size changes the maximum dimension. So the component originally has three times the length as it is shown here. How can this be adjusted? (If I just multiply a factor, the voxels stay small but pull the distances apart).
Is there perhaps a more reasonable way to write a voxelisation of a .stl file and put the centers of voxels into an np.array?
If anyone ever has the same problem and is looking for a solution:
This project worked for me: GitHub: stl-to-voxel
The model is then also filled. If the maximum dimension is known, you can determine the exact voxel size via the resolution.
Here is some code:
import stl_reader
import stltovoxel
import numpy as np
import copy
import os
import sys
input=r"C:\Users\user\Example.stl"
output=r"C:\Users\user\Test.xyz"
resolution = 50 #Resolution, into how many layers the model should be divided
stltovoxel.doExport(input, output, resolution)
Afterwards, you can read the coordinates from the list, write them into an array and process them further (quite normally).

Preserving the WCS information of a FITS file when rebinned

Aim : Rebin an existing image (FITS file) and write the new entries into a new rebinned image (also a FITS file).
Issue : Rebinned FITS file and the original FITS file seem to have mismatched co-ordinates (figure shown later in the question).
Process : I will briefly describe my process to shed more light. The first step is to read the existing fits file and define numpy arrays
from math import *
import numpy as np
import matplotlib.pyplot as plt
from astropy.visualization import astropy_mpl_style
from astropy.io import fits
import matplotlib.pyplot as plt
%matplotlib notebook
import aplpy
from aplpy import FITSFigure
file = 'F0621_HA_POL_0700471_HAWDHWPD_PMP_070-199Augy20.fits'
hawc = fits.open(file)
stokes_i = np.array(hawc[0].data)
stokes_i_rebinned = congrid(stokes_i,newdim,method="neighbour", centre=False, minusone=False)
Here "congrid" is a function I have used for near-neigbhour rebinning that rebins the original array to a new dimension given by "newdim". Now the goal is to write this rebinned array back into the FITS file format as a new file. I have several more such arrays but for brevity, I just include one array as an example. To keep the header information same, I read the header information of that array from the existing FITS file and use that to write the new array into a new FITS file. After writing, the rebinned file can be read just like the original :-
header_0= hawc[0].header
fits.writeto("CasA_HAWC+_rebinned_congrid.fits", rebinned_stokes_i, header_0, overwrite=True)
rebinned_file = 'CasA_HAWC+_rebinned_congrid.fits'
hawc_rebinned= fits.open(rebinned_file)
To check how the rebinned image looks now I plot them
cmap = 'rainbow'
stokes_i = hawc[0]
stokes_i_rebinned = hawc_rebinned[0]
axi = FITSFigure(stokes_i, subplot=(1,2,1)) # generate FITSFigure as subplot to have two axes together
axi.show_colorscale(cmap=cmap) # show I
axi_rebinned = FITSFigure(stokes_i_rebinned, subplot=(1,2,2),figure=plt.gcf())
axi_rebinned.show_colorscale(cmap=cmap) # show I rebinned
# FORMATTING
axi.set_title('Stokes I (146 x 146)')
axi_rebinned.set_title('Rebinned Stokes I (50 x 50)')
axi_rebinned.axis_labels.set_yposition('right')
axi_rebinned.tick_labels.set_yposition('right')
axi.tick_labels.set_font(size='small')
axi.axis_labels.set_font(size='small')
axi_rebinned.tick_labels.set_font(size='small')
axi_rebinned.axis_labels.set_font(size='small')
As you see for the original and rebinned image, the X,Y co-ordinates seem mismatched and my best guess was that WCS (world co-ordinate system) for the original FITS file wasn't properly copied for the new FITS file, thus causing any mismatch. So how do I align these co-ordinates ?
Any help will be deeply appreciated ! Thanks
I'm posting my answer in an astropy slack channel here should this be useful for others.
congrid will not work because it doesn't include information about the WCS. For example, your CD matrix is tied to the original image, not the re-binned set. There are a number of way to re-bin data with proper WCS. You might consider reproject although this often requires another WCS header to re-bin to.
Montage (though not a Python tool but has Python wrappers) is potentially another way.
As #astrochun already said, your re-binning function does not adjust the WCS of the re-binned image. In addition to reproject and Montage, astropy.wcs.WCSobject has slice() method. You could try using it to "re-bin" the WCS like this:
from astropy.wcs import WCS
import numpy as np
wcs = WCS(hawc[0].header, hawc)
wcs_rebinned = wcs.slice((np.s_[::2], np.s_[::2]))
wcs_hdr = wcs_rebinned.to_header()
header_0.update(wcs_hdr) # but watch out for CD->PC conversion
You should also make a "real" copy of hawc[0].header in header_0= hawc[0].header, for example as header_0= hawc[0].header.copy() or else header_0.update(wcs_hdr) will modify hawc[0].header as well.

How to extract a profile of value from a raster along a given line?

How to extract a profile of values from a raster along a given shapefile line in Python?
I am struggling finding a method to extract a profile of values (e.g. topographic profile) from a raster (geotiff). The library Rasterio has a method to clip/extract value from a raster based on a polygon, but I cannot find an equivalent method for a line shapefile.
There is a basic method with scipy, but it does not inherently conserve geographic information like a method based on higher level toolbox like rasterio could provide.
In other words, I am looking for an equivalent in Python of what the tool Terrain Profile in QGIS offers.
Thanks
This is a bit different than extracting for a polygon, as you want to sample every pixel touched by the line, in the order they are touched (the polygon approaches don't care about pixel order).
It looks like it would be possible to adapt this approach to use rasterio instead. Given a line read from a shapefile using geopandas or fiona as a shapely object, you use the endpoints to derive a new equidistant projection that you use as dst_crs in a WarpedVRT and read pixel values from that. It looks like you would need to calculate the length of your line in terms of the number of pixels you want sampled, this is the width parameter of the WarpedVRT.
This approach may need to be adapted further if your line is not an approximately straight line between the endpoints.
If you want to just get the raw pixel values under the line, you should be able to use a mask in rasterio or rasterize directly, for each line. You may want to use the all_touched=True in the case of lines.
I had a similar problem and found a solution which works for me. The solution uses shapely to sample points on a line/lines and then accesses respective values from the GeoTiff, therefore the extracted profile follows the direction of the line. Here is the method that I ended up with:
def extract_along_line(xarr, line, n_samples=256):
profile = []
for i in range(n_samples):
# get next point on the line
point = line.interpolate(i / n_samples - 1., normalized=True)
# access the nearest pixel in the xarray
value = xarr.sel(x=point.x, y=point.y, method="nearest").data
profile.append(value)
return profile
Here is a working example with data from the copernicus-dem database and the line is the diagonal of the received tile:
import rioxarray
import shapely.geometry
import matplotlib.pyplot as plt
sample_tif = ('https://elevationeuwest.blob.core.windows.net/copernicus-dem/'
'COP30_hh/Copernicus_DSM_COG_10_N35_00_E138_00_DEM.tif')
# Load xarray
tile = rioxarray.open_rasterio(sample_tif).squeeze()
# create a line (here its the diagonal of tile)
line = shapely.geometry.MultiLineString([[
[tile.x[-1],tile.y[-1]],
[tile.x[0], tile.y[0]]]])
# use the method from above to extract the profile
profile = extract_along_line(tile, line)
plt.plot(profile)
plt.show()

Turn samples into Mesh

i want to load a mesh file (.obj), then want to use the trimesh.sample.sample_surface_even() function to get some points on the surface, turn the resulting points back into a mesh and save them back as an .obj file.
My problem is, that i dont know how to turn the samples back into a mesh that can be saved. Can somebody tell me what i should do step by step, to achieve that goal?
Here is my code so far:
import numpy as np
import trimesh
mesh = trimesh.load_mesh('mesh10.obj')
sampledmesh= trimesh.sample.sample_surface_even(mesh,500)
#? How to turn sampledmesh back into a mesh?
sampledmesh.export('mesh10_export.obj')
You can use the submesh function on the sampled face indices, which is the second element in the returned tuple:
sampledmesh = trimesh.sample.sample_surface_even(mesh,500)
sampled_submesh = mesh.submesh([sampledmesh[1]])[0]
submesh returns an array of meshes, but here we just have one, so we take the first mesh.

TypeError: Image data can not convert to float

I am trying to create a 16-bit image like so:
import skimage
import random
from random import randint
xrow=raw_input("Enter the number of rows to be present in image.=>")
row=int(xrow)
ycolumn=raw_input("Enter the number of columns to be present in image.=>")
column=int(ycolumn)
A={}
for x in xrange(1,row):
for y in xrange(1,column):
a=randint(0,65535)
A[x,y]=a
imshow(A)
But I get the error TypeError: Image data can not convert to float.
This question comes up first in the Google search for this type error, but does not have a general answer about the cause of the error. The poster's unique problem was the use of an inappropriate object type as the main argument for plt.imshow(). A more general answer is that plt.imshow() wants an array of floats and if you don't specify a float, numpy, pandas, or whatever else, might infer a different data type somewhere along the line. You can avoid this by specifying a float for the dtype argument is the constructor of the object.
See the Numpy documentation here.
See the Pandas documentation here
This happened for me when I was trying to plot an imagePath, instead of the image itself. The fix was to load the image, and plotting it.
The error occurred when I unknowingly tried plotting the image path instead of the image.
My code :
import cv2 as cv
from matplotlib import pyplot as plt
import pytesseract
from resizeimage import resizeimage
img = cv.imread("D:\TemplateMatch\\fitting.png") ------>"THIS IS THE WRONG USAGE"
#cv.rectangle(img,(29,2496),(604,2992),(255,0,0),5)
plt.imshow(img)
Correction:
img = cv.imread("fitting.png") --->THIS IS THE RIGHT USAGE"
First read the image as an array
image = plt.imread(//image_path)
plt.imshow(image)
I was also getting this error, and the answers given above says that we should upload them first and then use their name instead of a path - but for Kaggle dataset, this is not possible.
Hence the solution I figure out is by reading the the individual image in a loop in mpimg format. Here we can use the path and not just the image name.
I hope it will help you guys.
import matplotlib.image as mpimg
for img in os.listdir("/content/train"):
image = mpimg.imread(path)
plt.imshow(image)
plt.show()
From what I understand of the scikit-image docs (http://scikit-image.org/docs/dev/index.html), imshow() takes a ndarray as an argument, and not a dictionary:
http://scikit-image.org/docs/dev/api/skimage.io.html?highlight=imshow#skimage.io.imshow
Maybe if you post the whole stack trace, we could see that the TypeError comes somewhere deep from imshow().
try
import skimage
import random
from random import randint
import numpy as np
import matplotlib.pyplot as plt
xrow = raw_input("Enter the number of rows to be present in image.=>")
row = int(xrow)
ycolumn = raw_input("Enter the number of columns to be present in image.=>")
column = int(ycolumn)
A = np.zeros((row,column))
for x in xrange(1, row):
for y in xrange(1, column):
a = randint(0, 65535)
A[x, y] = a
plt.imshow(A)
plt.show()
Try to use this,
plt.imshow(numpy.real(A))
plt.show()
instead of plt.imshow(A)
This happened because you may transfer a wrong type to imshow(), for example I use albumentations.Compose to change image, and the result is a dict rather than numpy.ndarray. so just change
plt.imshow(cv2.cvtColor(aug(image=img), cv2.COLOR_BGR2RGB))
to
plt.imshow(cv2.cvtColor(aug(image=img)['image'], cv2.COLOR_BGR2RGB))
then it works.
I guess you may have this problem in Pycharm. If so, you may try this to your problem.
Go to File-Setting-Tools-Python Scientificin Pycharm and remove the option of Show plots in tool window.
Try this
plt.imshow(im.reshape(im.shape[0], im.shape[1]), cmap=plt.cm.Greys)
It would help in some cases.
In my case image path was wrong! So firstly, you might want to check if image path is correct :)
Or maybe the image path contains Chinese characters, changing to English characters will solve this question.
For this kind of error try checking file path or name
As for cv2 is concerned.
You might not have provided the right file type while cv2.imread().
eg jpg instead of png.
Or you are providing image path instead
of image's array. eg plt.imshow(img_path),
try cv2.imread(img_path) first then plt.imshow(img) or cv2.imshow(img).
The problem was that my array was in type u3 i changed it to float and it worked for me .
I had a dataframe with Image column having the image/pic data.Reshaping part depends to person to person and image they deal with mine had 9126 size hence it was 96*96.
a = np.array(df_train.iloc[0].Image.split(),dtype='float')
a = a.reshape(96,96)
plt.imshow(a)
Input should be array
plt.imshow(plt.imread('image_path'))
For an image file in .mat format.
I have done the following to show the image using the imshow() function.
mat = scipy.io.loadmat('point05m_matrix.mat')
x = mat.get("matrix")
print(type(x))
print(len(x))
plt.imshow(x, extent=[0,60,0,55], aspect='auto')
plt.show()

Categories