Coordinate Frame Unification 3D

1 개요

여러 카메라(Scene)에서 촬영한 데이터를 기준(World) 좌표계에 대한 좌표값으로 합치는 알고리즘입니다.

각 카메라마다, 월드 좌표계에 존재하는 물체의 여러 기준점들을 촬영하여 제공하면, 해당 대응점들을 가장 잘 만족시키는 카메라의 6D Pose를 추정하여 데이터를 월드 좌표계로 변환합니다.

2 알고리즘 상세 설명

좌표계 간에 대응하는 점의 쌍을 제공해 줌으로써, 한 좌표계에서 다른 좌표계로 좌표변환을 수행하는 변환행렬을 구할 수 있습니다.

수학적으로 정확한 값이 있다면 서로 다른 3개의 점만 대응 관계가 주어져도 유일한 변환행렬을 구하는 것이 가능하지만, 이 경우는 결과가 수치적으로 안정적(작은 입력 오차가 작은 출력 오차를 보장하는 것)이지 않습니다.

일반적으로 카메라 측정 오차, 부동소수점 방식에서의 값 저장 및 계산 과정에서의 오차, Viewer에서 점을 찍을 때의 오차 등이 존재하기 때문에, 3개의 점으로는 의미있는 값을 구하기 어렵습니다. 따라서 최소 4개 이상의 대응점 쌍을 제공하도록 권장하고 있습니다. 4개 이상의 점에 대해서는 수치적으로 안정적인 해를 구할 수 있으며, 위에서 언급한 오차들이 작아질수록 정밀한 해를 구할 수 있습니다.

Point Cloud 전체 영역의 크기에 상응하는 적절하게 넓은 영역에서 점을 찍을수록 좋은 값을 얻을 수 있습니다.

Left Scene World Right Scene
Left Scene World World Right Scene
Fig. 좌/우에서 중앙 대상을 바라보고 찍은 이미지를 중앙에서 찍은 카메라(위)의 이미지과 대응시켜 합쳐진 이미지(아래)를 만든 결과

3 파라미터 설정 및 사용 방법

4.알고리즘 수행 결과 취득 방법

6 예제 코드

CFL3DObject floSource0;
CFL3DObject floSource1;
CFL3DObject floWorld;

floSource0.Load(L"../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Left).ply");
floWorld.Load(L"../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Middle).ply");
floSource1.Load(L"../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Right).ply");

CCoordinateFrameUnification3D coordinateFrameUnification;

// Scene 0와 World 좌표 간 점 대응을 추가
// Add point correpondence between Scene 0 & World

CFLArray<TPoint3<float>> flaWorld0, flaScene0;

flaWorld0.Resize(4);
flaScene0.Resize(4);

flaWorld0[0] = TPoint3<float>(0.316194f, 0.089235f, -0.955000f);
flaScene0[0] = TPoint3<float>(0.048920f, 0.131229f, -0.824725f);
flaWorld0[1] = TPoint3<float>(0.328092f, 0.086743f, -0.952000f);
flaScene0[1] = TPoint3<float>(0.062442f, 0.128631f, -0.826201f);
flaWorld0[2] = TPoint3<float>(0.465690f, 0.065212f, -0.920000f);
flaScene0[2] = TPoint3<float>(0.202130f, 0.117711f, -0.854954f);
flaWorld0[3] = TPoint3<float>(0.339934f, -0.020669f, -0.646000f);
flaScene0[3] = TPoint3<float>(0.189541f, -0.046209f, -0.589000f);

coordinateFrameUnification.AddSourceObject(floSource0, flaWorld0, flaScene0);

// Scene 1과 World 좌표 간 점 대응을 추가
// Add point correpondence between Scene 1 & World
CFLArray<TPoint3<float>> flaWorld1, flaScene1;

flaWorld1.Resize(6);
flaScene1.Resize(6);

flaWorld1[0] = TPoint3<float>(-0.553926f, 0.204508f, -1.155000f);
flaScene1[0] = TPoint3<float>(0.202496f, 0.448916f, -0.853000f);
flaWorld1[1] = TPoint3<float>(-0.552240f, 0.189193f, -1.160931f);
flaScene1[1] = TPoint3<float>(0.208646f, 0.434687f, -0.859625f);
flaWorld1[2] = TPoint3<float>(-0.479978f, 0.192098f, -1.145000f);
flaScene1[2] = TPoint3<float>(0.251620f, 0.415887f, -0.796545f);
flaWorld1[3] = TPoint3<float>(-0.477483f, 0.173172f, -1.146783f);
flaScene1[3] = TPoint3<float>(0.258778f, 0.401190f, -0.810000f);
flaWorld1[4] = TPoint3<float>(-0.406276f, -0.267226f, -0.835000f);
flaScene1[4] = TPoint3<float>(0.138451f, -0.120545f, -0.677569f);
flaWorld1[5] = TPoint3<float>(-0.016503f, -0.275241f, -1.050700f);
flaScene1[5] = TPoint3<float>(0.568925f, -0.122618f, -0.588000f);

coordinateFrameUnification.AddSourceObject(floSource1, flaWorld1, flaScene1);

CFL3DObject floDst;
coordinateFrameUnification.SetDestinationObject(floDst);
coordinateFrameUnification.Execute();

CFL3DObject floSource0 = new CFL3DObject();
CFL3DObject floSource1 = new CFL3DObject();
CFL3DObject floWorld = new CFL3DObject();
CFL3DObject floDst = new CFL3DObject();

floSource0.Load("../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Left).ply");
floWorld.Load("../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Middle).ply");
floSource1.Load("../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Right).ply");

CCoordinateFrameUnification3D coordinateFrameUnification = new CCoordinateFrameUnification3D();

