본문 바로가기

프로그래밍/종합설계 딥러닝 프로젝트

Pointcloud 사과 데이터 SUNRGBD형태로 만드는법

오늘은 커스텀 데이터인 사과 데이터에서 pointcloud 추출과 SUNRGBD형태로 만드는 법에 대해서 포스팅하겠습니다.

 

목표: 아래형식으로 커스텀 데이터 만들기

RealSense로 작업하는 법을 알기만하면 Kinect V2도 거의 비슷하기 때문에 쉽게 배울수 있습니다.

 

  •  Intel realsense sdk 실행합니다.

  • export file 을 클릭하면 ply파일과 jpg파일이 생성됩니다. 이때 jpg파일은 image폴더에 저장하면 4개중에 1개를 만들었습니다. 

이제 추출한 ply파일에 대해 라벨링(정답)을 해주어야 하고 pointcloud 또한 추출해서 bin(binary)파일로 변환해야 최종적으로 모델을 학습시킬수 있습니다.

3D 라벨링을 쉽게 해주는툴로 labelCloud가 있습니다. 

https://github.com/ch-sa/labelCloud

 

GitHub - ch-sa/labelCloud: A lightweight tool for labeling 3D bounding boxes in point clouds.

A lightweight tool for labeling 3D bounding boxes in point clouds. - GitHub - ch-sa/labelCloud: A lightweight tool for labeling 3D bounding boxes in point clouds.

github.com

 

라벨링 하기

  • labelCloud tool을 사용하여 ply 파일을 불러와서 3D 직육면체로 사과를 알맞게 가두시면 됩니다.
  • 그리고 Save label을 하면 라벨링 값이 json 파일로 저장됩니다.

 

저장되는 json 형식

이 json 파일을 아래와 같이 바꿔주시면 됩니다.

 

학습할때 필요한 라벨 형식(txt)

 

저는 몇백장의 사과에 대해 이렇게 손으로 일일이 바꿀 시간이 없어서 python을 이용해 변환코드를 작성하였습니다.

Code(json -> txt)

import pandas as pd

import json 
from collections import OrderedDict 
import pprint
import os
import glob
import csv
import numpy as np
import re
import pandas as pd
import math


homePath = '/home/yolo/labels' 

folders = os.listdir(homePath) 
data_num=len(folders)

def extract(filename):
    with open(filename, 'r',) as file:
        json_data = json.load(file) 
    bbox_num=len(json_data["objects"])
    output_array = np.zeros([bbox_num,9])
    for i in range(bbox_num): 
        output_array[i][1]=np.round(json_data["objects"][i]["centroid"]["x"],6)
        output_array[i][2]=np.round(json_data["objects"][i]["centroid"]["y"],6)
        output_array[i][3]=np.round(json_data["objects"][i]["centroid"]["z"],6)
        output_array[i][4]=np.round(json_data["objects"][i]["dimensions"]["length"],6)
        output_array[i][5]=np.round(json_data["objects"][i]["dimensions"]["width"],6)
        output_array[i][6]=np.round(json_data["objects"][i]["dimensions"]["height"],6)
        output_array[i][7]=np.round(math.cos((int(json_data["objects"][i]["rotations"]["z"]) - 90) * math.pi / 180),6)
        output_array[i][8]=np.round(math.sin((int(json_data["objects"][i]["rotations"]["z"]) - 90) * math.pi / 180),6)
    
    return output_array 
           
            

          
if __name__ == "__main__":
    savePath='/home/yolo/Desktop/json' 
        
    for j in range(0,99):
        # path = savePath +'/' + '%06d' %(j+1) +'.txt'
        # filename = homePath + '/' 'apple' + str(j+1) + '.json'
        path = savePath +'/' + '%06d' %(j+1) +'.txt'
        filename = homePath + '/'  +'%06d' %(j+1) + '.json'
        a = extract(filename)
        a = a.astype(str)
        b = a
        
        '''
        for i in range(len(a)):
            a[i,1] = str(1 * float(b[i,1]))
            a[i,2] = str(1 * float(b[i,3]))
            a[i,3] = str(1 * float(b[i,2]))
        
        '''
        a[:,0] = 'mandarin'
        # a[:,7] = '0'
        # a[:,8] = '-1'
        np.savetxt(path, a , fmt = '%s'+' 1 1 2 2 '+'%s'+' '+'%s'+' '+'%s'+' '+'%s'+' '+'%s'+' '+'%s'+' '+'%s'+' '+'%s')

 

이렇게해서 label까지 4개중 2개를 만들었습니다. 

 

이제 ply파일로부터 pointcloud를 추출하여 bin파일을 만듭니다. bin파일이 바로 depth 폴더에 있는 파일 형식입니다. 저는 bin파일 형식을 python으로 직접 열어보고 조사하였고 바로 ply로 부터 변환할수 있게 이번에도 python 코드로 작성 하였습니다.

 

Code(ply -> bin)

from plyfile import PlyData, PlyElement
import numpy as np
from os import path as osp

# R = np.array([[1, 0, 0], [0, 0, -1], [0, -1, 0]])
# R_inv = np.linalg.inv(R)

# for i in range(151,152):
    # plyfile = PlyData.read('/home/yolo/Desktop/apple_kinect/apple' + str(i) + '.ply')
plyfile = PlyData.read('/home/yolo/Desktop/ply/' + '000151' + '.ply')
d = np.vstack((1 * plyfile['vertex']['x'], 1 * plyfile['vertex']['y'],  1 * plyfile['vertex']['z']))
d = np.vstack((d, plyfile['vertex']['red'] / 255.0, plyfile['vertex']['green'] / 255.0, plyfile['vertex']['blue'] / 255.0))
    # d_xyz = d[:3,:]
    # d_rgb = d[3:,:]
    # d_xyz = R @ d_xyz # inverse transform (carmare coordinate)
    # d = np.vstack((d_xyz, d_rgb))
d = d.T
d = d.astype('float32')
d.tofile('/home/yolo/Desktop/ma/' + '000151' + '.bin')

이렇게해서 depth까지 4개중 3개를 만들었습니다.

마지막 calib값은 카메라가 기운 정도인데 저는 모든 사진을 수평에 가깝게 찍었기 때문에 항등행렬로 바꿔줬고 카메라 내부 intrinsic값도 조사하여 바꿔줬습니다. 이렇게하면 모든 calib값은 동일하기 때문에 1개만 만들고 복사하여 데이터를 생성하였습니다.

 

calib 데이터 형식(윗줄:3x3 기울기 행렬, 아랫줄:3x3 카메라 intrinsic 행렬)

 

자 드디어 모든 데이터 형식 calib, depth, image, label 작업이 끝났습니다. 딥러닝은 데이터셋이 정말 너무나도 중요하기 때문에 여기까지 정말 중요한 작업을 끝냈다고 할수 있습니다.

다음 포스팅에서 이렇게 공들여 만든 데이터로 학습을 해보도록 하겠습니다. 감사합니다.