遥感图像去除NoData及增强处理

去除NoData参考链接:https://stackoverflow.com/questions/20753288/filling-gaps-on-an-image-using-numpy-and-scipy
图像增强参考链接:https://stackoverflow.com/questions/20753288/filling-gaps-on-an-image-using-numpy-and-scipy
代码还是要改一些的,我把做好的放出来大家参考下

1.去除NoData
第二种方法比较慢

import cv2
import gdal
import scipy.interpolate
import numpy as np

def read_img(filename):
    dataset=gdal.Open(filename)

    im_width = dataset.RasterXSize
    im_height = dataset.RasterYSize

    im_geotrans = dataset.GetGeoTransform()
    im_proj = dataset.GetProjection()
    im_data = dataset.ReadAsArray(0,0,im_width,im_height)

    del dataset 
    return im_proj,im_geotrans,im_width, im_height,im_data


def write_img(filename, im_proj, im_geotrans, im_data):
    if 'int8' in im_data.dtype.name:
        datatype = gdal.GDT_Byte
    elif 'int16' in im_data.dtype.name:
        datatype = gdal.GDT_UInt16
    else:
        datatype = gdal.GDT_Float32

    if len(im_data.shape) == 3:
        im_bands, im_height, im_width = im_data.shape
    else:
        im_bands, (im_height, im_width) = 1,im_data.shape 

    driver = gdal.GetDriverByName("GTiff")
    dataset = driver.Create(filename, im_width, im_height, im_bands, datatype)

    dataset.SetGeoTransform(im_geotrans)
    dataset.SetProjection(im_proj)

    if im_bands == 1:
        dataset.GetRasterBand(1).WriteArray(im_data)
    else:
        for i in range(im_bands):
            dataset.GetRasterBand(i+1).WriteArray(im_data[i])

    del dataset

def NoData_kill(in_path, out_path):
    # data = cv2.imread("cq_test.tif")
    im_proj,im_geotrans,im_width, im_height,im_data = read_img(in_path)
    mask = np.isnan(im_data)
    c, w, h = mask.shape
    mask_list = []
    for i in range(c):
        if mask[i].__contains__(True):
            mask_list.append(mask[i])

    for m in mask_list:
        m = m + 0
        m = np.uint8(m)
        inpainted_img = cv2.inpaint(im_data, m, inpaintRadius=3, flags=cv2.INPAINT_TELEA)
        im_data = inpainted_img
    # cv2.imwrite('./fixed2.tif', data)
    write_img(out_path, im_proj, im_geotrans, im_data)

#too slow
def NoData_kill2(in_path, out_path):
    im_proj,im_geotrans,im_width, im_height, data = read_img(in_path)
    data = data.transpose(2,1,0)

    # a boolean array of (width, height) which False where there are missing values and True where there are valid (non-missing) values
    mask = ~( (data[:,:,0] == 255) & (data[:,:,1] == 255) & (data[:,:,2] == 255) )

    # array of (number of points, 2) containing the x,y coordinates of the valid values only
    xx, yy = np.meshgrid(np.arange(data.shape[1]), np.arange(data.shape[0]))
    xym = np.vstack( (np.ravel(xx[mask]), np.ravel(yy[mask])) ).T

    # the valid values in the first, second, third color channel,  as 1D arrays (in the same order as their coordinates in xym)
    data0 = np.ravel( data[:,:,0][mask] )
    data1 = np.ravel( data[:,:,1][mask] )
    data2 = np.ravel( data[:,:,2][mask] )

    # three separate interpolators for the separate color channels
    interp0 = scipy.interpolate.NearestNDInterpolator( xym, data0 )
    interp1 = scipy.interpolate.NearestNDInterpolator( xym, data1 )
    interp2 = scipy.interpolate.NearestNDInterpolator( xym, data2 )

    # interpolate the whole image, one color channel at a time    
    result0 = interp0(np.ravel(xx), np.ravel(yy)).reshape( xx.shape )
    result1 = interp1(np.ravel(xx), np.ravel(yy)).reshape( xx.shape )
    result2 = interp2(np.ravel(xx), np.ravel(yy)).reshape( xx.shape )

    # combine them into an output image
    result = np.dstack( (result0, result1, result2) )
    result = result.transpose(2,1,0)
    write_img(out_path, im_proj, im_geotrans, result)

