xiaoaoran / SemanticSTF

(CVPR 2023) The official project of "3D Semantic Segmentation in the Wild: Learning Generalized Models for Adverse-Condition Point Clouds"
95 stars 12 forks source link

Got an error that the number of samples is different using SemanticSTF. #5

Closed engineerJPark closed 8 months ago

engineerJPark commented 9 months ago

Hi, I'm raising an issue because I'm having a problem using SemanticSTF.

When I load xyz point data and label data from dataloader to use the validation set of SemanticSTF, I get an error that they have different sample lengths as follows.

 File "~/clip3d/dataloader/dataset.py", line 1072, in __getitem__
    labels = labels[inds]
IndexError: index 124898 is out of bounds for axis 0 with size 111392

When I actually print it out, it looks like this: on the left is the xyz point data, and on the right is the label data.

(138785, 4) (111028, 1)
(137495, 4) (109996, 1)
(138860, 4) (111088, 1)
(139240, 4) (111392, 1)

I'm currently using a different codebase(2DPASS), so there may be differences, but I don't see anything in SemanticSTF/PointDR/core/datasets/semantic_stf.py, I don't see any code that specifically addresses this or makes a difference, so I'm wondering if there's something wrong with the dataset you uploaded.

code below is the dataset class that load xyz point data and label data from SemanticSTF.

import os
import yaml
import numpy as np
from PIL import Image

from torch.utils import data

def absoluteFilePaths(directory, num_vote):
    for dirpath, _, filenames in os.walk(directory):
        filenames.sort()
        for f in filenames:
            for _ in range(num_vote):
                yield os.path.abspath(os.path.join(dirpath, f))

class SemanticKITTISTF(data.Dataset):
    def __init__(self, config, data_path, num_vote=1):
        with open(config['dataset_params']['label_mapping'], 'r') as stream:
            semkittiyaml = yaml.safe_load(stream)

        self.config = config
        # self.corruption = corruption
        self.imageset = 'val'
        self.num_vote = num_vote
        self.learning_map = semkittiyaml['learning_map']
        original_data_path = data_path
        self.im_idx = []
        self.im_idx += absoluteFilePaths('/'.join([data_path.replace('sequences', 'SemanticSTF'), 'val', 'velodyne']), num_vote)
        self.im_idx = sorted(self.im_idx)
        # added
        calib_path = os.path.join(original_data_path, '08', "calib.txt")
        calib = self.read_calib(calib_path)
        self.proj_matrix = np.matmul(calib["P2"], calib["Tr"]) 
        print('dataloader corruption_dataset init length im_idx', len(self.im_idx))

        self.no_image = False
        # if config['model_params']['model_architecture'] == "baseline" or config['baseline_only'] is True:
        if config['model_params']['model_architecture'] != "arch_2dpass" or config['baseline_only'] is True:
            self.no_image = True

        # print(self.im_idx[0])
        # print(self.im_idx[0].replace('velodyne', 'labels')[:-3] + 'label')

    def __len__(self):
        'Denotes the total number of samples'
        return len(self.im_idx)

    @staticmethod
    def read_calib(calib_path):
        """
        :param calib_path: Path to a calibration text file.
        :return: dict with calibration matrices.
        """
        calib_all = {}
        with open(calib_path, 'r') as f:
            for line in f.readlines():
                if line == '\n':
                    break
                key, value = line.split(':', 1)
                calib_all[key] = np.array([float(x) for x in value.split()])

        # reshape matrices
        calib_out = {}
        calib_out['P2'] = calib_all['P2'].reshape(3, 4)  # 3x4 projection matrix for left camera
        calib_out['Tr'] = np.identity(4)  # 4x4 matrix
        calib_out['Tr'][:3, :4] = calib_all['Tr'].reshape(3, 4)

        return calib_out

    def __getitem__(self, index):
        # print('SemanticKITTIC getitem')
        raw_data = np.fromfile(self.im_idx[index], dtype=np.float32).reshape((-1, 4))

        origin_len = len(raw_data)
        raw_data = raw_data[:, :4]
        points = raw_data[:, :3]

        annotated_data = np.fromfile(self.im_idx[index].replace('velodyne', 'labels')[:-3] + 'label',
                                     dtype=np.uint32).reshape((-1, 1))
        instance_label = annotated_data >> 16
        annotated_data = annotated_data & 0xFFFF  # delete high 16 digits binary

        ## change invalid (snow, fog, rain ...) to ignore label
        idx_20 = np.where(annotated_data == 20)
        annotated_data[idx_20] = 0

        print(raw_data.shape, annotated_data.shape)
        print(np.unique(annotated_data))

        if self.config['dataset_params']['ignore_label'] != 0:
            annotated_data -= 1
            annotated_data[annotated_data == -1] = self.config['dataset_params']['ignore_label']

        if not self.no_image:
            # added
            image_file = self.im_idx[index].replace('velodyne', 'image_2').replace('.bin', '.png')
            image = Image.open(image_file)

        data_dict = {}
        data_dict['xyz'] = points
        data_dict['labels'] = annotated_data.astype(np.uint8)
        data_dict['instance_label'] = instance_label
        data_dict['signal'] = raw_data[:, 3:4]
        data_dict['origin_len'] = origin_len
        if not self.no_image:
            data_dict['img'] = image # added
            data_dict['proj_matrix'] = self.proj_matrix # added

        return data_dict, self.im_idx[index]