// Scene 0와 World 좌표 간 점 대응을 추가
// Add point correpondence between Scene 0 & World

var flaWorld0 = new List<TPoint3<float>>(4);
var flaScene0 = new List<TPoint3<float>>(4);

flaWorld0.Add(new TPoint3<float>(0.316194f, 0.089235f, -0.955000f));
flaScene0.Add(new TPoint3<float>(0.048920f, 0.131229f, -0.824725f));
flaWorld0.Add(new TPoint3<float>(0.328092f, 0.086743f, -0.952000f));
flaScene0.Add(new TPoint3<float>(0.062442f, 0.128631f, -0.826201f));
flaWorld0.Add(new TPoint3<float>(0.465690f, 0.065212f, -0.920000f));
flaScene0.Add(new TPoint3<float>(0.202130f, 0.117711f, -0.854954f));
flaWorld0.Add(new TPoint3<float>(0.339934f, -0.020669f, -0.646000f));
flaScene0.Add(new TPoint3<float>(0.189541f, -0.046209f, -0.589000f));

coordinateFrameUnification.AddSourceObject(ref floSource0, flaWorld0, flaScene0);

// Scene 1과 World 좌표 간 점 대응을 추가
// Add point correpondence between Scene 1 & World
var flaWorld1 = new List<TPoint3<float>>(6);
var flaScene1 = new List<TPoint3<float>>(6);

flaWorld1.Add(new TPoint3<float>(-0.553926f, 0.204508f, -1.155000f));
flaScene1.Add(new TPoint3<float>(0.202496f, 0.448916f, -0.853000f));
flaWorld1.Add(new TPoint3<float>(-0.552240f, 0.189193f, -1.160931f));
flaScene1.Add(new TPoint3<float>(0.208646f, 0.434687f, -0.859625f));
flaWorld1.Add(new TPoint3<float>(-0.479978f, 0.192098f, -1.145000f));
flaScene1.Add(new TPoint3<float>(0.251620f, 0.415887f, -0.796545f));
flaWorld1.Add(new TPoint3<float>(-0.477483f, 0.173172f, -1.146783f));
flaScene1.Add(new TPoint3<float>(0.258778f, 0.401190f, -0.810000f));
flaWorld1.Add(new TPoint3<float>(-0.406276f, -0.267226f, -0.835000f));
flaScene1.Add(new TPoint3<float>(0.138451f, -0.120545f, -0.677569f));
flaWorld1.Add(new TPoint3<float>(-0.016503f, -0.275241f, -1.050700f));
flaScene1.Add(new TPoint3<float>(0.568925f, -0.122618f, -0.588000f));

coordinateFrameUnification.AddSourceObject(ref floSource1, flaWorld1, flaScene1);

coordinateFrameUnification.SetDestinationObject(ref floDst);
floSource0 = CFL3DObject()
floSource1 = CFL3DObject()
floWorld = CFL3DObject()
floDst = CFL3DObject()

# 데이터 로드 // Load data
floSource0.Load("../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Left).ply")
floWorld.Load("../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Middle).ply")
floSource1.Load("../../ExampleImages/CoordinateFrameUnification3D/Office_mosaicked(Right).ply")

coordinateFrameUnification = CCoordinateFrameUnification3D()

# Scene 0와 World 좌표 간 점 대응을 추가
# Add point correpondence between Scene 0 & World
flaWorld0 = List[TPoint3[Single]](4)
flaScene0 = List[TPoint3[Single]](4)

flaWorld0.Add(TPoint3[Single](0.316194, 0.089235, -0.955000))
flaScene0.Add(TPoint3[Single](0.048920, 0.131229, -0.824725))
flaWorld0.Add(TPoint3[Single](0.328092, 0.086743, -0.952000))
flaScene0.Add(TPoint3[Single](0.062442, 0.128631, -0.826201))
flaWorld0.Add(TPoint3[Single](0.465690, 0.065212, -0.920000))
flaScene0.Add(TPoint3[Single](0.202130, 0.117711, -0.854954))
flaWorld0.Add(TPoint3[Single](0.339934, -0.020669, -0.646000))
flaScene0.Add(TPoint3[Single](0.189541, -0.046209, -0.589000))

coordinateFrameUnification.AddSourceObject(floSource0, flaWorld0, flaScene0)

# Scene 1과 World 좌표 간 점 대응을 추가
# Add point correpondence between Scene 1 & World
flaWorld1 = List[TPoint3[Single]](6)
flaScene1 = List[TPoint3[Single]](6)

flaWorld1.Add(TPoint3[Single](-0.553926, 0.204508, -1.155000))
flaScene1.Add(TPoint3[Single](0.202496, 0.448916, -0.853000))
flaWorld1.Add(TPoint3[Single](-0.552240, 0.189193, -1.160931))
flaScene1.Add(TPoint3[Single](0.208646, 0.434687, -0.859625))
flaWorld1.Add(TPoint3[Single](-0.479978, 0.192098, -1.145000))
flaScene1.Add(TPoint3[Single](0.251620, 0.415887, -0.796545))
flaWorld1.Add(TPoint3[Single](-0.477483, 0.173172, -1.146783))
flaScene1.Add(TPoint3[Single](0.258778, 0.401190, -0.810000))
flaWorld1.Add(TPoint3[Single](-0.406276, -0.267226, -0.835000))
flaScene1.Add(TPoint3[Single](0.138451, -0.120545, -0.677569))
flaWorld1.Add(TPoint3[Single](-0.016503, -0.275241, -1.050700))
flaScene1.Add(TPoint3[Single](0.568925, -0.122618, -0.588000))

coordinateFrameUnification.AddSourceObject(floSource1, flaWorld1, flaScene1)

coordinateFrameUnification.SetDestinationObject(floDst)
coordinateFrameUnification.Execute()