How can generate a raw file from multi-band tif file? - python

I try open a tif image with 16-bit per pixel and multi-band to convert it in a raw file. I'm using PIL with the next commands i = Image.open('image.tif') and after I use rawData = i.tostring(). It doesn't work with multi-band tif image.
The error is:
File "C:\Python27\lib\site-packages\PIL\Image.py", line 1980, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
The directory contains the file.
How I must do it ?

GDAL is pretty good at opening multiband rasters, and supports 11 different band types, including int16.
from osgeo import gdal
import numpy as np
ds = gdal.Open('image.tif')
# loop through each band
for bi in range(ds.RasterCount):
band = ds.GetRasterBand(bi + 1)
# Read this band into a 2D NumPy array
ar = band.ReadAsArray()
print('Band %d has type %s'%(bi + 1, ar.dtype))
raw = ar.tostring()

Related

How to save a new raster with the projections of the previous raster

I tried to make an algorithm in Python where I entered a georeferenced raster (known coordinate system), all its negative values were transformed to zero, and then a new image was saved with the georeference of the initial image.
import skimage.io
import pandas as pd
import numpy as np
pathhr = 'C:\\Users\\dataset\\S30W051.tif'
HR = skimage.io.imread(pathhr)
df1 = pd.DataFrame(HR)
HR_changed = df1[df1 < 0] = 0
#save function
savedata = df1.to_numpy()
skimage.io.imsave('C:\\Users\\dataset\\S30W051_TEST.tif', savedata)
But when I save my raster at the end of this script, I get a non-georeferenced TIFF raster.
How do I keep the same coordinate system as the initial raster (without transforming the output raster into local coordinates)?
I ask for help in solving this problem. Thanks.
You could use rasterio for opening and saving your tiff files, and copy the metadata of the initial raster to the new raster.
import rasterio as rio
# Load the original image
with rio.open(pathhr, 'r') as r:
HR = r.read()
meta = r.meta
# Do any transformation you like (on the numpy array)
HR_changed = HR[HR < 0] = 0
# Save the changed raster
with rio.open('C:\\Users\\dataset\\S30W051_TEST.tif', 'w', **meta) as dst:
dst.write(HR_change)

How to read .img format image?

I have a image in .img format. The image size is 1920x1200 px. It's a RGB image with 8 bit depth. I am using the following python code to recover this image. However, the error can display the image but the image content isn't correct. I don't where did I do wrong. Anyone can help?
w, h = 1920, 1200 # img image size in px
# read img files and save them to png
with open(file_add, 'rb') as f:
# Seek backwards from end of file by 3 bytes per pixel
f.seek(-w*h*3, 2)
img = np.fromfile(f, dtype=np.uint8).reshape((h, w, 3))
# Save as PNG, and retain 8-bit resolution
PIL.Image.fromarray(img).save('result.png')
I would like to upload the img file, however, it's larger than the 2Mb limitation.
Your file is in some hideous, Microsoft-designed "Compound File Binary Format" which is described here. I don't run Windows so I cannot unpack it. There are apparently tools available, but I cannot vouch for any of them:
https://openrpmsgfile.com/cfbf.html
http://fileformats.archiveteam.org/wiki/Microsoft_Compound_File
There seems to be a Python module called olefile that can read these things. I installed it and was able to test your file and find your image within it as follows:
#!/usr/bin/env python3
import olefile
import numpy as np
from PIL import Image
# Open file
ole = olefile.OleFileIO('image.img')
# Get a directory listing
ole.dumpdirectory()
# Open image stream within file and read
stream = ole.openstream('image/__102/DataObject')
data = stream.read()
# Define image width, height and bytes per pixel
w, h, bpp = 1920, 1200, 3
imsize = w * h * bpp
# Check data size and image size
print(f'Data size: {len(data)}, Image size: {imsize}')
# There are 192 bytes difference, assume it is a header and take our bytes from the tail of the file
data = data[-imsize:]
# Make into Numpy array
na = np.frombuffer(data, dtype=np.uint8).reshape((h*3,w))
# Convert from interleaved by line to interleaved by plane
R = na[0::3]
G = na[1::3]
B = na[2::3]
na = np.dstack((R,G,B))
# Make into PIL Image and save, but you could equally use OpenCV or scikit-image here
Image.fromarray(na).save('result.jpg')
Sample Output from running script:
'Root Entry' (root) 192 bytes
'NonDataObjects' (stream) 26 bytes
'Signature' (stream) 12 bytes
'image' (storage)
'__102' (storage)
'DataObject' (stream) 6912192 bytes
'DataObjectChilds' (stream) 4 bytes
'DataObjectStub' (stream) 6760 bytes
Data size: 6912192, Image size: 6912000
I worked out it was a CFBF file from the following. Firstly, if you run the Linux/Unix file command to determine the type of the file, you get this:
file image.img
image.img: Composite Document File V2 Document, Cannot read section info
Secondly, if you dump the file with xxd you will see the CFBF signature bytes referred to in the links above:
xxd image.img
00000000: d0cf 11e0 a1b1 1ae1 0000 0000 0000 0000 ................
Keywords: OLE file, CFBF, Composite Document File V2 Document, IMG format, d0cf11e0a1b1
This post seems to be accomplishing what you're looking for. It reads the data with matplotlib instead, but it should still be able to do what you want.
You can use if you have in case .img with .hdr nibabel or simpleITK and transformed to numpy array
important !! simplITK support maximum 5D.
import nibabel as nib
data_path="sample/path"
array_data=nib.load(data_path).get_fdata() # you get your matrix
print(array_data.shape)
exemple with SimpleITK
import SimpleITK as sitk
data_path="/your/path"
imgObj=sitk.Image(data_path) # you will get and Image object it's a complex data format to handle
array_data = sitk.GetArrayFromImage(imgObj) # you array matrix