Thank you in advance for your kind response. Sincerly,

Jaywxy commented 6 months ago

我将semanticstf的val数据改为22序列,用semantickitti的API @查看点云和他的标签,也发现了点云数量和标签输入不一致,你问你最后复现了吗? python visualize.py --sequence 22 --dataset /mnt/860evo_500/dataset/semantic-kitti/


INTERFACE: Dataset /mnt/860evo_500/dataset/semantic-kitti/ Config config/semantic-kitti.yaml Sequence 22 Predictions None ignore_semantics False do_instances False ignore_safety False offset 0


Opening config file config/semantic-kitti.yaml Sequence folder exists! Using sequence from /mnt/860evo_500/dataset/semantic-kitti/sequences/22/velodyne Labels folder exists! Using labels from /mnt/860evo_500/dataset/semantic-kitti/sequences/22/labels Using semantics in visualizer Points shape: (139240, 3) Label shape: (111392,) Traceback (most recent call last): File "visualize.py", line 154, in semantics=semantics, instances=instances and semantics) File "/home/wxy/semantic-kitti-api/auxiliary/laserscanvis.py", line 29, in init self.update_scan() File "/home/wxy/semantic-kitti-api/auxiliary/laserscanvis.py", line 132, in update_scan self.scan.open_label(self.label_names[self.offset]) File "/home/wxy/semantic-kitti-api/auxiliary/laserscan.py", line 236, in open_label self.set_label(label) File "/home/wxy/semantic-kitti-api/auxiliary/laserscan.py", line 252, in set_label raise ValueError("Scan and Label don't contain same number of points") ValueError: Scan and Label don't contain same number of points

Hi, I'm raising an issue because I'm having a problem using SemanticSTF.

When I load xyz point data and label data from dataloader to use the validation set of SemanticSTF, I get an error that they have different sample lengths as follows.

 File "~/clip3d/dataloader/dataset.py", line 1072, in __getitem__
    labels = labels[inds]
IndexError: index 124898 is out of bounds for axis 0 with size 111392

When I actually print it out, it looks like this: on the left is the xyz point data, and on the right is the label data.

(138785, 4) (111028, 1)
(137495, 4) (109996, 1)
(138860, 4) (111088, 1)
(139240, 4) (111392, 1)

I'm currently using a different codebase(2DPASS), so there may be differences, but I don't see anything in SemanticSTF/PointDR/core/datasets/semantic_stf.py, I don't see any code that specifically addresses this or makes a difference, so I'm wondering if there's something wrong with the dataset you uploaded.

code below is the dataset class that load xyz point data and label data from SemanticSTF.

import os
import yaml
import numpy as np
from PIL import Image

from torch.utils import data

def absoluteFilePaths(directory, num_vote):
    for dirpath, _, filenames in os.walk(directory):
        filenames.sort()
        for f in filenames:
            for _ in range(num_vote):
                yield os.path.abspath(os.path.join(dirpath, f))