if __name__ == "__main__":
    in_path = 'cq_test.tif'
    out_path = './fixed.tif'
    NoData_kill(in_path, out_path)



放大看


2.遥感图像增强

import cv2
import gdal
import numpy as np
from PIL import Image, ImageEnhance 
import matplotlib.pyplot as plt

def read_img(filename):
    dataset=gdal.Open(filename)

    im_width = dataset.RasterXSize
    im_height = dataset.RasterYSize

    im_geotrans = dataset.GetGeoTransform()
    im_proj = dataset.GetProjection()
    im_data = dataset.ReadAsArray(0,0,im_width,im_height)

    del dataset 
    return im_proj,im_geotrans,im_width, im_height,im_data


def write_img(filename, im_proj, im_geotrans, im_data):
    if 'int8' in im_data.dtype.name:
        datatype = gdal.GDT_Byte
    elif 'int16' in im_data.dtype.name:
        datatype = gdal.GDT_UInt16
    else:
        datatype = gdal.GDT_Float32

    if len(im_data.shape) == 3:
        im_bands, im_height, im_width = im_data.shape
    else:
        im_bands, (im_height, im_width) = 1,im_data.shape 

    driver = gdal.GetDriverByName("GTiff")
    dataset = driver.Create(filename, im_width, im_height, im_bands, datatype)

    dataset.SetGeoTransform(im_geotrans)
    dataset.SetProjection(im_proj)

    if im_bands == 1:
        dataset.GetRasterBand(1).WriteArray(im_data)
    else:
        for i in range(im_bands):
            dataset.GetRasterBand(i+1).WriteArray(im_data[i])

    del dataset

def deaw_gray_hist(gray_img):
    '''
    :param  gray_img大小为[h, w]灰度图像
    绘制直方图
    '''
    # 获取图像大小
    h, w = gray_img.shape
    gray_hist = np.zeros([256])
    for i in range(h):
        for j in range(w):
            gray_hist[gray_img[i][j]] += 1
    x = np.arange(256)
    # 绘制灰度直方图
    plt.bar(x, gray_hist)
    plt.xlabel("gray Label")
    plt.ylabel("number of pixels")
    plt.show()


def im_enhance(in_path,out_path):
    '''
    图像锐化
    '''
    im_proj,im_geotrans,im_width, im_height,im_data = read_img(in_path)

    im_data = im_data.transpose(2,1,0)
    im_data = Image.fromarray(im_data)
    enhancer = ImageEnhance.Sharpness(im_data)
    enhanced_im = enhancer.enhance(100.0)
    enhanced_im = np.array(enhanced_im)
    enhanced_im = enhanced_im.transpose(2,1,0)
    write_img(out_path, im_proj, im_geotrans, enhanced_im)

def linear_transform(in_path, a, b, out_path):
    '''
    # 对图像进行 线性变换
    :param img: [h, w, 3] 彩色图像
    :param a:  float  这里需要是浮点数,把图片uint8类型的数据强制转成float64
    :param b:  float
    :return: out = a * img + b
    '''
    im_proj,im_geotrans,im_width, im_height,im_data = read_img(in_path)
    out = a * im_data + b
    out[out > 255] = 255
    out = np.around(out)
    out = out.astype(np.uint8)
    write_img(out_path, im_proj, im_geotrans, out)


