1

I am having some problems opening some .tif files that I have. I've tried using pillow, gdal, cv2, and skimage. I would prefer to use pillow since I do use it in other scripts. I cannot use rasterio becuase when I set up a batch file rasterio throws an gdal._version error that I have yet to solve.

This opening image error is strange to me since I had another code that split raster images (had a missing data issue so I switched to this one) that uses gdal and has no problem opening it. I read a few posts about how pillow does not support certain data types, but I have not any work arounds yet. I've attached the properties of my image and will continue to trouble shoot.

Is there anything that pops out that I need to fix? Again I would prefer to use the first code block I posted (using pillow).

Pillow

import os
from PIL import Image
from itertools import product

def tile(filename, dir_in, dir_out, d):
    Image.MAX_IMAGE_PIXELS = None
    name, ext = os.path.splitext(filename)
    img = Image.open(os.path.join(dir_in, filename))
    w, h = img.size

    grid = list(product(range(0, h - h % d, d), range(0, w - w % d, d)))
    for i, j in grid:
        box = (j, i, j + d, i + d)
        out = os.path.join(dir_out, f'{name}_{i}_{j}{ext}')
        img.crop(box).save(out)

tile('name.tif',
     r'D:\image',
     r'D:\images_split',
     1000)
Traceback (most recent call last):
  File "C:/Users/delete_NA/split.py", line 22, in <module>
    1000)
  File "C:/Users/delete_NA/split.py", line 9, in tile
    img = Image.open(os.path.join(dir_in, filename))
  File "C:\Users\anaconda3\envs\split\lib\site-packages\PIL\Image.py", line 2959, in open
    "cannot identify image file %r" % (filename if filename else fp)
PIL.UnidentifiedImageError: cannot identify image file 'D:\\image\\image_to_split.tif'

GDAL

import os
import gdal
from itertools import product

def tile(filename, dir_in, dir_out, d):
    Image.MAX_IMAGE_PIXELS = None
    name, ext = os.path.splitext(filename)
    img = gdal.Open(os.path.join(dir_in, filename))
    w, h = img.size

    grid = list(product(range(0, h - h % d, d), range(0, w - w % d, d)))
    for i, j in grid:
        box = (j, i, j + d, i + d)
        out = os.path.join(dir_out, f'{name}_{i}_{j}{ext}')
        img.crop(box).save(out)

tile('name.tif',
     r'D:\image',
     r'D:\images_split',
     1000)
Traceback (most recent call last):
  File "C:/Users/delete_NA/split.py", line 22, in <module>
    1000)
  File "C:/Users/delete_NA/split.py", line 10, in tile
    w, h = img.size
  File "C:\Users\anaconda3\envs\split\lib\site-packages\osgeo\gdal.py", line 2184, in <lambda>
    __getattr__ = lambda self, name: _swig_getattr(self, Dataset, name)
  File "C:\Users\anaconda3\envs\split\lib\site-packages\osgeo\gdal.py", line 80, in _swig_getattr
    raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name))
AttributeError: 'Dataset' object has no attribute 'size'

Other split code with gdal - this one works

import os
from osgeo import gdal
# import variables

# Setting the directory
os.chdir(r"D:\ortho")

# Loading in the image
rimg = gdal.Open("image.tif")

# Upper left corner of the minX and maxY
gt = rimg.GetGeoTransform()

xmin = gt[0]
ymax = gt[3]

res = gt[1]
xlen = res * rimg.RasterXSize # units is important UTM or WGS
ylen = res * rimg.RasterYSize

# how many tiles you want to have in each row and column
xdiv = 150
ydiv = 150

# Determining the size of each new image 
xsize = xlen/xdiv
ysize = ylen/ydiv

print(xsize)
print(ysize)

xsteps = [xmin + xsize * i for i in range(xdiv+1)] # plut because we start in the left top corner where X is at its lowest
ysteps = [ymax - ysize * i for i in range(ydiv+1)] # minus because we start in the left top corner where Y is at its highest

for i in range(xdiv):
    for j in range(ydiv):
        xmin = xsteps[i]
        xmax = xsteps[i+1]
        ymax = ysteps[j]
        ymin = ysteps[j+1]

        # Splices the image up into the set divs and saves them.
        gdal.Warp("D:/split_images/item" + str(i)+str(j) + ".tif",rimg,
                  outputBounds = (xmin,ymin,xmax,ymax),dstNodata = -9999)

Tif Properties Images

Edits I ran another image through that is a fraction of the size, with the same properties. Same CRS, Units, Data type, ect. I don't think it would be a size issue because I pass Image.MAX_IMAGE_PIXELS = None. One thing to note though, each image that is split, the CRS is not being assigned, which does cause an issue for me later on.

  • You do see, that there are missing `'` in `tile('name.tif', r'D:\image, r'D:\images_split, 1000)` (second and third parameter)!? – HansHirse Feb 24 '21 at 07:52
  • @HansHirse Yes, I do see that now. Must have accidently deleted it somehow. Let me update that. But the code I have in my IDLE does have the `'`. So that shouldn't be the issue. –  Feb 24 '21 at 16:49

1 Answers1

0

After some digging I found that Image.open() from pillow does not support BigTiffs. It also only supports specific byte sizes. tifffile can be used to open BigTiffs. I ended up changing a couple things in my code. First, using tifffile instead of pillow. Second, changing img.size to img.shape. Third, tifffile opens the image into a numpy array, so use the clip method instead. The code does work, though it is not being clipped. This answers my initial question though.

import os
import tifffile
from itertools import product

def tile(filename, dir_in, dir_out, d):
    name, ext = os.path.splitext(filename)
    img = tifffile.imread(os.path.join(dir_in, filename))
    w = img.shape[0]
    h = img.shape[1]

    grid = list(product(range(0, h - h % d, d), range(0, w - w % d, d)))
    for i, j in grid:
        box = (j, i, j + d, i + d)
        out = os.path.join(dir_out, f'{name}_{i}_{j}{ext}')
        img = img.clip(box)
        img = img.astype('uint8')
        tifffile.imsave(out, img)

tile('name.tif',
     r'D:\image',
     r'D:\images_split',
     1000)