class SemanticKITTISTF(data.Dataset):
    def __init__(self, config, data_path, num_vote=1):
        with open(config['dataset_params']['label_mapping'], 'r') as stream:
            semkittiyaml = yaml.safe_load(stream)

        self.config = config
        # self.corruption = corruption
        self.imageset = 'val'
        self.num_vote = num_vote
        self.learning_map = semkittiyaml['learning_map']
        original_data_path = data_path
        self.im_idx = []
        self.im_idx += absoluteFilePaths('/'.join([data_path.replace('sequences', 'SemanticSTF'), 'val', 'velodyne']), num_vote)
        self.im_idx = sorted(self.im_idx)
        # added
        calib_path = os.path.join(original_data_path, '08', "calib.txt")
        calib = self.read_calib(calib_path)
        self.proj_matrix = np.matmul(calib["P2"], calib["Tr"]) 
        print('dataloader corruption_dataset init length im_idx', len(self.im_idx))

        self.no_image = False
        # if config['model_params']['model_architecture'] == "baseline" or config['baseline_only'] is True:
        if config['model_params']['model_architecture'] != "arch_2dpass" or config['baseline_only'] is True:
            self.no_image = True

        # print(self.im_idx[0])
        # print(self.im_idx[0].replace('velodyne', 'labels')[:-3] + 'label')

    def __len__(self):
        'Denotes the total number of samples'
        return len(self.im_idx)

    @staticmethod
    def read_calib(calib_path):
        """
        :param calib_path: Path to a calibration text file.
        :return: dict with calibration matrices.
        """
        calib_all = {}
        with open(calib_path, 'r') as f:
            for line in f.readlines():
                if line == '\n':
                    break
                key, value = line.split(':', 1)
                calib_all[key] = np.array([float(x) for x in value.split()])

        # reshape matrices
        calib_out = {}
        calib_out['P2'] = calib_all['P2'].reshape(3, 4)  # 3x4 projection matrix for left camera
        calib_out['Tr'] = np.identity(4)  # 4x4 matrix
        calib_out['Tr'][:3, :4] = calib_all['Tr'].reshape(3, 4)

        return calib_out

    def __getitem__(self, index):
        # print('SemanticKITTIC getitem')
        raw_data = np.fromfile(self.im_idx[index], dtype=np.float32).reshape((-1, 4))

        origin_len = len(raw_data)
        raw_data = raw_data[:, :4]
        points = raw_data[:, :3]

        annotated_data = np.fromfile(self.im_idx[index].replace('velodyne', 'labels')[:-3] + 'label',
                                     dtype=np.uint32).reshape((-1, 1))
        instance_label = annotated_data >> 16
        annotated_data = annotated_data & 0xFFFF  # delete high 16 digits binary

        ## change invalid (snow, fog, rain ...) to ignore label
        idx_20 = np.where(annotated_data == 20)
        annotated_data[idx_20] = 0

        print(raw_data.shape, annotated_data.shape)
        print(np.unique(annotated_data))

        if self.config['dataset_params']['ignore_label'] != 0:
            annotated_data -= 1
            annotated_data[annotated_data == -1] = self.config['dataset_params']['ignore_label']

        if not self.no_image:
            # added
            image_file = self.im_idx[index].replace('velodyne', 'image_2').replace('.bin', '.png')
            image = Image.open(image_file)

        data_dict = {}
        data_dict['xyz'] = points
        data_dict['labels'] = annotated_data.astype(np.uint8)
        data_dict['instance_label'] = instance_label
        data_dict['signal'] = raw_data[:, 3:4]
        data_dict['origin_len'] = origin_len
        if not self.no_image:
            data_dict['img'] = image # added
            data_dict['proj_matrix'] = self.proj_matrix # added

        return data_dict, self.im_idx[index]

Thank you in advance for your kind response. Sincerly,

这是为命令加了--ignore_semantic de 结果......这是啥图啊 image

xiaoaoran commented 6 months ago

@Jaywxy @engineerJPark The point dimension in STF dataset is 5 instead of 4 as in SemanticKITTI. So reshape it to [-1,5] when reading it.

You can find it in our code https://github.com/xiaoaoran/SemanticSTF/blob/77ebee6196b6dcd9a0dce1ebe57f35c9e29c5bb7/PointDR/core/datasets/semantic_stf.py#L148

Jaywxy commented 5 months ago

感谢回复