• numpy array数组 数据增广造成的小问题


    numpy array数组 数据增广造成的小问题


    有我们在进行不同数组相加时候,有时候会出现不同shape的数组相加,这个时候numpy 数组的 数据增广机制会自动启用,但是有时候 数据增广机制反而会阻碍我们达到我们的计算目标。

    一 举例说明1

    import os
    import numpy as np
    import skimage.io
    import glob
    
    "定义图像路径和保存数据的路径"
    mask_dir = '/data/study_Irrigation/Ca_256_val/labels'  # mask_dir路径中共有435个256*256尺寸的影像
    save_dir = '/data/study_Irrigation/Ca_256_val'
    classes_num = 2
    
    "初始化每个类的数目,我这里图像中只有2类"
    maskset_hist = np.zeros(classes_num)
    
    "返回目标目录中包含所有后缀名为 .tif 的文件的列表"
    label_paths = glob.glob(os.path.join(mask_dir, '*.tif'))
    # glob模块用法参考:https://zhuanlan.zhihu.com/p/71861602, https://rgb-24bit.github.io/blog/2018/glob.html
    # glob.glob('*.org')  # 返回包含所有后缀名为 .org 的文件的列表
    # glob.iglob('*/')  # 返回匹配所有目录的迭代器
    print(len(label_paths))
    
    "读取所有图像文件并且统计所有图像中的不同类别的数量"
    for label_path in label_paths:
        label = skimage.io.imread(label_path, as_gray=True)
        # 判断label.shape 是否是我之前裁剪好的尺寸(256, 256),不是的话要打印出这个图像的ID
        if label.shape != (256, 256):
            print('label.shape', label.shape)
            print('label_id', label_path.split("//")[-1])
        unique_values, unique_counts = np.unique(label, return_counts=True)
        # np.unique(arr, return_index, return_inverse, return_counts)
        # return_counts:如果为 true,返回去重数组中的元素在原数组中的出现次数,默认为False
        # 参考:https://blog.csdn.net/weixin_44211968/article/details/123772201
        
        # 检查每一个label文件是否正确:是否符合设定的类别数; 如果不符合,则跳过统计这个label,并记录其id。
        max_value, min_value = np.max(unique_values), np.min(unique_values)
        if max_value > (self.classes_num - 1) or min_value < 0:
             print('Labels can take value between 0 and number of classes.')
             print('Some problem with labels. Please check. label_set:', unique_values)
             print('Label Image ID: ' + label_path.split("//")[-1])
             continue
         else:
             maskset_hist += unique_counts
             
        # 计算每个类别数在总数的占比     
        class_ratio = maskset_hist / np.sum(maskset_hist) 
         # 平滑类别权重 
        class_weights = 1 / (np.log(self.normVal + class_ratio)) 
        # classWeights = 1 / (class_ratio + 0.01) # 直接置倒数
        class_weights = np.power(class_weights, self.label_weight_scale_factor)  # 根据标签权重系数缩放
        
        # 必须将imgset_mean数据类型转换为str。写入txt文件的必须是str,不能是数字。
        # 否则报错ufunc 'add' did not contain a loop with signature matching types (dtype('float32'), dtype
        # 直接读取出txt中的内容,其数据类型为str,因而不可以直接用来计算,需要将其数据类型改为数字.
        with open(os.path.join(self.save_dir, 'maskset_hist_class_ratio.txt'), 'w') as f:
            f.writelines(line.astype('str') + '\n' for line in maskset_hist)
            f.writelines(line.astype('str') + '\n' for line in class_ratio)
        with open(os.path.join(self.save_dir, 'class_weights.txt'), 'w') as f:
            f.writelines(line.astype('str') + '\n' for line in class_weights)
    
    print(maskset_hist) # [20447653.0 11992667.0]
    print(np.sum(maskset_hist))  # 32440320
    print(class_ratio) # [0.6303160079801926 0.36968399201980745]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    出现问题:
    mask_dir路径中共有435个256256尺寸的影像,这些影像包含的像素数目总数是 435256256=28508160。
    然而np.sum(maskset_hist)的结果为 32440320,足足比 mask_dir路径 中的像素总数多出来 3932160个,相当于多出来60个256
    256尺寸的影像。
    问题出在 maskset_hist += unique_counts ,
    因为 有的结果是unique_count [63076 2460], 有的结果是 unique_counts [65536]. 我们的出发点是统计图像中包含的2个类别值的每个类别的数量,我们期望所有的图像中的类别数量都是2类,得到的nique_counts 数组shape为(2,),然而有的图像中的类别数量只有1类,这样得到的 unique_counts 数组shape为(1,). shape为(2,)的数组和 shape为(1,)的数组 相加时候, 就会启动数组增广,因而实际上这里多加了一个数。例如:[63076 2460]和[65536]相加,实际上是 [63076 2460]和[65536 65536]相加.

    我暂时没有找到方法来避免不同shape数组相加时候自动出现numpy数据增广的机制。因而我改变上述代码中的统计图像中不同类别数量的方法。

    下面只改变核心代码:

    # 核心代码:
    
    # "初始化每个类的数目"
    background_num = 0
    Irrigated_num = 0
    
    for label_path in label_paths:
        label = skimage.io.imread(label_path, as_gray=True)
        # 判断label.shape 是否是我之前裁剪好的尺寸(256, 256),不是的话要打印出这个图像的ID
        if label.shape != (256, 256):
            print('label.shape', label.shape)
            print('label_id', label_path.split("//")[-1])
        unique_values = np.unique(mask, return_counts=False)
        # np.unique(arr, return_index, return_inverse, return_counts)
        # return_counts:如果为 true,返回去重数组中的元素在原数组中的出现次数,默认为False
        # 参考:https://blog.csdn.net/weixin_44211968/article/details/123772201
        
        # 检查每一个label文件是否正确:是否符合设定的类别数; 如果不符合,则跳过统计这个label,并记录其id。
        max_value, min_value = np.max(unique_values), np.min(unique_values)
        if max_value > (self.classes_num - 1) or min_value < 0:
             print('Labels can take value between 0 and number of classes.')
             print('Some problem with labels. Please check. label_set:', unique_values)
             print('Label Image ID: ' + label_path.split("//")[-1])
             continue
         else:
             background_num += np.sum(mask == 0)
             Irrigated_num += np.sum(mask == 1)
    
    maskset_hist = [background_num, Irrigated_num]
    class_ratio = maskset_hist / sum(maskset_hist)  # 计算每个类别数在总数的占比
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    完整代码如下:

    import os
    import numpy as np
    import skimage.io
    import glob
    
    "定义图像路径和保存数据的路径"
    mask_dir = '/data/study_Irrigation/Ca_256_val/labels'  # mask_dir路径中共有435个256*256尺寸的影像
    save_dir = '/data/study_Irrigation/Ca_256_val'
    classes_num = 2
    
    "初始化每个类的数目,我这里图像中只有2类"
    maskset_hist = np.zeros(classes_num)
    
    "返回目标目录中包含所有后缀名为 .tif 的文件的列表"
    label_paths = glob.glob(os.path.join(mask_dir, '*.tif'))
    # glob模块用法参考:https://zhuanlan.zhihu.com/p/71861602, https://rgb-24bit.github.io/blog/2018/glob.html
    # glob.glob('*.org')  # 返回包含所有后缀名为 .org 的文件的列表
    # glob.iglob('*/')  # 返回匹配所有目录的迭代器
    print(len(label_paths))
    
    "读取所有图像文件并且统计所有图像中的不同类别的数量"
    for label_path in label_paths:
        label = skimage.io.imread(label_path, as_gray=True)
        # 判断label.shape 是否是我之前裁剪好的尺寸(256, 256),不是的话要打印出这个图像的ID
        if label.shape != (256, 256):
            print('label.shape', label.shape)
            print('label_id', label_path.split("//")[-1])
        unique_values = np.unique(label, return_counts=False)
        # np.unique(arr, return_index, return_inverse, return_counts)
        # return_counts:如果为 true,返回去重数组中的元素在原数组中的出现次数,默认为False
        # 参考:https://blog.csdn.net/weixin_44211968/article/details/123772201
        
        # 检查每一个label文件是否正确:是否符合设定的类别数; 如果不符合,则跳过统计这个label,并记录其id。
        max_value, min_value = np.max(unique_values), np.min(unique_values)
        if max_value > (self.classes_num - 1) or min_value < 0:
             print('Labels can take value between 0 and number of classes.')
             print('Some problem with labels. Please check. label_set:', unique_values)
             print('Label Image ID: ' + label_path.split("//")[-1])
             continue
         else:
             background_num += np.sum(mask == 0)
             Irrigated_num += np.sum(mask == 1)
     
        maskset_hist = [background_num, Irrigated_num]
        # 计算每个类别数在总数的占比  
        class_ratio = maskset_hist / sum(maskset_hist)
        # 平滑类别权重 
        class_weights = 1 / (np.log(self.normVal + class_ratio)) 
        # classWeights = 1 / (class_ratio + 0.01) # 直接置倒数
        class_weights = np.power(class_weights, self.label_weight_scale_factor)  # 根据标签权重系数缩放
        
        # 必须将imgset_mean数据类型转换为str。写入txt文件的必须是str,不能是数字。
        # 否则报错ufunc 'add' did not contain a loop with signature matching types (dtype('float32'), dtype
        # 直接读取出txt中的内容,其数据类型为str,因而不可以直接用来计算,需要将其数据类型改为数字.
        with open(os.path.join(self.save_dir, 'maskset_hist_class_ratio.txt'), 'w') as f:
            f.writelines(line.astype('str') + '\n' for line in maskset_hist)
            f.writelines(line.astype('str') + '\n' for line in class_ratio)
        with open(os.path.join(self.save_dir, 'class_weights.txt'), 'w') as f:
            f.writelines(line.astype('str') + '\n' for line in class_weights)
    
    print(maskset_hist) # [20447653 8060507]
    print(np.sum(maskset_hist))  # 28508160
    print(class_ratio) # [0.7172561470119433 0.28274385298805677]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
  • 相关阅读:
    新华三与中国移动完成IPv6随流检测互通测试
    轻量级简约仪表板Dasherr
    【Python 实战基础】Pandas如何转换时间类型字段
    基于协同过滤算法的旅游推荐系统
    【Designing ML Systems】第 9 章 :生产中的持续学习和测试
    PAT 1006 Sign In and Sign out
    Redis集群搭建
    Nginx系列教程(二)| 一文带你读懂Nginx的正向与反向代理
    LeetCode 接雨水 双指针
    力扣刷题--3005. 最大频率元素计数【简单】
  • 原文地址:https://blog.csdn.net/LIWEI940638093/article/details/132649945