前言
许多地表参数反演算法中是以整景影像中的每个小窗口为单位进行计算。这时候就需要对整景影像划分为数个固定窗口大小影像。以下函数实现输入想要设定窗口的大小,影像列行数,返回一个分块影像的左上角和右下角坐标的查找表数组。有这样一个数组,无论是影像计算还是裁剪深度学习样本都可以适用。
之后会写一个有重叠的分块影像函数即滑动窗口。(已更新:2020-5-22-23:22)
规则窗口(无重叠)
2020-5-22-23:21 更新 无需生成lut版本
;自定义分隔影像函数,规则分隔
;wz 为窗口大小
;clos 为 影像列数
;rows 为影像行数
function block2, cols, rows, wz
compile_opt idl2
param_number = n_params()
if param_number eq 3 then begin
wz = wz
rows = rows
cols = cols
if wz gt rows or wz gt cols then begin
print, 'WindowSize gt imageSize'
return, 0
endif
if rows mod wz eq 0 then begin ; 计算行列方向的窗口数量
row_wz = rows / wz
endif else begin
row_wz = floor(rows/wz) + 1
endelse
if cols mod wz eq 0 then begin
col_wz = cols / wz
endif else begin
col_wz = floor(cols/wz) + 1
endelse
block_data = intarr(4, row_wz * col_wz)
num = 0
for i = 0,(row_wz - 1) do begin
for j = 0,(col_wz - 1) do begin
block_data[0, num] = wz * j > 0 ; 左上列坐标
block_data[1, num] = wz * i > 0
block_data[2, num] = wz* (j + 1) - 1 ; 右下列坐标
block_data[3, num] = wz* (i + 1) - 1
max_col = wz* (j + 1) - 1
max_row = wz* (i + 1) - 1
if max_col ge cols and max_row lt rows then begin
block_data[0, num] = cols - wz ; 左上列坐标
block_data[1, num] = wz * i > 0
block_data[2, num] = cols - 1 ; 右下列坐标
block_data[3, num] = wz * (i + 1) - 1
endif
if max_row ge rows and max_col lt cols then begin
block_data[0, num] = wz * j > 0 ; 左上列坐标
block_data[1, num] = rows - wz
block_data[2, num] = wz * (j + 1) - 1 ; 右下列坐标
block_data[3, num] = rows - 1
endif
if max_row ge rows and max_col ge cols then begin
block_data[0, num] = cols - wz ; 左上列坐标
block_data[1, num] = rows - wz
block_data[2, num] = cols - 1 ; 右下列坐标
block_data[3, num] = rows - 1
endif
num = num + 1
endfor
endfor
return, block_data
endif else begin
print, 'Please check Function params'
return, 0
endelse
end
用来裁剪测试一下,窗口大小为100,没有问题。
滑动窗口(有重叠)
2020-5-22-23:22更新
沿着行或列方向进行步长为1行像元的滑动,列或行之间进行步长为窗口大小的无重叠滑动。
;自定义影像滑动窗口
;row 影像行数
;col 影像列数
;wz 滑动窗口的大小
;dim 滑动方向的维度 1代表沿列方向(上下) 2代表沿行方向(左右)
function image_slide, cols, rows, wz, dim = dim
compile_opt idl2
param_number = n_params()
if param_number eq 3 and (dim eq 1 or dim eq 2) then begin
rows = rows
cols = cols
wz = wz
step = 1
if wz gt rows or wz gt cols then begin
print, 'WindowSize ge imageSize'
return, 0
endif
case 1 of
dim eq 1 : begin
row_num = floor((rows - wz) / step) + 1
col_num = floor(cols / wz) + 1 ; 行列方向的窗口个数
slide_data = intarr(4, row_num * col_num) ; 用于存放滑动窗口在影像的左上右下列行坐标
counts = row_num * col_num ; 记录窗口的数量
num = 0 ; 计数器 逐行写入数组
for i = 0, (col_num * wz - 1), wz do begin ; 沿列方向进行滑动, 列之间的窗口无重叠 -1是为了防止i溢出列数
for j = 0, (rows - wz), step do begin
slide_data[0, num] = i ; 左上列坐标
slide_data[1, num] = j
slide_data[2, num] = i + wz - 1 ; 右下列坐标
slide_data[3, num] = j + wz - 1
max_col = i + wz - 1
max_row = j + wz - 1
if max_col ge cols and max_row lt rows then begin ; 对不满足一个窗口大小的列边缘像素进行反向取窗口
slide_data[0, num] = cols - wz ; 左上列坐标
slide_data[1, num] = j
slide_data[2, num] = cols - 1 ; 右下列坐标
slide_data[3, num] = j + wz - 1
endif
if max_row ge rows and max_col lt cols then begin
slide_data[3, num] = rows - 1
slide_data[1, num] = rows - wz
endif
if max_col ge cols and max_row ge rows then begin ; 对不满足一个窗口大小的列边缘像素进行反向取窗口
slide_data[0, num] = cols - wz ; 左上列坐标
slide_data[1, num] = rows - wz
slide_data[2, num] = cols - 1 ; 右下列坐标
slide_data[3, num] = rows - 1
endif
num = num + 1
endfor
endfor
end
dim eq 2 : begin
col_num = floor((cols - wz) / step) + 1
row_num = floor(rows / wz) + 1 ; 行列方向的窗口个数
slide_data = intarr(4, row_num * col_num) ; 用于存放滑动窗口在影像的左上右下列行坐标
counts = row_num * col_num ; 记录窗口的数量
num = 0 ; 计数器 逐行写入数组
for i = 0, (row_num * wz - 1), wz do begin
for j = 0, (cols - wz), step do begin
slide_data[0, num] = j ; 左上列坐标
slide_data[1, num] = i
slide_data[2, num] = j + wz - 1 ; 右下列坐标
slide_data[3, num] = i + wz - 1
;print,j
max_col = j + wz - 1
max_row = i + wz - 1
if max_col ge cols and max_row lt rows then begin ; 对不满足一个窗口大小的列边缘像素进行反向取窗口
slide_data[0, num] = rows - wz ; 左上列坐标
slide_data[1, num] = i
slide_data[2, num] = rows - 1 ; 右下列坐标
slide_data[3, num] = i + wz - 1
endif
if max_row ge rows and max_col lt cols then begin
slide_data[3, num] = rows - 1
slide_data[1, num] = rows - wz
endif
if max_col ge cols and max_row gt rows then begin ; 对不满足一个窗口大小的列边缘像素进行反向取窗口
slide_data[0, num] = rows - wz ; 左上列坐标
slide_data[1, num] = cols - wz
slide_data[2, num] = rows - 1 ; 右下列坐标
slide_data[3, num] = cols - 1
endif
num = num + 1
endfor
endfor
end
endcase
return, slide_data
endif else begin
print, 'Please check Function params'
return, 0
endelse
end
测试一下,输出的坐标没问题。对于不够一个窗口大小的边缘列进行反向滑动。
ENVI> image_slide(110 , 41, 40, dim = 1)
0 0 39 39
0 1 39 40
40 0 79 39
40 1 79 40
70 0 109 39
70 1 109 40
窗口大小为200,裁剪测试一下。
动图感受下滑动的过程(在普通图像中原点坐标是在左下角,所以自下往上进行滑动)。
使用方法
(1)影像计算
这里测试了一个8192*8000的数组,使得每一块分块影像的值等于他的分块序号。
pro block_test
compile_opt idl2
e = envi()
data = make_array(8192,8000, type=2)
subs = block2(8192, 8000, 500) ; 调用block函数对影像分块
dim = size(subs, /dimensions)
count = dim[1] ; 获取分块图像的数量
for i = 0,count-1 do begin
sub = subs[*, i] ; 获取第一个分块影像的 左上角 右上角 行 列 坐标
data[sub[0]:sub[2], sub[1]:sub[3]] = i
endfor
tempfn = e.GetTemporaryFilename()
raster = e.CreateRaster(tempfn, data)
raster.save
view = e.GetView()
layer = view.CreateLayer(raster)
end
运行结果如下,影像分块值按行依次递增,说明分块没有错误。
(2)影像裁剪
pro crop_image
compile_opt idl2
img = read_image('E:\Manual instructions\image\apple.jpg')
;img_vis = image(img)
img = reform(img[1,*,*])
dim = size(img, /dimensions)
rows = dim[1]
cols = dim[0]
subs = image_slide(cols, rows, 251, dim=1)
counts = n_elements(subs) / 4
for i = 0, counts - 1 do begin
sub = subs[*, i]
img_out = img[sub[0]:sub[2], sub[1]:sub[3]]
write_jpeg, 'E:\Manual instructions\image\out3\' + 'image_crop' + string(i) + '.jpg', img_out
endfor
end
lut版本
lut文件在IDL目录下生成。(起初生成lut文件是为了方便调试代码,实际上根本不适用,假如影像够大或者窗口过小,生成的txt文件大小能到G的量级~)
function block, wz, cols, rows
compile_opt idl2
cd, getenv('idl_tmpdir')
wz = wz
rows = rows
cols = cols
if rows mod wz eq 0 then begin
row_wz = rows / wz
endif else begin
row_wz = round(rows/wz) + 1
endelse
if cols mod wz eq 0 then begin
col_wz = cols / wz
endif else begin
col_wz = round(cols/wz) + 1
endelse
lut = 'lut.txt'
openw, lun, lut, /get_lun
for i = 0,row_wz-1 do begin
for j = 0,col_wz-1 do begin
max_col = wz*(j+1) - 1
max_row = wz*(i+1) - 1
if max_col gt cols then max_col = cols - 1
if max_row gt rows then max_row = rows - 1
printf, lun, wz*j>0, wz*i>0, max_col, max_row
endfor
endfor
free_lun,lun
nl = file_lines(lut)
lutdata = intarr(4, nl)
openr, lun, lut, /get_lun
readf, lun, lutdata
free_lun, lun
return, lutdata
end