PointNet语义分割预测代码部分最详解!!!!!

如果你还没有理清预测部分的代码,那请耐心的看以下的代码注释,一定能够帮助您全部理清顺序

包含以下相关文件
meta
all_data_list :列举的是数据集中所包含的所有训练数据,以npy格式结尾;
anno_path : 是对应文件的相对存放路径;
area6_data_label :为验证训练模型时所用到数据集的数据文件列表;
class_name :数据集所包含的所有13类分类类别;

batch_inference.py :用于预测分类,将预测结果导出
collect_indoor3d_data :用于生成npy格式文件
indoor3d_uti.py :包含了作者写的功能性函数

batch_inference.py

以下只贴出比较关键的代码解释

BATCH_SIZE = FLAGS.batch_size
NUM_POINT = FLAGS.num_point
MODEL_PATH = FLAGS.model_path
GPU_INDEX = FLAGS.gpu
DUMP_DIR = FLAGS.dump_dir
if not os.path.exists(DUMP_DIR): os.mkdir(DUMP_DIR)
LOG_FOUT = open(os.path.join(DUMP_DIR, 'log_evaluate.txt'), 'w')
LOG_FOUT.write(str(FLAGS)+'\n')
DIR = os.path.join(ROOT_DIR,'data/npy')
"""我自己创建的文件夹,提供collect_indoor3d_data.py生成的npy文件存储路径"""
ROOM_PATH_LIST = [os.path.join(DIR,line.rstrip()) for line in open(FLAGS.room_data_filelist)]
"""room_data_filelist为数据集npy按顺序排列,将其文件路径一一列出"""
NUM_CLASSES = 13
"""13类分类"""

定义全局变量,在sem_seg中创建dump文件夹,其中创建log日志文件,将所有全局变量写入日志文件内。

def evaluate():
    is_training = False
     
    with tf.device('/gpu:'+str(GPU_INDEX)):
        pointclouds_pl, labels_pl = placeholder_inputs(BATCH_SIZE, NUM_POINT)
        is_training_pl = tf.placeholder(tf.bool, shape=())
        """定义输入输出占位符 """
        # simple model
        pred = get_model(pointclouds_pl, is_training_pl)
        """ 模型训练 """
        loss = get_loss(pred, labels_pl)
        """ 计算损失"""
        pred_softmax = tf.nn.softmax(pred)
        """ 将预测结果归一化"""
        #tf.nn.softmax()就是把一个N*1的向量归一化为(0,1)之间的值
        # Add ops to save and restore all the variables.
        saver = tf.train.Saver()
        """ 设置保存模型"""

构建整个训练网络流程的图,很普通的操作

    # Create a session
    config = tf.ConfigProto()
    config.gpu_options.allow_growth = True
    config.allow_soft_placement = True
    config.log_device_placement = True
    sess = tf.Session(config=config)

    # Restore variables from disk.
    saver.restore(sess, MODEL_PATH)
    log_string("Model restored.")

创建会话,恢复模型,为预测做准备

    ops = {'pointclouds_pl': pointclouds_pl,
           'labels_pl': labels_pl,
           'is_training_pl': is_training_pl,
           'pred': pred,
           'pred_softmax': pred_softmax,
           'loss': loss}
    
    total_correct = 0
    """ 总正确数"""
    total_seen = 0
    """ 总个数 """

构建需要用到的输入的字典

    for room_path in ROOM_PATH_LIST:
    """将272个房间npy文件路径一一进行预测"""
        out_data_label_filename = os.path.basename(room_path)[:-4] + '_pred.txt'
        """生成存储预测对应房间名称的点云数据的空文本"""
        out_data_label_filename = os.path.join(DUMP_DIR, out_data_label_filename)
        """ 添加存放路径"""
        out_gt_label_filename = os.path.basename(room_path)[:-4] + '_gt.txt'
        """生成存储实际对应房间名称的点云数据的空文本"""
        out_gt_label_filename = os.path.join(DUMP_DIR, out_gt_label_filename)
        """添加存储路径"""
        print(room_path, out_data_label_filename)
        a, b = eval_one_epoch(sess, ops, room_path, out_data_label_filename, out_gt_label_filename)
        """单次预测"""
        total_correct += a
        total_seen += b
        fout_out_filelist.write(out_data_label_filename+'\n')
    fout_out_filelist.close()
    log_string('all room eval accuracy: %f'% (total_correct / float(total_seen)))

