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

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

  • 一 举例说明1

有我们在进行不同数组相加时候,有时候会出现不同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]

出现问题:
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)  # 计算每个类别数在总数的占比

完整代码如下:

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]

你可能感兴趣的:(数据处理/数据科学/Array,numpy)