├── README.md ├── docs └── viz.gif └── visualizer ├── listdir.m ├── main_reader.m ├── readBin.m ├── readLabel.m └── semantickitti_label_colormap.m /README.md: -------------------------------------------------------------------------------- 1 | # semantickitti-matlab 2 | Some useful tools written in Matlab for SemanticKITTI 3 | 4 | 5 | ## How to use 6 | - directory *visualizer*: to show both semantics and instances of data like below. 7 | - ![](docs/viz.gif) 8 | - a long example is in [the Youtube link](https://youtu.be/gNeEfPEyHuw). 9 | 10 | 11 | ## Plan 12 | - more to be added... 13 | 14 | ## Contact 15 | - paulgkim@kaist.ac.kr 16 | -------------------------------------------------------------------------------- /docs/viz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gisbi-kim/semantickitti-matlab/026f2d2548ed709c6eb575622016812082a7ca33/docs/viz.gif -------------------------------------------------------------------------------- /visualizer/listdir.m: -------------------------------------------------------------------------------- 1 | function [files] = listdir(dir_path) 2 | 3 | files = dir(dir_path); 4 | files(1:2) = []; % remove . and .. 5 | files = {files(:).name}; 6 | 7 | end 8 | 9 | -------------------------------------------------------------------------------- /visualizer/main_reader.m: -------------------------------------------------------------------------------- 1 | clc; 2 | clear; 3 | addpath(genpath('.')); 4 | 5 | % set the colormap (for semantics) 6 | semantickitti_label_colormap; 7 | 8 | % set the colormap (for instances) 9 | num_max_instances = 10000; 10 | instance_colormap = round(255 * rand(num_max_instances, 3)); 11 | non_movable_color = 210; 12 | instance_colormap = [non_movable_color, non_movable_color, non_movable_color; instance_colormap]; % the first color is reserved for the non-movable instance color. 13 | 14 | %% 15 | SEQ_IDX = "00"; 16 | 17 | BASE_DIR = "your/path/to/kitti/"; % change this 18 | DIR_SCAN = fullfile(BASE_DIR, SEQ_IDX, "velodyne"); 19 | DIR_LABEL = fullfile(BASE_DIR, SEQ_IDX, "labels"); 20 | 21 | scan_filenames = listdir(DIR_SCAN); 22 | label_filenames = listdir(DIR_LABEL); 23 | 24 | num_scans = length(scan_filenames); 25 | 26 | %% 27 | clear framecaptures_semantics; 28 | clear framecaptures_instances; 29 | frame_recorded_idx = 1; 30 | 31 | num_skips = 2; 32 | for target_idx = 1:num_scans 33 | if(rem(target_idx, num_skips) ~= 0) 34 | continue; 35 | end 36 | 37 | % 0. read 38 | target_idx_str = num2str(target_idx, '%06.f'); 39 | target_scan_filename = scan_filenames{target_idx}; target_scan_filepath = fullfile(DIR_SCAN, target_scan_filename); 40 | target_label_filename = label_filenames{target_idx}; target_label_filepath = fullfile(DIR_LABEL, target_label_filename); 41 | 42 | pc = readBin(target_scan_filepath, 0); 43 | [pc_lb, pc_id] = readLabel(target_label_filepath); % lb: label (28 types), id: instance id 44 | 45 | % 1. semantic seg 46 | pc_lb_set = unique(pc_lb); 47 | num_lb = length(pc_lb_set); 48 | if(num_lb > num_LABEL_INDEXES) 49 | disp(strcat("- ", num2str(target_idx), ": false scan, pass it.")); 50 | continue; 51 | end 52 | 53 | pc_colors = zeros(pc.Count, 3); 54 | for ith = 1:numel(pc_lb_set) 55 | semantic_idx = pc_lb_set(ith); 56 | semantic_color = LABEL_COLORMAP_uint((semantic_idx == LABEL_INDEXES), :); 57 | points_idx_this_semantic = find(semantic_idx == pc_lb); 58 | pc_colors(points_idx_this_semantic, :) = repmat(semantic_color, numel(points_idx_this_semantic), 1); 59 | end 60 | pc.Color = uint8(pc_colors); 61 | 62 | % 2. instance seg 63 | pc_instance = pointCloud(pc.Location); 64 | 65 | [pc_id_set, num_each_id] = unique(pc_id); 66 | num_id = length(pc_id_set); 67 | 68 | pc_instance_colors = round(255 * 0.8 * ones(pc_instance.Count, 3)); 69 | for ith = 1:numel(pc_id_set) 70 | instance_idx = pc_id_set(ith); 71 | instance_color = instance_colormap(instance_idx+1, :); % tmp, blue 72 | points_idx_this_instance = find(instance_idx == pc_id); 73 | pc_instance_colors(points_idx_this_instance, :) = repmat(instance_color, numel(points_idx_this_instance), 1); 74 | end 75 | pc_instance.Color = uint8(pc_instance_colors); 76 | 77 | % viz 78 | ptsize = 20; 79 | limsize = 150; zoomfactor = 6; 80 | 81 | figure(1); clf; 82 | pcshow(pc, 'MarkerSize', ptsize); 83 | xlim([-limsize, limsize]); ylim([-limsize, limsize]); 84 | zlim([-4, 15]); 85 | title_str = strcat("KITTI ", SEQ_IDX, ": ", num2str(target_idx)); title(title_str); 86 | grid off; 87 | zoom(zoomfactor); 88 | text(0, 10, 30, title_str); 89 | framecaptures_semantics(frame_recorded_idx) = getframe(gcf); 90 | 91 | figure(2); clf; 92 | pcshow(pc_instance, 'MarkerSize', ptsize); 93 | xlim([-limsize, limsize]); ylim([-limsize, limsize]); 94 | zlim([-4, 15]); 95 | title_str = strcat("KITTI ", SEQ_IDX, ": ", num2str(target_idx)); title(title_str); 96 | grid off; 97 | zoom(zoomfactor); 98 | text(0, 10, 30, title_str); 99 | framecaptures_instances(frame_recorded_idx) = getframe(gcf); 100 | 101 | % 102 | frame_recorded_idx = frame_recorded_idx + 1; 103 | end 104 | 105 | 106 | % a viz result writer 107 | writerObj = VideoWriter('semantickitti_viz.avi'); 108 | writerObj.FrameRate = 5; 109 | open(writerObj); 110 | for i=1:length(framecaptures_semantics) 111 | frame_semantic = framecaptures_semantics(i); 112 | frame_instance = framecaptures_instances(i); 113 | 114 | frame_semantic.cdata = [frame_semantic.cdata, frame_instance.cdata]; 115 | writeVideo(writerObj, frame_semantic); 116 | end 117 | close(writerObj); 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /visualizer/readBin.m: -------------------------------------------------------------------------------- 1 | function ptcloud = readBin(bin_path, lidar_height) 2 | 3 | %% Read 4 | fid = fopen(bin_path, 'rb'); raw_data = fread(fid, [4 inf], 'single'); fclose(fid); 5 | points = raw_data(1:3,:)'; 6 | points(:, 3) = points(:, 3) + lidar_height; % z in car coord. 7 | 8 | ptcloud = pointCloud(points); 9 | 10 | end % end of function 11 | -------------------------------------------------------------------------------- /visualizer/readLabel.m: -------------------------------------------------------------------------------- 1 | function [pc_lb, pc_id] = readLabel(file_path) 2 | 3 | %% Read 4 | fid = fopen(file_path, 'rb'); 5 | label = fread(fid, [1 inf], 'uint32'); 6 | fclose(fid); 7 | 8 | % ref: https://github.com/PRBonn/semantic-kitti-api/blob/77d6e9b2ddd8ec334bf97651ffa68a75345b2796/auxiliary/laserscan.py#L238 9 | pc_lb = bitand(label, hex2dec('ffff')); % lower 16 bit 10 | pc_id = double(bitsrl(uint32(label), 16)); % upper 16 bit 11 | 12 | end % end of function 13 | -------------------------------------------------------------------------------- /visualizer/semantickitti_label_colormap.m: -------------------------------------------------------------------------------- 1 | % 2 | LABEL_INDEXES = [0 1 10 11 13 15 16 18 20 30 31 32 40 44 48 49 50 51 52 60 70 71 72 80 81 99 252 253 254 255 256 257 258 259]; 3 | num_LABEL_INDEXES = length(LABEL_INDEXES); 4 | 5 | % 6 | LABEL_COLORMAP = [0, 0, 0; 0, 0, 255; 245, 150, 100; 245, 230, 100; 250, 80, 100; 150, 60, 30; 255, 0, 0; 180, 30, 80; ... 7 | 255, 0, 0; 30, 30, 255; 200, 40, 255; 90, 30, 150; 255, 0, 255; 255, 150, 255; 75, 0, 75; 75, 0, 175; 0, 200, 255; ... 8 | 50, 120, 255; 0, 150, 255; 170, 255, 150; 0, 175, 0; 0, 60, 135; 80, 240, 150; 150, 240, 255; 0, 0, 255; 255, 255, 50; ... 9 | 245, 150, 100; 255, 0, 0; 200, 40, 255; 30, 30, 255; 90, 30, 150; 250, 80, 100; 180, 30, 80; 255, 0, 0]; 10 | LABEL_COLORMAP_uint = uint8(LABEL_COLORMAP); 11 | LABEL_COLORMAP_float = LABEL_COLORMAP/255; --------------------------------------------------------------------------------