将每个房间的文件依次进行预测

def eval_one_epoch(sess, ops, room_path, out_data_label_filename, out_gt_label_filename):
    error_cnt = 0
    is_training = False
    total_correct = 0
    total_seen = 0
    loss_sum = 0
    total_seen_class = [0 for _ in range(NUM_CLASSES)]
    """ 创建13个元素的列表,用于存放总的每个类的个数 """
    total_correct_class = [0 for _ in range(NUM_CLASSES)]
    """ 创建13个元素的列表,存放总的每个类的正确个数"""
    if FLAGS.visu:
        fout = open(os.path.join(DUMP_DIR, os.path.basename(room_path)[:-4]+'_pred.obj'), 'w')
        fout_gt = open(os.path.join(DUMP_DIR, os.path.basename(room_path)[:-4]+'_gt.obj'), 'w')
    fout_data_label = open(out_data_label_filename, 'w')
    """ _pred.txt用于写入预测点云数据 """
    fout_gt_label = open(out_gt_label_filename, 'w')
    """ _gt.txt用于写入实际点云数据 """
    
    current_data, current_label = indoor3d_util.room2blocks_wrapper_normalized(room_path, NUM_POINT)
    """
    将点云数据分块化
    current_data包含的是所有块中的点云信息
    current_label包含的是所有块中的点云的标签"""
    current_data = current_data[:,0:NUM_POINT,:]
    current_label = np.squeeze(current_label)
    # Get room dimension..获取房间尺寸
    data_label = np.load(room_path)
    data = data_label[:,0:6]
    max_room_x = max(data[:,0])
    max_room_y = max(data[:,1])
    max_room_z = max(data[:,2])
    
    file_size = current_data.shape[0]
    num_batches = file_size // BATCH_SIZE
    print(file_size)

以上都是对数据进行预处理,我们进入以下函数进行详细分析 current_data, current_label是如何生成的
current_data, current_label =indoor3d_util.room2blocks_wrapper_normalized(room_path, NUM_POINT)

room2blocks_wrapper_normalized() :提取出npy点云信息

def room2blocks_wrapper_normalized(data_label_filename, num_point, block_size=1.0, stride=1.0,
                                   random_sample=False, sample_num=None, sample_aug=1):
    if data_label_filename[-3:] == 'txt':
        data_label = np.loadtxt(data_label_filename)
    elif data_label_filename[-3:] == 'npy':
        data_label = np.load(data_label_filename)
        """ 将房间里的所有点信息读取出,包含xyzRGBL,命为data_label"""
    else:
        print('Unknown file type! exiting.')
        exit()
    return room2blocks_plus_normalized(data_label, num_point, block_size, stride,
                                       random_sample, sample_num, sample_aug)

将单个房间的所有点云信息读取出来后,进入room2block_plius_normalized()数据处理

room2blocks_plus_normalized():

def room2blocks_plus_normalized(data_label, num_point, block_size, stride,
                                random_sample, sample_num, sample_aug):
    """ 
    具有输入文件名和RGB预处理。 对于每个块集中XYZ,将归一化XYZ添加为678通道
    """
    data = data_label[:,0:6]
    """ 
    将所有点的XYZRGB读出,data为列表
    """
    data[:,3:6] /= 255.0
    """
    将RGB进行归一化
    """
    label = data_label[:,-1].astype(np.uint8)
    """
    提取出所有label
    """
    max_room_x = max(data[:,0])
    max_room_y = max(data[:,1])
    max_room_z = max(data[:,2])
    """
    将最大的xyz取出,进行xyz归一化做准备
    """
    data_batch, label_batch = room2blocks(data, label, num_point, block_size, stride,
                                          random_sample, sample_num, sample_aug)
     """
     data_batch包含了所有块的点云信息,包含xyzrgb
     label_batch包含了所有块的点云标签
     """
    new_data_batch = np.zeros((data_batch.shape[0], num_point, 9))
    """
    创建个(30,4096,9),将所有信息都填入新的数组中
    """
    for b in range(data_batch.shape[0]):
    """
    一共有30个块,每个块进行读取
    """
        new_data_batch[b, :, 6] = data_batch[b, :, 0]/max_room_x
        new_data_batch[b, :, 7] = data_batch[b, :, 1]/max_room_y
        new_data_batch[b, :, 8] = data_batch[b, :, 2]/max_room_z
        """
        将房间的归一化坐标填入678
        """
        minx = min(data_batch[b, :, 0])
        """
        最小x坐标
        """
        miny = min(data_batch[b, :, 1])
        """
        最小y坐标
        """
        data_batch[b, :, 0] -= (minx+block_size/2)
        data_batch[b, :, 1] -= (miny+block_size/2)
    new_data_batch[:, :, 0:6] = data_batch
    return new_data_batch, label_batch

