Clipping a .tiff Raster into grids with Python - python

I have a large .tiff raster (at least 200x150), but I need a bunch of 32x32 .tiff files. Is there an easy way to cut up that .tiff in Python? I think the workflow would look something like:
Create 32x32 box in bottom right corner of raster
Clip raster with that box, saving new clipped .tiff raster
Shift box left by 32 pixels (if less than 32 pixels left, shift up 32 pixels and restart on right side)
Repeat clip/shift until can't shift up or sideways
The input raster won't be an even multiple of 32, but I don't care if I lose some of the original raster off of the sides. As long as the original data is preserved for each 32x32 raster, I'm happy.

I was able to solve this using the arcpy module.
The arcpy.management.SplitRaster() documentation is available at https://pro.arcgis.com/en/pro-app/2.8/tool-reference/data-management/split-raster.htm. After this, I used os.listdir() to get a list of the output files. OpenCV has a ndarrayt.shape() function that gives the dimensions of the image, so I looped that over each file and deleted any that didn't match the size that I wanted.

Related

Tile satellite images with GDAL_retile in python?

I'm trying to tile a folder of 3 band images into 256 x 256 pixel squares, (keeping the original CRS), feed this into a Unet model and then re-organize my tiled data back into one complete image to view the results of my model.
I've used this answer but the last row of tiles are composed of the remaining pixels (edge cases).
Is there a way of either allowing for padding to be added or an automatically determined overlap to prevent this and ensure all tiles are 256x256?
makeLastPartFull = True is supposed to do this with cv2, so I am looking for something similar with GDAL?
I'm using Pycharm version 2021.1.

How to paste an image to another image based on multiple coordinate comparison in python?

I need to merge two images (one is jpg and other one is png) based on its coordinate values. I have obtained coordinate value of both images and resized based on the size. I found a relevant answer here ,but it deals with only one pair of coordinates.
Paste an image to another image at two given co-ordinates with altered opacity using PIL or OpenCV in Python
I checked the other link How can I paste an image to another image by comparing its coordinate values using PIL or opencv in Python?
but still image is getting distorted.
Pillow based merge will be better because my second image is png and pillow deals with the transparency of png files better. Can anyone suggest a better answer which deals with multiple coordinate value comparison in each images and merge?
the image will be like this
The points will be like this,
"keypoints":[
{
"score":0.91145658
"part":"leftshoulder"
"position":{"x":233.165434,"y":326.7643555}
},
{
"score":0.91145658
"part":"right shoulder"
"position":{"x":233.165434,"y":326.7643555}
}
]
First image left shoulder point should merge with second image left shoulder point. First image right shoulder point should merge with second image right shoulder point. It will be go like this according to the points.
That is the expected outcome

How can you crop an SVG Image in Python?

With a program, I am producing an SVG image with dimensions of 400px x 400px. However, I would like to crop the bottom of this SVG image off, based off of a variable that dictates how much of the bottom of the image should be cropped in pixels.
This SVG image is being generated with pyCairo with surface = cairo.SVGSurface("output.svg", WIDTH, HEIGHT) and ctx = cairo.Context(surface).
Although the HEIGHT variable is a constant and isn't changed, after I perform some operations on the surface object, I would like to be able to resize it once more. I can use the Pillow Image object to crop PNGs, but it does not support SVGs.
I have also tried to open the svg file with open("output.svg"). However, if I try to read it, I am unable to and it shows up as blank, thus making it unmodifiable.
Is there any way in Python to either crop an SVG image or modify its size after it has been modified with pycairo?
The answer above is incomplete and at least for me doesn't solve the problem.
A SVG can simply be cropped (trimmed, clipped, cut) using vpype with the crop or trim and translate commands.
import vpype_cli as vp
#vp.excute("read test.svg translate 300 400 trim 30 20 write output.svg")
vpype_cli.execute("read test.svg crop 0cm 0cm 10cm 20cm write output.svg")
Playing around with the parameters should lead to the desired crop.
Took some time to find this, as most answers say it cant be done, which is ridiculous.
You cannot crop SVG like you crop PNG because in the latter you can just drop pixels, while for the former you have defined paths that can't be easily recomputed.
If you're sure there's nothing in the part you are about to "crop", you can use set_context_size to make the svg context/canvas smaller while preserving ratio and size inside.

Python 3: How to blur a GeoTIFF image with color table?

