I have a problem with exporting a GeoTIFF file by using python and gdal.
What I want to do is to convert a NumPy array into a GeoTIFF file.
There are reference GeoTIFF files, so I want to make sure that the produced GeoTIFF file has proper geometric coordinates.
The problem is that the tiff file seems to be produced, but the values it contains are not good.
I tried to view the file by using QGIS, but the appearance of the image was completely black. In addition to the problem with the appearance of the image, the values are also changed from the original NumPy array. For example, the maximum value of the NumPy array is 149, but QGIS says that there is no such value in the file.
What is the cause of this problem, and how can I fix it?
The codes are here.
#Check the metadata of the reference file.
with rio.open('/content/drive/My Drive/Colab Notebooks/satellite_data/MCD12Q1/MCD12Q1.A2019001.IGBP.Buryat.geotiff.tif') as filename : filename.bounds
filename.meta["transform"]
#Output=> {'count': 1,'crs': CRS.from_epsg(4326),'driver': 'GTiff','dtype': 'uint8','height': 1920, 'nodata': None, 'transform': Affine(0.00416666, 0.0, 97.99955519999997, 0.0, -0.00416666, 58.0000512),
'width': 4800}
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
#Set some parameters
xsize=filename.meta["width"]
ysize=filename.meta["height"]
band=1
dtype = gdal.GDT_UInt16
output = gdal.GetDriverByName('GTiff').Create('/content/drive/My Drive/Colab Notebooks/outputs/output.tif', xsize, ysize, band, dtype)
output.SetGeoTransform((filename.meta["transform"][0],filename.meta["transform"][1],filename.meta["transform"][2],filename.meta["transform"][3],filename.meta["transform"][4],filename.meta["transform"][5]))
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
output.SetProjection(srs.ExportToWkt())
output.GetRasterBand(1).WriteArray(NumOfFiresExpanded["2019"]) #The "NumOfFireExpanded["2019"] is the target numpy array.
output.FlushCache()
output = None
I have an example here which takes numpy arrays and builds a GeoTiff.
How do I write/create a GeoTIFF RGB image file in python?
Use gdalinfo -stats <geotiff> to view the GeoTiff and make sure the range is good. Viewing 16-bit imagery can be non-deterministic depending on the viewer. QGIS is a good test viewer.
Related
Sorry for my english but it's not my first language.
I would like to create a program that:
Transform a jpeg or png image into an array (very important: I would like an array composed only of the values that the pixels of the image have and not metadata or other information. Where I can select each specific pixel of the image).
Save this array in a txt file.
Transform this array composed of only the pixel values of the image back into jpg or png image and save it in a file.
Requests:
Is the array I created with the program I wrote composed only of the pixel values of the image? is there also metadata or other information?
Is this a valid way to remove metadata from an image?
Is this a valid way to create the array representing that image pixel by pixel?
Is this a valid way to convert png images to jpeg or jpeg to png?
Thank you!
This is the program I created, any opinion?
import numpy as np
from PIL import Image
import sys
img_data = Image.open("imagea.jpeg")
img_arr = np.array(img_data)
np.set_printoptions(threshold=sys.maxsize)
print(img_arr.shape)
new_img = Image.fromarray(img_arr)
new_img.save("imageb.jpeg")
print("Image saved!")
file = open("file1.txt", "w+")
content = str(img_arr)
file.write(content)
file.close()
print("Finished!")
Loading an image and converting it to a Numpy array is a perfectly legitimate way of discarding all metadata including:
EXIF data, copyright data,
IPTC and XMP data,
ICC colour profile data
You can tell it's all gone by thinking about the Numpy array you hold and its dimensions and data type.
Note that you need to be careful with PNG palette images and images with an alpha channel.
Note that you can achieve this more simply on the command-line with ImageMagick using:
magick mogrify -strip IMAGE.JPG
Or with exiftool.
Note that you can achieve this by using a format that doesn't support metadata, such as NetPBM, with extension .ppm e.g.:
magick INPUT.JPG -strip -compress none RESULT.PPM # gives P3/plain ASCII file
magick INPUT.JPG -strip RESULT.PPM # gives P6/binary file
You can also read/write PPM files with PIL.
There are problems in my writing data into .tif file with gdal module in python.
I want to extract data (numpy array) from a tif file and modify some of its values before saving it into a new one, with the new file functioning normally. I use following script:
tif = gdal.Open('data/pre_heilj_mean90_15.tif') #original tif file
imwidth = tif.RasterXSize
imheight = tif.RasterYSize
data = tif.ReadAsArray()
data[100][100] = 100 #modify value
data = data.astype(np.float32)
driver = gdal.GetDriverByName("GTiff")
dataset = driver.Create('data/res.tif', imwidth, imheight, 1, gdal.GDT_Float32)
dataset.SetSpatialRef(tif.GetSpatialRef())
dataset.SetGeoTransform(tif.GetGeoTransform())
dataset.SetProjection(tif.GetProjection())
dataset.GetRasterBand(1).WriteArray(data)
dataset.FlushCache()
dataset=None
data=None
tif=None
I am certain that data in original tif file is 2-d and float32 type.
However, the new tif file(res.tif) is all black in ArcMap:
res.tif
Here is how the original tif file shows in ArcMap:
original tif file
And sizes of the two files differ a lot, original is 5287KB and the new one is 4633KB.
I want to know what goes wrong.(forgive my poor English pls)
You probably forgot to write the nodata value in the metadata of the output file. The fact that it's "black" is probably just due to stretching, if you stretch the output similar (min = ~406) is should look similar.
For example get the nodata value with:
nodata_value = tif.GetRasterBand(1).GetNoDataValue()
Then write/assign it with:
dataset.GetRasterBand(1).SetNoDataValue(nodata_value)
Keep in mind that this is a property of a band, so multiple bands in a single file can potentially have different nodata values.
I'm trying to take some VTK image data generated from a 3-D numpy array and convert it into poly data so it can be read by a package that only takes .vtp as an input format. I chose to use the marching cubes algorithm to take my point/node data as input and give poly data as an output. The data is segmented into two phases (0 = black, 255 = white), so only one contour is necessary. I tried using the vtkPolyDataReader class to create an object for the vtkMarchingCubes class, then using vtkPolyDataWriter to take the contoured marching cubes object and save it as a VTP file:
import vtk
input = 'mydata.vti'
reader = vtk.vtkPolydataReader()
reader.SetFileName(input)
reader.Update()
contour = vtk.vtkMarchingCubes()
contour.SetInputConnection(reader.GetOutputPort())
contour.SetValue(0, 128.)
contour.Update()
writer = vtk.vtkPolyDataWriter()
writer.SetInputData(contour.GetOutput())
writer.SetFileName('mydata.vtp')
writer.Update()
writer.Write()
When I run the code, it takes much less time than it ought to (the input file is about 2 GB), and the VTP file the code creates is less than 1 KB. I've been banging my head against a wall over this and poring over the VTK documentation and some provided examples, but I can't figure out what I've done wrong.
To read a .vtki file you need to use vtk.vtkXMLImageDataReader. You are trying to read an image file with a vtk.vtkPolyDataReader, which is designed for reading surface meshes.
I have a large 40 mb (about 173,397 lines) .dat file filled with binary data (random symbols). It is an astronomical photograph. I need to read and display it with Python. I am using a binary file because I will need to extract pixel value data from specific regions of the image. But for now I just need to ingest it into Python. Something like the READU procedure in IDL. Tried numpy and matplotlib but nothing worked. Suggestions?
You need to know the data type and dimensions of the binary file. For example, if the file contains float data, use numpy.fromfile like:
import numpy as np
data = np.fromfile(filename, dtype=float)
Then reshape the array to the dimensions of the image, dims, using numpy.reshape (the equivalent of REFORM in IDL):
im = np.reshape(data, dims)
I want to save floating-point numbers as pixels in an image file. I am currently working in OpenCV-python, but I had also tried it with Pillow (PIL). Both packages convert float pixel data to integer before writing them to the file.
I want to save pixel values such as:
(245.7865, 123.18788, 98.9866)
But when I read back the image file I get:
(246, 123, 99)
Somehow my floating-point numbers get rounded off and converted to integers.
How to stop PIL or OpenCV from converting them to integer?
Raster images are normally stored as integer values only. Instead save the numpy array directly like so
x = numpy.array([1, 2, 3])
with open('x.npy', 'wb') as f:
numpy.save(f, x)
Then load the variable back like so
x = numpy.load('x.npy')
Other alternatives include
Save one or more GRAY16 png images, with your floats multiplied and truncated.
Use the Netpbm format supporting floats.
Save a pickle.
The behavior you observe depends on the file format in which you save the image. Few image formats have a specification for floating-point pixel values. Though some do, first and foremost TIFF.
To demonstrate the desired behavior with a TIFF image writer, consider the following script. It uses the versatile image input/output library ImageIO, which relies on PILlow as one of its back-ends:
# Use Stack Overflow logo as sample image.
import imageio
logo = 'https://cdn.sstatic.net/Sites/stackoverflow/img/logo.png'
image = imageio.imread(logo)
# Normalize to 1. Pixel values are now floating-point.
image = image / image.max()
# Save as image file and read back in.
format = 'tiff'
imageio.imwrite(f'image.{format}', image)
print(f'wrote: {image.dtype}')
image = imageio.imread(f'image.{format}')
print(f'read: {image.dtype}')
The output of that script is:
wrote: float64
read: float64
If, on the other hand, you change the format to PNG (format = 'png' in the code), the output is:
Lossy conversion from float64 to uint8. Range [0, 1].
Convert image to uint8 prior to saving to suppress this warning.
wrote: float64
read: uint8