Creating a 32 bit image and saving as tif - python-3.x

This is a very basic question but I do not seem to find a good solution to it. I want to create a black (all zeros) 32 bit image with dimension 244 X 244 and save it as tif. I tried some modules like PIL but all I got was a single channel RGB image. Any suggestions? Any links?
Thank you for the help and apologies if the question is too basic!

Hopefully this will help:
#!/usr/local/bin/python3
import numpy as np
from PIL import Image
# Numpy array containing 244x244 solid black image
solidBlackImage=np.zeros([244,244,3],dtype=np.uint8)
img=Image.fromarray(solidBlackImage,mode="RGB")
img.save("result.tif")
The image I get as a result can be examined as follows with ImageMagick, and seen to be a 24-bit image:
identify -verbose result.tif | more
Output
Image: result.tif
Format: TIFF (Tagged Image File Format)
Mime type: image/tiff
Class: DirectClass
Geometry: 244x244+0+0
Units: PixelsPerInch
Colorspace: sRGB
Type: Bilevel
Base type: TrueColor
Endianess: LSB
Depth: 8/1-bit
Channel depth:
Red: 1-bit
Green: 1-bit
Blue: 1-bit
...
...
Or, you can verify with tiffinfo:
tiffinfo result.tif
Output
TIFF Directory at offset 0x8 (8)
Image Width: 244 Image Length: 244
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: RGB color
Samples/Pixel: 3
Rows/Strip: 244
Planar Configuration: single image plane
Another option might be pyvips as follows, where I can specify LZW compression as well:
#!/usr/local/bin/python3
import numpy as np
import pyvips
width,height,bands=244,244,3
# Numpy array containing 244x244 solid black image
solidBlackImage=np.zeros([height,width,bands],dtype=np.uint8)
# Convert numpy to vips image and save with LZW compression
vi = pyvips.Image.new_from_memory(solidBlackImage.ravel(), width, height, bands,'uchar')
vi.write_to_file('result.tif',compression='lzw')
That results in this:
tiffinfo result.tif
Output
TIFF Directory at offset 0x3ee (1006)
Image Width: 244 Image Length: 244
Resolution: 10, 10 pixels/cm
Bits/Sample: 8
Sample Format: unsigned integer
Compression Scheme: LZW
Photometric Interpretation: RGB color
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 3
Rows/Strip: 128
Planar Configuration: single image plane
Predictor: horizontal differencing 2 (0x2)

Related

Python - Multiple images to multilayered .xcf

I have three PIL images of the same size in RAM (no disk here). They represent different frequencies (details, shadow, mask).
Is it possible to overlay these images into a .xcf file to further process them by hand in gimp? If so, can the opacity of the layers be controlled before saving the image?
I'm ideally looking for a python solution.
Not certain what GIMP expects, but this might get you started as a multi-layer TIFF with varying opacities:
#!/usr/bin/env python3
import numpy as np
from PIL import Image
w, h = 400, 400
# Our layers to write to output file
layers = []
# Make layer 0 - 400x400 RGBA with red square, A=64
im = np.full((w,h,4), [0,0,0,64], np.uint8)
im[10:110, 10:110, :3] = [255,0,0]
layers.append(Image.fromarray(im))
# Make layer 1 - 400x400 RGBA with green square, A=128
im = np.full((w,h,4), [0,0,0,128], np.uint8)
im[20:120, 20:120, :3] = [0,255,0]
layers.append(Image.fromarray(im))
# Make layer 2 - 400x400 RGBA with blue square, A=192
im = np.full((w,h,4), [0,0,0,192], np.uint8)
im[30:130, 30:130, :3] = [0,0,255]
layers.append(Image.fromarray(im))
# Save as multi-layer TIFF with PIL
layers[0].save('result.tif', save_all=True, append_images=layers[1:], compression='tiff_lzw')
The Preview app on macOS displays it like this - hopefully you can see the red at least is more transparent, or less vibrant:
tiffinfo perceives it like this:
TIFF Directory at offset 0x9740 (260c)
Image Width: 400 Image Length: 400
Bits/Sample: 8
Compression Scheme: LZW
Photometric Interpretation: RGB color
Extra Samples: 1<unassoc-alpha>
Samples/Pixel: 4
Rows/Strip: 40
Planar Configuration: single image plane
TIFF Directory at offset 0x20096 (4e80)
Image Width: 400 Image Length: 400
Bits/Sample: 8
Compression Scheme: LZW
Photometric Interpretation: RGB color
Extra Samples: 1<unassoc-alpha>
Samples/Pixel: 4
Rows/Strip: 40
Planar Configuration: single image plane
TIFF Directory at offset 0x30506 (772a)
Image Width: 400 Image Length: 400
Bits/Sample: 8
Compression Scheme: LZW
Photometric Interpretation: RGB color
Extra Samples: 1<unassoc-alpha>
Samples/Pixel: 4
Rows/Strip: 40
Planar Configuration: single image plane

Resize grayscale image by summing pixel intensities for every 2x2 grid

