去除遥感影像黑边

去除遥感影像黑边
ytkz为什么会出现黑边
某些遥感L1级别的影像本身自带黑边,所以在经过预处理后,L2级别的遥感影像存在黑边。
L1级别的影像的边缘如下,黑边的像素值是0。
L1级别的透明区域的像素值为Nodata,如下。
我们可以在arcgis上设置L1级别的像素为透明,但是这个设置是不改变影像,只是视觉效果上发生改变,操作如下:右击影像,选择属性,然后在Symbology勾选上Display Background Value按钮
可视化结果如下:
然而,经过6S大气校正、RPC几何校正后的影像边缘如下,黑边的像素值是负值。
怎么去除
逻辑简单,将L2级别的影像中的负值设置为0即可。
代码简单,如下:
from osgeo import gdal
import numpy as np
import os
def remove_black_edges_border_only(input_path, output_path, block_size=2000, edge_width=100):
"""
以分块方式读取遥感影像,仅对影像边缘区域(图像边界内 edge_width 像素范围)进行检测,
将小于0(负值)的像素值置为0;影像内部区域不作检测修改。
参数:
input_path : 输入影像路径(例如 GeoTIFF 文件)
output_path : 输出影像路径
block_size : 分块尺寸(默认2000,可以根据内存情况调整)
edge_width : 边缘区域宽度(单位:像素),仅对图像四周 edge_width 范围内的像素进行处理
"""
# 打开输入影像(只读模式)
ds = gdal.Open(input_path, gdal.GA_ReadOnly)
if ds is None:
raise FileNotFoundError(f"无法打开输入文件:{input_path}")
cols = ds.RasterXSize
rows = ds.RasterYSize
bands = ds.RasterCount
geotransform = ds.GetGeoTransform()
projection = ds.GetProjection()
# 创建输出影像,与输入影像在尺寸、波段和数据类型上保持一致
driver = gdal.GetDriverByName('GTiff')
out_ds = driver.Create(output_path, cols, rows, bands, ds.GetRasterBand(1).DataType)
out_ds.SetGeoTransform(geotransform)
out_ds.SetProjection(projection)
# 针对每个波段分块处理
for i in range(1, bands + 1):
in_band = ds.GetRasterBand(i)
out_band = out_ds.GetRasterBand(i)
# 按块遍历整幅影像
for y in range(0, rows, block_size):
block_height = block_size if y + block_size < rows else rows - y
for x in range(0, cols, block_size):
block_width = block_size if x + block_size < cols else cols - x
# 读取当前块数据
data = in_band.ReadAsArray(x, y, block_width, block_height)
# 保证数据为浮点型,便于比较(也可根据实际数据类型调整)
data = data.astype(np.float32)
# 生成当前块的全局像素坐标网格
xs = np.arange(x, x + block_width)
ys = np.arange(y, y + block_height)
# X: 每行的列坐标; Y: 每列的行坐标,形状均为 (block_height, block_width)
X, Y = np.meshgrid(xs, ys)
# 定义边缘区域:全局坐标位于图像左边 edge_width 内、右边 edge_width 内、
# 上边 edge_width 内或下边 edge_width 内的像素
border_mask = ((X < edge_width) | (X >= cols - edge_width) |
(Y < edge_width) | (Y >= rows - edge_width))
# 仅对边缘区域中小于0的像素值设置为0
data[border_mask & (data < 0)] = 0
# 将当前块处理后的数据写回输出影像
out_band.WriteArray(data, xoff=x, yoff=y)
# 刷新缓存
out_band.FlushCache()
# 关闭数据集
ds = None
out_ds = None
print(f"分块处理完成,输出文件保存在:{output_path}")
# 示例调用
if __name__ == "__main__":
input_file = r"D:\orth.tif" # 替换为实际路径
output_file = os.path.splitext(input_file)[0] + '_remove_blacks_border.tif'
remove_black_edges_border_only(input_file, output_file, block_size=2000, edge_width=100)
去除前:
去除后:
去除黑边的结果对比
去除黑边,即是减少异常值对影像的影响,一般来说,多波段遥感影像的像素值是存在负值的。
现在仅在视觉效果上,对比有无黑边的对比。简单说一下自己的理解。
众所周知,我们常见的色彩图像都是8比特,8比特是指数值的范围在2的8次方之间。
2的8次方等于256,但是编程界通常从0开始计数,所以彩色图像的数值范围在0-255之间。
一切非8比特的遥感影像,在arcgis打开时,arcgis会自动的对影像进行拉伸,
把非8比特的影像,按照不同的拉伸规则,映射到0-255之间。
回到本文,如果有负值的存在,则影像在arcgis的可视化,会偏白,看起来灰蒙蒙的。结果如下:
去除黑边后的影像,在arcgis可视化结果的色彩比较明亮,效果如下,
改进
上面的代码是对整体影像进行检测异常值,然后对异常值进行替换。速度会非常慢。
改进的点是,提前判断影像的四条边缘所在的图像坐标范围,只针对这四个范围进行数值检测、数值替换即可。