当前位置:首页>python>技术分享//遥感影像自适应降位拉伸(附python代码及测试数据)

技术分享//遥感影像自适应降位拉伸(附python代码及测试数据)

  • 2026-09-28 18:26:53
技术分享//遥感影像自适应降位拉伸(附python代码及测试数据)

1.统计影像直方图信息
2.获取影像拉伸点像素值
3.图像拉伸
4.tif格式影像读写
5.测试

卫星遥感影像通常为16位,如何将影像降位拉伸为8位?简单粗暴的方法是直接进行降位处理:

A_min,A_max = A_16bit.min(),A_16bit.max()A_8bit = (A_16bit - A_min) / (A_max - A_min)

这种办法对于所有的影像都适用。缺点在于,经过处理后的影像要么太亮,要么太暗,信息严重损失。这是由于影像上可能存在少量亮度异常的噪点,进行拉伸处理时这些异常点也参与计算。

直接降位处理效果为:

为了提升降位处理后影像质量,让影像亮度更合理,需要引入直方图拉伸算法。直方图拉伸算法首先统计影像直方图。基于累积直方图,截掉直方图两侧占比很少的像素,保留中间部分,对这部分影像进行拉伸处理。

以下是利用python进行遥感影像自适应降位处理流程。

需要引入的库文件:

import osimport sysimport globfrom osgeo import gdalimport numpy as npimport cv2

1.统计影像直方图

输入:影像数据,numpy矩阵

返回:影像直方图

代码:

def CalHistogram(img):    img_dtype = img.dtype    img_hist = img.reshape(-1)    img_min,img_max = img_hist.min(),img_hist.max()    n_bins = 2 ** 16    if (img_dtype == np.uint8 ):        n_bins = 256    if  (img_dtype == np.uint16 ):        n_bins = 2**16    elif (img_dtype == np.uint32):        n_bins = 2**32     if (img_dtype == np.uint8 ) or (img_dtype == np.uint16 ) or (img_dtype == np.uint32):        hist = np.bincount(img_hist,minlength = n_bins)        hist[0] = 0          hist[-1] = 0            s_values = np.arange(n_bins)    else:        hist,s_values= np.histogram(img_hist,bins = n_bins,range = (img_min,img_max))         hist[0] = 0        hist[-1] = 0       img_hist = None      return hist,s_values

2.获取影像拉伸点像素值

    输入:影像数据,左侧(图像较暗部分)图像截取的比例,0.001表示0.1%,右侧(图像较亮部分)图像截取值比例

    返回:图像拉伸点对应的像素值

    代码:

def GetPercentStretchValue(img,left_clip = 0.001,right_clip = 0.001):    right_clip = 1.0 - right_clip    hist,s_values = CalHistogram(img)    s_quantiles = np.cumsum(hist).astype(np.float64)    s_quantiles /= (s_quantiles[-1] + 1.0E-5)        left_clip_index = np.argmin(np.abs(s_quantiles-left_clip))    right_clip_index = np.argmin(np.abs(s_quantiles-right_clip))      img_min_clip,img_max_clip = s_values[[left_clip_index,right_clip_index]]    return img_min_clip,img_max_clip 

3.图像拉伸

def percent_stretch_image(input_image_data, left_clip = 0.001,right_clip = 0.001,left_mask = None,                        right_mask = None ):    if input_image_data is None:        return None      n_dim = input_image_data.ndim    img_bands = 1 if n_dim == 2 else input_image_data.shape[n_dim-1]    xsize = input_image_data.shape[1]    ysize = input_image_data.shape[0]    indtype = input_image_data.dtype    if indtype == np.uint8:        to_8bit = True    if img_bands > 1:        out_8bit_data = np.zeros((ysize,xsize,img_bands),dtype = np.uint8)    else:        out_8bit_data = np.zeros((ysize,xsize),dtype = np.uint8)      for i_band in range(img_bands):        if img_bands == 1:            input_image_data_raw = input_image_data#[:,:,i_band]        else:            input_image_data_raw = input_image_data[:,:,i_band]        img_clip_min,img_clip_max = GetPercentStretchValue(input_image_data_raw,left_clip=left_clip,right_clip = right_clip)            input_image_data_raw = np.clip(input_image_data_raw,img_clip_min,img_clip_max)        input_image_data_raw = (input_image_data_raw -  img_clip_min)/(img_clip_max - img_clip_min) * 255        input_image_data_raw = input_image_data_raw.astype(np.uint8)                       if img_bands > 1:            out_8bit_data[:,:,i_band] = input_image_data_raw        else:            out_8bit_data = input_image_data_raw    return out_8bit_data

4.tif格式影像读写

def read_tif(file_path):    tif_f = file_path    ds = gdal.Open(tif_f)    if ds == None:        print("Error || Can't open {0} as tif file.".format(tif_f))        return    cols = ds.RasterXSize    rows = ds.RasterYSize    bands = ds.RasterCount    pro = ds.GetProjection()    data_set = np.zeros((rows, cols, bands))    for i in range(bands):        band = ds.GetRasterBand(i + 1)        data_type = gdal.GetDataTypeName(band.DataType).lower()        data_set[:, :, i] = band.ReadAsArray()    data_set = np.array(data_set, dtype = data_type)    del ds    return data_set, prodef write_tif(file_path, data, transform = None, projection = None):    out_file = file_path    w_data = data    if len(w_data.shape) == 2:        w_data = w_data.reshape(w_data.shape[0],w_data.shape[1],1)    if transform is not None:        tra = transform    if projection is not None:        pro = projection    if w_data.dtype == np.uint8:#"int8":        datatype = gdal.GDT_Byte    elif w_data.dtype == np.uint16:#"int16":        datatype = gdal.GDT_UInt16    else:        datatype = gdal.GDT_Float32

5.测试

    in_file = 'a.tif'    img,_ = read_tif(in_file)    n_dim = img.ndim    img_bands = 1 if n_dim == 2 else img.shape[n_dim-1]       print(img.min(),img.mean(),img.max())    img_raw_s = (img - img.min()) / (img.max() - img.min())*255    print('img raw s:',img_raw_s.min(),img_raw_s.mean(),img_raw_s.max())    img = percent_stretch_image(img)    out_file = os.path.join(out_path,os.path.basename(in_file))    write_tif(out_file,img.astype(np.uint8))    write_tif(out_file + '_raw.tif',img_raw_s.astype(np.uint8))    if img_bands > 3:        write_tif(out_file + '_RGB.tif',img[:,:,[2,1,0]].astype(np.uint8))        write_tif(out_file + '_RGB_raw.tif',img_raw_s[:,:,[2,1,0]].astype(np.uint8))

处理后效果为:

细节对比效果:

测试影像下载地址:

https://pan.baidu.com/s/17wLYyQzK3DAW2rP5gSRxZA?pwd=aiwe

最新文章

随机文章