I've got a GeoTIFF image that I need to make blurry by applying a smoothing filter. The image itself contains metadata that needs to be preserved. It has a bit-depth of 8 and uses a color table with 256 32-bit RGBA values to look up a color for each pixel, but in order for the resulting image to look smooth it will probably have to use a bit-depth of 24 or 32 and no color table, alternatively use jpeg compression. What may complicate this further is that the image is 23,899x18,330 pixels large, which is almost five times as large as the largest file PIL wants to open by default.
How can create the blurry version of this image in Python 3?
I have also tried using PIL to just open and save it again:
from PIL import Image
Image.MAX_IMAGE_PIXELS = 1000000000
im = Image.open(file_in)
im.save(file_out)
This code doesn't crash, and I get a new .tif file that is approximatelly as large as the original file, but when I try to open it in Windows Photo Viewer to look at it the application says it is corrupt, and it cannot be re-opened by PIL.
I have also tried using GDAL. When I try this code, I get an output image that is 835 MB large, which corresponds to an uncompressed image with a bit-depth of 16 (which is also what the file metadata says when I right-click on it and choose "Properties" – I'm using Windows 10). However, the resulting image is monochrome and very dark, and the colors look like they have been jumbled up, which makes me believe that the code I'm trying interprets the pixel values as intensity values and not as table keys.
So in order to make this method work, I need to figure out how to apply the color table (which is some sort of container for tuples, of type osgeo.gdal.ColorTable) to the raster band (whatever a raster band is), which is a numpy array with the shape (18330, 23899), to get a new numpy array with the shape (18330, 23899, 4) or (4, 18330, 23899) (don't know which is the correct shape), insert this back into the loaded image and remove the color table (or create a new one with the same metadata), and finally save the modified image with compression enabled (so I get closer to the original file size – 11.9 MB – rather than 835 MB which is the size of the file I get now). How can I do that?
pyvips can process huge images quickly using just a small amount of memory, and supports palette TIFF images.
Unfortunately it won't support the extra geotiff tags, since libtiff won't work on unknown tag types. You'd need to copy that metadata over in some other way.
Anyway, if you can do that, pyvips should work on your image. I tried this example:
import sys
import pyvips
# the 'sequential' hint tells libvips that we want to stream the image
# and don't need full random access to pixels ... in this mode,
# libvips can read, process and write in parallel, and without needing
# to hold the whole image in memory
image = pyvips.Image.new_from_file(sys.argv[1], access='sequential')
image = image.gaussblur(2)
image.write_to_file(sys.argv[2])
On an image of the type and size you have, generating a JPEG-compressed TIFF:
$ tiffinfo x2.tif
TIFF Directory at offset 0x1a1c65c6 (438068678)
Image Width: 23899 Image Length: 18330
Resolution: 45118.5, 45118.5 pixels/cm
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: palette color (RGB from colormap)
...
$ /usr/bin/time -f %M:%e python3 ~/try/blur.py x2.tif x3.tif[compression=jpeg]
137500:2.42
So 140MB of memory, 2.5 seconds. The output image looks correct and is 24mb, so not too far off yours.
A raster band is just the name given to each "layer" of the image, in your case they will be the red, green, blue, and alpha values. These are what you want to blur. You can open the image and save each band to a separate array by using data.GetRasterBand(i) to get the ith band (with 1-indexing, not 0-indexing) of the image you opened using GDAL.
You can then try and use SciPy's scipy.ndimage.gaussian_filter to achieve the blurring. You'll want to send it an array that is shape (x,y), so you'll have to do this for each raster band individually. You should be able to save your data as another GeoTIFF using GDAL.
If the colour table you are working with means that your data is stored in each raster band in some odd format that isn't just floats between 0 and 1 for each of R, G, B, and A, then consider using scipy.ndimage.generic_filter, although without knowing how your data is stored it's hard to give specifics on how you'd do this.

Rotating image increases its size?

I am trying to rotate some images whose width is more than height about the left-top corner, by 90 degrees. I have written this :
from PIL import Image
import sys, csv, os, traceback, glob
import shutil, math
src_im = Image.open("Test.png")
print src_im.size[0] , ',' , src_im.size[1]
src_im = src_im.transpose(Image.ROTATE_90)
src_im = src_im.transpose(Image.FLIP_LEFT_RIGHT)
src_im = src_im.transpose(Image.FLIP_TOP_BOTTOM)
src_im.save("TestResult.png")
print src_im.size[0] , ',' , src_im.size[1]
Output generated is as I expect, but there is a huge change in size. Any ideas where I might be going wrong ?
Its the same pixel information being stored, just rotated, why should there be a change in the image size ?
eg.
(936 x 312) 155KB
(312 x 936) 342KB
Edit:
Ok, so I tried rotating the images with the inbuilt image viewer of windows, and there is an increase in that case as well. So its not really specific to Python per se. More about compression. Am still not clear why would it be less compressible on rotation ? And this is happening for all images I am trying, not this particular one. Updating the tags accordingly.
PNG compress the image by "filtering" each line, trying to predict the values for each pixel as a function of the "past" neighbours (previous row and/or column), and then compressing the prediction error by using ZLIB (Deflate).
The issue here seems to be this: the vertical image has almost vertical stripes; when scanned along the rows, it has a fairly predictable medium-range pattern (about 8 similar colors followed by a short burst of lighter colour). This suggest that, while the short-range prediction will not be very successful, the prediction error will get a highly repetitive pattern, that should be relatively easy to compress. This does not happen when the image is rotated.
I verified that the different horizontal/vertical sizes were not the problem: I made a bigger square (900x900) by repeating the original image 9 times. The PNG image with quasi vertical stripes has roughly half the size than the other one.
Another experiment that confirms the above: save both images as grayscale BMP (this is an uncompressed format, it stores one byte per pixel, along the rows). You get two images of 293.110 bytes. Compress both of them with a standard ZIP compressor (same family as ZLIB's deflate). The vertical image, again, gets about half the size than the other one.

Categories

Resources