def normalize_transform(in_path, out_path):
    '''
    直方图正规化
    cv2.normalize(src,dst,alpha,beta,normType,dtype,mask)
    参数:
    src: 图像对象矩阵
    dst:输出图像矩阵(和src的shape一样)
    alpha:正规化的值,如果是范围值,为范围的下限 (alpha – norm value to normalize to or the lower range boundary in case of the range normalization.)
    beta:如果是范围值,为范围的上限;正规化中不用到 ( upper range boundary in case of the range normalization; it is not used for the norm normalization.)
    norm_type:normalize的类型
                cv2.NORM_L1:将像素矩阵的1-范数做为最大值(矩阵中值的绝对值的和)
                cv2.NORM_L2:将像素矩阵的2-范数做为最大值(矩阵中值的平方和的开方)
                cv2.NORM_MINMAX:将像素矩阵的∞-范数做为最大值 (矩阵中值的绝对值的最大值)
                
    dtype: 输出图像矩阵的数据类型,默认为-1,即和src一样
    mask:掩模矩阵,只对感兴趣的地方归一化
    '''
    im_proj,im_geotrans,im_width, im_height,im_data = read_img(in_path)
    c, h, w = im_data.shape
    arr_list = []
    for i in range(c):
        Imin, Imax = cv2.minMaxLoc(im_data[i])[:2]
        Omin, Omax = 0, 255
        a = float(Omax - Omin) / (Imax - Imin)
        b = Omin - a * Imin
        out = a * im_data[i] + b
        out = out.astype(np.uint8)
        arr_list.append(np.expand_dims(out,axis=0))

    temp = np.zeros_like(im_data)
    for i in range(c-1):
        temp[i] = arr_list[i]

    nor_out = temp
    write_img(out_path, im_proj, im_geotrans, nor_out)

def equalize_transfrom(in_path, out_path):
    '''
    全局直方图均衡化
    cv2.equalizeHist(src,dst)
        src: 图像对象矩阵,必须为单通道的uint8类型的矩阵数据
        dst:输出图像矩阵(和src的shape一样)
    '''
    im_proj,im_geotrans,im_width,im_height,im_data = read_img(in_path)
    c, h, w = im_data.shape
    temp = np.zeros_like(im_data)
    for i in range(c):
        temp[i] = cv2.equalizeHist(im_data[i])
    write_img(out_path, im_proj, im_geotrans, temp)

def restrict_hist(in_path, out_path):
    '''
    clahe=cv2.createCLAHE(clipLimit,tileGridSize)
        clipLimit:限制对比度的阈值,默认为40,直方图中像素值出现次数大于该阈值,多余的次数会被重新分配
        tileGridSize:图像会被划分的size, 如tileGridSize=(8,8),默认为(8,8)
    calhe.apply(img) #对img进行限制对比度自适应直方图均衡化
    '''
    im_proj,im_geotrans,im_width,im_height,im_data = read_img(in_path)
    c, h, w = im_data.shape
    temp = np.zeros_like(im_data)
    for i in range(c):
        clahe = cv2.createCLAHE(3,(8,8))
        temp[i] = clahe.apply(im_data[i])
    write_img(out_path, im_proj, im_geotrans, temp)

def gamma_trans(in_path, out_path):
    '''
    伽马变换
    '''
    im_proj,im_geotrans,im_width,im_height,im_data = read_img(in_path)
    img_norm = im_data/255.0  #注意255.0得采用浮点数
    img_gamma = np.power(img_norm,0.4)*255.0
    img_gamma = img_gamma.astype(np.uint8)
    write_img(out_path, im_proj, im_geotrans, img_gamma)

if __name__ == "__main__":
    in_path = './fixed2.tif'

    # out_path = './enhance2.tif'
    # linear_transform(in_path, 2.0, 10.0, out_path)

    # out_path = './enhance3.tif'
    # normalize_transform(in_path, out_path)

    # out_path = './enhance4.tif'
    # equalize_transfrom(in_path, out_path)

    # out_path = './enhance5.tif'
    # restrict_hist(in_path, out_path)

    out_path = './enhance6.tif'
    gamma_trans(in_path, out_path)

线性拉伸增强

直方图正规化

直方图均衡化

限制对比度自适应直方图均衡化

伽马变换

注意:如果影像太大,可以滑框做,毕竟遥感都是大影像,滑框做的时候最好选择能兼顾全局的方法

你可能感兴趣的:(gdal,python,cv2)