I have a dataset of 36,000 tif images (grayscale, 16-bit) each of size 2048 x 2048 pixels. I want to resize them to 1024 x 1024 pixels by adding the intensities at each 2x2 grid to generate the intensity at each pixel in the resized image. I need to do this in Python. I have been doing this using ImageJ with Image>Transform>Bin, method = Sum. I cannot find a Python library which does this. Any help is appreciated. Thank you.
block_reduce from skimage_measure worked for me. Here's the code snippet:
import numpy as np
from skimage.measure import block_reduce
import skimage.io as tiffio
#read original 2k x 2k image
original_image = tiffio.imread(read_path+"/RawImage_00000.tif", plugin = 'tifffile')
#bin image by factor of 2 along both axes, summing pixel values in 2x2 blocks
sum2bin_image = block_reduce(original_image, block_size=(2, 2), func=np.sum)
#Numpy arrays are 64-bit float variables, so the following step restores the original unsigned 16-bit format
sum2bin_image = np.round(sum2bin_image).astype(np.uint16)
#save generated image
tiffio.imsave(save_path+'/'+'sum2bin_00000.tif', sum2bin_image, plugin='tifffile')

How to set a colormap for PySimpleGUI Image()

Is there a way to set a colormap for sg.Image() or sg.DrawImage()? In my case I have a grayscale (single-band) thermal image that I'd like to show with a heat colormap. Short example of current code:
import PySimpleGUI as sg
layout = [[sg.Image(thermal_image_path, size=(600, 600))]]
window = sg.Window('Show image', size=(600, 600),
resizable=True).Layout(layout).finalize()
You could map the grey-tones to a range of different Hues and set the Saturation and Lightness constant - see Wikipedia article on HSL
#!/usr/bin/env python3
import numpy as np
import cv2
def heatmap(im):
# Map range 0..255 of greys to Hues in range 60..180
# Keep Lightness=127, Saturation=255
# https://en.wikipedia.org/wiki/HSL_and_HSV#Hue_and_chroma
H = (im.astype(np.float32) * 120./255.).astype(np.uint8) + 60
L = np.full((h,w), 127, np.uint8)
S = np.full((h,w), 255, np.uint8)
HLS = cv2.merge((H,L,S))
return cv2.cvtColor(HLS,cv2.COLOR_HLS2RGB)
# Create greyscale gradient
w, h = 256, 100
grey = np.repeat(np.arange(w,dtype=np.uint8).reshape(1,-1), h, axis=0)
cv2.imwrite('grey.png',grey) # debug only
# Apply heatmap to greyscale image
hm = heatmap(grey)
# Just for display
from PIL import Image
Image.fromarray(hm).save('result.png')
That makes the following greyscale image:
And then gets transformed to this:
Or you could shell out to ImageMagick with subprocess.run(), or use wand (its Python binding) to do this:
Make a 100x100 greyscale ramp - this is just setup to create an image to work with:
magick -size 100x100 gradient: grey.png
Make a 5-colour heatmap by varying the hues around the HSL circle - this only needs doing once and you can keep and reuse the image heat.png:
magick xc:"hsl(240,255,128)" xc:"hsl(180,255,128)" xc:"hsl(120,255,128))" xc:"hsl(60,255,128)" xc:"hsl(0,255,128)" +append heat.png
Map the shades of the greyscale image to our CLUT (colour lookup table) - this is the actual answer:
magick grey.png heat.png -clut result.png

How to store a segmented image as thematic image as opposed to continuous image

I have a result of image segmentation image array as image(values as predicted class).when i save this image i get continuous layer type . But what i want is thematic layer type instead.
What function or parameters i should use to save this image as thematic(in .tif format)
eg. a 3x3 image looks like
[2,3,1
0,1,2
3,1,2]
instead of pixel values like
[255,192,64
0,64,128
128,192,64]
I want histogram to read from 0-3. Instead histogram is in the range(0-256) for first 3x3 example image.
I am using tifffile to write in .tif format
pred = numpy.argmax(ypreds, axis = 2)
tifffile.imwrite("pred1.tif", pred)
This code seems to save the values as you require:
import numpy as np
import tifffile
# Create representative image
y = np.random.randint(0,4,size=(3,3),dtype=np.uint8)
# Mine looks like this
# array([[1, 3, 3],
# [0, 2, 3],
# [1, 0, 0]], dtype=uint8)
# Save as TIFF
tifffile.imsave("pred1.tif",y)
Now check contents with ImageMagick and values and histogram appear to match data:
magick identify -verbose pred1.tif
Image: pred1.tif
Format: TIFF (Tagged Image File Format)
Mime type: image/tiff
Class: DirectClass
Geometry: 3x3+0+0
Resolution: 1x1
Print size: 3x3
Units: Undefined
Colorspace: Gray
Type: Grayscale
Endianess: LSB
Depth: 8-bit
Channel depth:
Gray: 8-bit
Channel statistics:
Pixels: 9
Gray:
min: 0 (0) <--- matches image
max: 3 (0.0117647) <--- matches image
mean: 1.44444 (0.00566449)
standard deviation: 1.33333 (0.00522876)
kurtosis: -1.91725
skewness: 0.105324
entropy: 0.945531
Colors: 4
Histogram: <--- matches image
3: ( 0, 0, 0) #000000 gray(0)
2: ( 1, 1, 1) #010101 gray(1)
1: ( 2, 2, 2) #020202 gray(2)
3: ( 3, 3, 3) #030303 gray(3)

Incorrect Image Dimensions using pillow/PIL

In Anaconda, I am using the PIL library to import a Nikon NEF image and display its size. The original image dimensions (according to the original image file) are 4608 pixels by 3072 pixels, but when I run my program the dimensions are said to be 160 by 120 pixels. How do I get the correct image size? Code displayed below:
from PIL import Image
import numpy as np
im = Image.open('DSC_0016.NEF')
width, height = im.size
print(width,height)

Resources