Convert image files to a csv file

I'm working on a The Japanese Female Facial Expression (JAFFE) Database. You can find the database on this link http://www.kasrl.org/jaffe.html.
When I download the database I got a list of pictures. I would like to convert these image files into a CSV file but I'm still new in deep learning and I don't know how. Someone proposed that I work with OpenCV. what should I do?
i have simple example
i hope this help you.
from PIL import Image
import numpy as np
import sys
import os
import csv
def createFileList(myDir, format='.jpg'):
fileList = []
print(myDir)
for root, dirs, files in os.walk(myDir, topdown=False):
for name in files:
if name.endswith(format):
fullName = os.path.join(root, name)
fileList.append(fullName)
return fileList
# load the original image
myFileList = createFileList('path/to/directory/')
for file in fileList:
print(file)
img_file = Image.open(file)
# get original image parameters...
width, height = img_file.size
format = img_file.format
mode = img_file.mode
# Make image Greyscale
img_grey = img_file.convert('L')
value = np.asarray(img_grey.getdata(), dtype=np.int).reshape((img_grey.size[1], img_grey.size[0]))
value = value.flatten()
print(value)
with open("img_pixels.csv", 'a') as f:
writer = csv.writer(f)
writer.writerow(value)
Install pillow, numpy, pandas
Convert the image to RGB
plot RGB along with x,y co-ordinates in a pandas Dataframe
Save the dataframe as csv
Sample working code as below
from PIL import Image
from numpy import array, moveaxis, indices, dstack
from pandas import DataFrame
image = Image.open("data.tiff")
pixels = image.convert("RGB")
rgbArray = array(pixels.getdata()).reshape(image.size + (3,))
indicesArray = moveaxis(indices(image.size), 0, 2)
allArray = dstack((indicesArray, rgbArray)).reshape((-1, 5))
df = DataFrame(allArray, columns=["y", "x", "red","green","blue"])
print(df.head())
df.to_csv("data.csv",index=False)
You don't need to write any code, you can just use vips on the command-line on macOS, Linux or Windows.
So, in Terminal (or Command Prompt, if on Windows):
vips im_vips2csv TM.AN1.190.tiff result.csv
will convert the 256x256 greyscale image TM.AN1.190.tiff into a 256 line CSV with 256 entries per line. Simples!
If you want to replace the tab separators by commas, you can do:
tr '\t' , < result.csv > NewFile.csv

Saving to EPS not supported in Python Pillow?