data包含单个房间的所有xyzRGB信息,并将RGB归一化,利用room2blocks将点云数据进行分块化,生成data_batch(包含30个块的4096个点云xyzRGB信息), label_batch(对应的每个快的标签),创建new_data_batch(30,4096,9),将xyz坐标除最大xyz坐标作为归一化坐标填入new_data_batch的678。

room2blocks():将data进行分块化成1m x 1m的block

def room2blocks(data, label, num_point, block_size=1.0, stride=1.0,
                random_sample=False, sample_num=None, sample_aug=1):

    assert(stride<=block_size)
    #np.amax()
    limit = np.amax(data, 0)[0:3]
    """
    取出xyz的最大坐标,为确定一共有多少block
    """ 
    # Get the corner location for our sampling blocks 获取采样块的拐角位置
    xbeg_list = []
    ybeg_list = []
    if not random_sample:
        num_block_x = int(np.ceil((limit[0] - block_size) / stride)) + 1 
        """
        np.ceil计算大于等于改值的最小整数
        x方向的分块数为6
        """
        num_block_y = int(np.ceil((limit[1] - block_size) / stride)) + 1
        """
        y方向的分块数为5
        """
        for i in range(num_block_x):
        """先定x坐标,按y方向逐个移动分块"""
            for j in range(num_block_y):
                xbeg_list.append(i*stride) 
                ybeg_list.append(j*stride)
                """
                将块索引填入列表中
                """

在这里插入图片描述
用画图来解释为如下图
在这里插入图片描述
首先确定x坐标为0,然后以y方向逐块分块,当分好后,x坐标加1,再按y方向分块,直至将所有房间全部分块好。接下来继续看代码。

 else:
        num_block_x = int(np.ceil(limit[0] / block_size))
        num_block_y = int(np.ceil(limit[1] / block_size))
        if sample_num is None:
            sample_num = num_block_x * num_block_y * sample_aug
        for _ in range(sample_num):
            xbeg = np.random.uniform(-block_size, limit[0]) 
            ybeg = np.random.uniform(-block_size, limit[1]) 
            xbeg_list.append(xbeg)
            ybeg_list.append(ybeg)

    # Collect blocks
    block_data_list = []
    block_label_list = []
    idx = 0
    for idx in range(len(xbeg_list)): 
       xbeg = xbeg_list[idx]
       ybeg = ybeg_list[idx]
       """
       取出分好的块
       """
       xcond = (data[:,0]<=xbeg+block_size) & (data[:,0]>=xbeg)
       """
       开始获取块中点云信息,做个判断,满足x坐标<1且同时x坐标>1为true,否则false
       """
       ycond = (data[:,1]<=ybeg+block_size) & (data[:,1]>=ybeg)
       """
       满足y坐标是否在此块中
       """
       cond = xcond & ycond
       """
       xy坐标同时满足的为true,相当于确定了点的索引
       """
       if np.sum(cond) < 100: # discard block if there are less than 100 pts.
           continue
       """
       如果少于100个点,则丢弃这个块
       """
       block_data = data[cond, :]
       """
       data包含所有点的xyzRGB信息,提取出符合该块范围的点云
       """
       block_label = label[cond]
       """
       提取出对应的标签
       """
       
       # randomly subsample data #随机子样本数据
       block_data_sampled, block_label_sampled = \
           sample_data_label(block_data, block_label, num_point)
       """
       将每个块的点都采样为4096个点,
       块中多于4096的点进行随机选择4096个,块中少于4096进行重复点填充至4096
       """
       block_data_list.append(np.expand_dims(block_data_sampled, 0))
       block_label_list.append(np.expand_dims(block_label_sampled, 0))
            
    return np.concatenate(block_data_list, 0), \
           np.concatenate(block_label_list, 0)
      """
      block_data_list包含了所有块的点云信息,包含xyzrgb
      block_label_list包含了所有块的点云标签
      """

