Tiff图像处理2_Python

图像数据类型转换、图像拉伸、波段判断

走过的坑。。。就不提了。之前做深度学习的训练,在数据集都快完成之际,也就是下载,做标签,裁剪,筛选都弄完了。送到网络里面去训练,由于数据类型的不符,导致出来的预测结果,都是黑色的。查阅了许多资料,可能存在的情况有很多。(下图截图自别人的博客)Tiff图像处理2_Python_第1张图片
一个图截不下
然后我就找到了数据类型的原因,准备尝试这个。因为确实,人家的数据能直接点开,咱的只能在ArcGIS里点开。对于一个搞png这种搞惯了的,确实看着很扎眼啊。。。然后右键查看了图像和mask的属性,确实是不一样。uint8类型的是能够打开的,所以我向师兄讨了个代码,能够进行数据类型转换。

import os
import numpy as np
from PIL import Image
from osgeo import gdal
import cv2
# 将图像类型转换为uint8类型(图像拉伸)
def get_uint8_image(image, vmin, vmax, pmin, pmax):
    ''' Scale image from float (or any) input array to uint8
    Parameters
    ----------
        image : 2D matrix  # 传入的是二维矩阵,多维的需要多次调用该函数
        vmin : float - minimum value  # 通常设置为None。4个参数,要么设置前两个,要么设置后两个
        vmax : float - maximum value  # 通常设置为None。这两个参数描述的是image中的最大值和最小值的大小。
        pmin : 下边界,取百分比,即,百分之pmin以下的舍弃,重点拉伸中间部分
        pmax : 上边界,取百分比,即,百分之pmax以上的舍弃,重点拉伸中间部分
    Returns
    -------
        2D matrix  # 返回的是二维矩阵
    '''
    if vmin is None:
        vmin = np.nanpercentile(image, pmin)
    if vmax is None:
        vmax = np.nanpercentile(image, pmax)
    # redistribute into range [0,255]
    # uint8Image = 1 + 254 * (image - vmin) / (vmax - vmin)  # 图像拉伸 1-255
    uint8Image = (255-0) * (image - vmin) / (vmax - vmin)  # 图像拉伸 0-255
    uint8Image[uint8Image < 1] = 0  # 二维矩阵中,所有小于1的部分,拉伸成0
    uint8Image[uint8Image > 255] = 255  # 二维矩阵中,所有大于255的部分,拉伸成255
    uint8Image[~np.isfinite(image)] = 0   # ~是取反,将二维矩阵中的所有无穷值,极大极小nan等,设置成0
    # 转换过后的图像不含nan值,会变为0
    return uint8Image.astype('uint8')  # 返回类型为uint8的图像,此时可以在桌面双击点开图像查看内容

至于图像拉伸又是怎么一回事吧,就不得不提到刚刚的伤心事。还是先放图。
这个是先裁剪,再拉伸的patch:(Tif图好像不能直接拉上来,会显示格式错误,所以用了截图,还多截了点没用的边缘)
Tiff图像处理2_Python_第2张图片
这个是先拉伸,再裁剪的patch:
Tiff图像处理2_Python_第3张图片
我是在RGB的三通道上进行的裁剪。所以第二个patch显示的应该是对的,是真彩色。而第一个patch,由于是先裁剪的,所以在整个patch上,相较于原来的裁剪前的大图(没有打开,图像太大了,但是仍能看到是真彩色图像):
Tiff图像处理2_Python_第4张图片
在最大值和最小值上,并不一致,导致虽然在数据上面,是和原图一模一样。但是不论用什么东西打开,他都是会给你做拉伸的,ArcGIS或者是普通编辑器都应该会,会把你本来图像的数据进行拉伸.也就是说,上下限就成了你patch 的最大最小值,而不是原图的最大最小值。这样显示出来,当然颜色就会有差异,不过数值没有任何差异。就是看着不太舒服,不是很容易识别。为了避免这个问题,我们应该主动去做归一化的图像拉伸,避免其他软件的自动拉伸。所以应该在最开始就做拉伸,再进行裁剪,能保证所有的patch都和原图一致。最终结果就是,数据类型一致了,网络预测也不是黑色了。(当然,又重新做了一遍裁剪,筛选等等步骤,颈椎留下了痛苦的泪水)

同时还有个好处,这个代码对于其他情况考虑的也很周到,比如图像中存在nan值,或者是超过了拉伸区间的值,都进行了处理。其实看这个公式,会觉得拉伸好像和归一化挺像的,思想都是从一个区间,变到另一个区间。至于他们是什么样的关系,是不是相通,没有进一步查阅资料,就不瞎说了。总而言之这个代码解决了一个二维矩阵的拉伸问题,同时也解决了数据类型转换的问题。

但是对于自己的数据,光是二维矩阵是不够用的,我们可是多通道的,所以整合了一下,写了一个自己适用的。
PS: 为了省事,单独把波段的判断拎出来,写了个小函数,毕竟后面还有很多整合的函数,需要去判断这个波段。

# 检测tif图的波段数
def band_number(img_path):
    im_data, im_geotrans, im_proj = readTiff(img_path)
    if len(im_data.shape) == 3:  # 三个参数,波段数,H,W
        im_bands, im_height, im_width = im_data.shape
    # elif len(im_data.shape) == 2:  # 两个参数,一般只有灰度图,band为1,不显示,只有H,W,相当于直接是二维矩阵了
    #     im_data = np.array([im_data])
    else:
        im_bands, (im_height, im_width) = 1, im_data.shape  # 同上,没有band值的返回值,就手动给band赋值
    return im_bands
# 将所有tif图,转换成uint8类型
def transform_allTiff_into_uint8(src_path,des_path):
    dirs = os.listdir(src_path)  # 逐个读取文件名
    i = 0
    over_No = 134  # 需要检测的图像的总数,根据需要自行设置
    for file_name in dirs:
        file_path = src_path + "/" + file_name  # 源img路径
        im_data, im_geotrans, im_proj = readTiff(file_path)
        if(band_number(file_path) == 1):  # 单通道(灰度图)
        # print(im_data.shape)
            im_height, im_width = im_data.shape
            uint_data = np.zeros((im_height, im_width)).astype(np.uint8)
            uint_data[::] = get_uint8_image(im_data, None, None, 0, 100)  # 最后两个参数可调为10,99,对应arcGIS显示
            writeTiff(uint_data, im_geotrans, im_proj, des_path + "/" + file_name)
        else:  # 多通道
            im_bands, im_height, im_width = im_data.shape
            uint_data = np.zeros((im_bands, im_height, im_width)).astype(np.uint8)
            for j in range(im_bands):  # 多波段用for循环,对应波段一一转换
                uint_data[j,::] = get_uint8_image(im_data[j], None, None, 0, 100)  # 最后两个参数可调为10,99,对应arcGIS显示
            # uint_data[0, ::] = get_uint8_image(im_data[0], None, None, 0, 100)  # R
            # uint_data[1, ::] = get_uint8_image(im_data[1], None, None, 0, 100)  # G
            # uint_data[2, ::] = get_uint8_image(im_data[2], None, None, 0, 100)  # B
            writeTiff(uint_data, im_geotrans, im_proj, des_path+"/"+ file_name)
        # print(uint_data.shape)
        # print(file_path)
        print(i)
        i = i + 1
        if i == over_No:  # 终止条件
            break
    print("transform over")

图像的读、写参考1的代码。直接复制粘贴即可。

你可能感兴趣的:(遥感,图像处理,python,tiff,图像处理,计算机视觉)