I am trying to convert an image from PNG to EPS using Pillow. The following code gives an error:
from PIL import Image
Image.open("Image1.png").save("Image1.eps", fmt='EPS')
Which reads:
Traceback (most recent call last):
File "C:/Users/pbreach/Dropbox/Personal/FigureConversion/convert.py", line 15, in <module>
convert_image(in_name, out_name, fmt='EPS')
File "C:/Users/pbreach/Dropbox/Personal/FigureConversion/convert.py", line 4, in convert_image
Image.open(in_name).save(out_name, fmt)
File "C:\Users\pbreach\Continuum\Anaconda3\lib\site-packages\PIL\Image.py", line 1826, in save
save_handler(self, fp, filename)
File "C:\Users\pbreach\Continuum\Anaconda3\lib\site-packages\PIL\EpsImagePlugin.py", line 362, in _save
raise ValueError("image mode is not supported")
ValueError: image mode is not supported
Is EPS really not supported? In the documentation EPS is second on the list of fully supported formats. Is there anything that I need to do if this is not the case?
Weirdly enough, if I do Image.open("Image1.png").save("Image1.jpg", fmt='EPS') it works but saves to JPG.
Pillow supports EPS, but cannot write it with alpha channel (RGBA, LA)
https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html?highlight=eps#eps:
Pillow identifies EPS files containing image data, and can read files
that contain embedded raster images (ImageData descriptors). If
Ghostscript is available, other EPS files can be read as well. The EPS
driver can also write EPS images. The EPS driver can read EPS images
in L, LAB, RGB and CMYK mode, but Ghostscript may convert the images
to RGB mode rather than leaving them in the original color space. The
EPS driver can write images in L, RGB and CMYK modes.
Helped for me to convert the image to RGB mode before saving
from PIL import Image
fig = Image.open("Image1.png")
if fig.mode in ('RGBA', 'LA'):
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html?highlight=eps#eps
print('Current figure mode "{}" cannot be directly saved to .eps and should be converted (e.g. to "RGB")'.format(fig.mode))
fig = fig.convert('RGB')
out_fig = "Image1.eps"
fig.save(out_fig)
fig.close()
But sometimes I had problems: got black background in .eps instead of transparent .png. For me helped remove_transparency() function from https://stackoverflow.com/a/35859141/7444782 to substitute the transparent background to a specified color (white by default)
from PIL import Image
def remove_transparency(im, bg_color=(255, 255, 255)):
"""
Taken from https://stackoverflow.com/a/35859141/7444782
"""
# Only process if image has transparency (http://stackoverflow.com/a/1963146)
if im.mode in ('RGBA', 'LA') or (im.mode == 'P' and 'transparency' in im.info):
# Need to convert to RGBA if LA format due to a bug in PIL (http://stackoverflow.com/a/1963146)
alpha = im.convert('RGBA').split()[-1]
# Create a new background image of our matt color.
# Must be RGBA because paste requires both images have the same format
# (http://stackoverflow.com/a/8720632 and http://stackoverflow.com/a/9459208)
bg = Image.new("RGBA", im.size, bg_color + (255,))
bg.paste(im, mask=alpha)
return bg
else:
return im
fig = Image.open("Image1.png")
if fig.mode in ('RGBA', 'LA'):
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html?highlight=eps#eps
print('Current figure mode "{}" cannot be directly saved to .eps and should be converted (e.g. to "RGB")'.format(fig.mode))
fig = remove_transparency(fig)
fig = fig.convert('RGB')
out_fig = "Image1.eps"
fig.save(out_fig)
fig.close()
It might be that you have a png with an alpha channel. EPS in PIL does not support transparency in raster images.
So if you remove the alpha channel by im[:,:,0:2] it might just work like a charm.
It will be more than one line, however.

Simplest way to save array into raster file in Python

With one 2-d array in the shape of (100, 100), I want to save it into raster file in .tiff format.
I can use gdal package to read tiff files which are already exist. But I still can't find a simple way to transform the 2-d array into tiff file.
Using plt.imsave("xx.tif",array) or
def array_to_raster(array):
"""Array > Raster
Save a raster from a C order array.
:param array: ndarray
"""
dst_filename = 'xxx.tiff'
x_pixels = 100 # number of pixels in x
y_pixels = 100 # number of pixels in y
driver = gdal.GetDriverByName('GTiff')
dataset = driver.Create(
dst_filename,
x_pixels,
y_pixels,
1,
gdal.GDT_Float32, )
dataset.GetRasterBand(1).WriteArray(array)
dataset.FlushCache() # Write to disk.
return dataset, dataset.GetRasterBand(1)
They all failed to achieve my target. The second method was adapted from here which can transform an array into a geotiff with a projection.
Is there some simple way to save array into .tiff, so I can call it by import the tiff file next time.
Any advices would be appreciate.
A tif raster could be considered as 'array+proj+geotransforms'.
If you want to write an array to a tiff ,you can refer to the following code:
dst_filename = 'xxx.tiff'
x_pixels = 100 # number of pixels in x
y_pixels = 100 # number of pixels in y
driver = gdal.GetDriverByName('GTiff')
dataset = driver.Create(dst_filename,x_pixels, y_pixels, 1,gdal.GDT_Float32)
dataset.GetRasterBand(1).WriteArray(array)
# follow code is adding GeoTranform and Projection
geotrans=data0.GetGeoTransform() #get GeoTranform from existed 'data0'
proj=data0.GetProjection() #you can get from a exsited tif or import
dataset.SetGeoTransform(geotrans)
dataset.SetProjection(proj)
dataset.FlushCache()
dataset=None
Easiest way with imageio
If you don't care about its projection it's a oneliner:
import imageio
imageio.imwrite('test.tiff', [[0,255],[255,0]])

Categories

Resources