遥感卫星影像的切片处理

我们在GIS数据处理或者深度学习数据制备的时候经常用到一些分辨率比较高的遥感数据,这些数据通常比较大,使用主流的opencv库处理时会有最大处理限制,所以,笔者的思路如下:

  • 首先对影像进行切片处理,并且按序列编号
  • 按照序列读取这些切片
  • 分别对这些切片进行处理
  • 最后可以按照切片的名称将它们拼合起来。

本篇内容:

切片操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from PIL import Image
import os

# 输入文件路径
tiff_file = 'img.tif'

Image.MAX_IMAGE_PIXELS = None # or some other big number
# 打开TIFF文件
im = Image.open(tiff_file)

# 获取图像的宽高
img_width, img_height = im.size

crop_width = 640
crop_height = 640

save_path = 'cut/'

if not os.path.exists(save_path):
os.makedirs(save_path)

print(f'Path {save_path} {"exists" if os.path.exists(save_path) else "created"}')

# 计算可以分割的行列数
rows = img_height // crop_height
cols = img_width // crop_width

# 循环裁剪图像
for r in range(rows + 1):
for c in range(cols + 1):
# 计算当前切片的位置和大小
x1 = c * crop_width
y1 = r * crop_height
x2 = x1 + crop_width if x1 + crop_width < img_width else img_width
y2 = y1 + crop_height if y1 + crop_height < img_height else img_height

# 裁剪图像
box = (x1, y1, x2, y2)
tile = im.crop(box)
#处理操作

# 生成切片文件名并保存
tile_name = '{}_{}.tif'.format(r, c)
tile.save(save_path + tile_name)

print('切片完成!')

拼接操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from PIL import Image
import os
import re

img_width=
img_height=
folder='tiles/'
# 保存拼接图片的路径
save_path = folder+'reconstituted.tif'

# 获取所有切片的文件名
tile_names = os.listdir(folder)
tile_names.sort()

# 打开第一个切片获取图像模式和大小
sample_tile = Image.open(folder+tile_names[0])
mode = sample_tile.mode
tile_width, tile_height = sample_tile.size

# 使用正则提取行列号
pattern = re.compile(r'(\d+)_(\d+)\.tif')

# rows = 0
# cols = 0
for name in tile_names:
match = pattern.match(name)
if match:
r = int(match.group(1))
c = int(match.group(2))
# rows = max(rows, r)
# cols = max(cols, c)


# 创建新图
result = Image.new(mode, (img_width, img_height))

# 按序拼接
for index, tile_name in enumerate(tile_names):

match = pattern.match(tile_name)
if match:
r = int(match.group(1))
c = int(match.group(2))
# 打开切片图像
tile = Image.open(folder+tile_name)

# 拼接
result.paste(tile, (c * tile_width, r * tile_height))

# 保存结果图片
result.save(save_path)
print('图像拼接完成!')

或者在使用PIL库读取时,可以直接设置无读取上限

Image.MAX_IMAGE_PIXELS = None # or some other big number

但是,不管是使用的哪个库,想要简单地将所有的切片拼合起来,转化为np数组后进行操作(如分割等)都是不可行的,可能会占用大量内存,这里笔者也没有找到更好的解决方法。