以上是indoor3d_util中的代码,紧接着回到eval_one_epoch数据预处理结束之后

  for batch_idx in range(num_batches):
        start_idx = batch_idx * BATCH_SIZE
        end_idx = (batch_idx+1) * BATCH_SIZE
        cur_batch_size = end_idx - start_idx
        
        feed_dict = {ops['pointclouds_pl']: current_data[start_idx:end_idx, :, :],
                     ops['labels_pl']: current_label[start_idx:end_idx],
                     ops['is_training_pl']: is_training}
        loss_val, pred_val = sess.run([ops['loss'], ops['pred_softmax']],
                                      feed_dict=feed_dict)

        if FLAGS.no_clutter:
            pred_label = np.argmax(pred_val[:,:,0:12], 2) # BxN
        else:
            pred_label = np.argmax(pred_val, 2) # BxN

分批次进行网络预测

        for b in range(BATCH_SIZE):
       """分批次对每个预测的数据进行处理,这里BATCH_SIZE设置为1,每次只处理一个数据"""
            pts = current_data[start_idx+b, :, :]
            """取出当前批次的点云数据,包括xyz坐标"""
            l = current_label[start_idx+b,:]
            pts[:,6] *= max_room_x
            pts[:,7] *= max_room_y
            pts[:,8] *= max_room_z
            """678加上房间的标准化位置坐标"""
            pts[:,3:6] *= 255.0
            """颜色255占位"""
            pred = pred_label[b, :]
            for i in range(NUM_POINT):
                color = indoor3d_util.g_label2color[pred[i]]
                """ 添加颜色"""
                color_gt = indoor3d_util.g_label2color[current_label[start_idx+b, i]]
                if FLAGS.visu:
                    fout.write('v %f %f %f %d %d %d\n' % (pts[i,6], pts[i,7], pts[i,8], color[0], color[1], color[2]))
                    """ 将点云信息和颜色信息写入预测的文件"""
                    fout_gt.write('v %f %f %f %d %d %d\n' % (pts[i,6], pts[i,7], pts[i,8], color_gt[0], color_gt[1], color_gt[2]))
                    """ 写入实际点云文件"""
                fout_data_label.write('%f %f %f %d %d %d %f %d\n' % (pts[i,6], pts[i,7], pts[i,8], pts[i,3], pts[i,4], pts[i,5], pred_val[b,i,pred[i]], pred[i]))
                fout_gt_label.write('%d\n' % (l[i]))
        correct = np.sum(pred_label == current_label[start_idx:end_idx,:])
        total_correct += correct
        total_seen += (cur_batch_size*NUM_POINT)
        loss_sum += (loss_val*BATCH_SIZE)
        for i in range(start_idx, end_idx):
            for j in range(NUM_POINT):
                l = current_label[i, j]
                total_seen_class[l] += 1
                total_correct_class[l] += (pred_label[i-start_idx, j] == l)

    log_string('eval mean loss: %f' % (loss_sum / float(total_seen/NUM_POINT)))
    log_string('eval accuracy: %f'% (total_correct / float(total_seen)))
    fout_data_label.close()
    fout_gt_label.close()
    if FLAGS.visu:
        fout.close()
        fout_gt.close()
    return total_correct, total_seen
  • 3
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
.gitignore 文件是在使用git管理项目时必备的文件。它的作用是告诉git哪些文件或文件夹应该被忽略,不纳入版本控制。通过在.gitignore文件中列出需要忽略的文件或文件夹的规则,git会自动忽略这些文件的变动,不进行版本控制。 在.gitignore文件中,每一行表示一个忽略规则。以"#"开头的行表示注释,不会被git读取。规则可以使用通配符,比如使用"*"表示匹配任意字符,使用"?"表示匹配单个字符。可以使用斜杠"/"表示路径分隔符,表示要忽略的文件或文件夹的路径。如果需要忽略某个文件夹下的所有内容,可以在路径后面加上斜杠,例如"folder/"。 举个例子,假设在.gitignore文件中有如下规则: ``` # this is .gitignore file. # 以下是忽略的文件 folder/ ``` 这个规则表示忽略名为"folder"的文件夹及其下的所有内容。 通过使用.gitignore文件,我们可以灵活地控制哪些文件需要纳入版本控制,哪些文件不需要纳入版本控制,从而避免提交不必要的文件变动,使代码仓库更加清晰和高效。 引用 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Git 开发必备 .gitignore 详解!【建议收藏】](https://blog.csdn.net/u011074149/article/details/119887324)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值