ChiCODE
[2] Application : Point Cloud Segmentation 본문
[형광펜]
---- : 제목----
---- : 중요한 깨달음
---- : 기억하면 좋은 꿀정보
---- : 해결되지않은 에러나 문제
---- : 문제에 대한 솔루션
- Point Cloud Segmentation
[1] Segmentation Introduction
(1) Basic
Segmentation이란, 이것은 이 object에 속하고, 다른 어떤 것은 ground plane에 속하고에 속하는 것과 같이 특정 객체와 연관짓는 것을 우리는 Segmentation이라고 한다.
우리는 장애물을 찾을 수 있기를 원한다. 하지만 어떤 물체들은 장애물이 아니다.
pcd 에 나타나지만 장애물이 아닌 객체는 도로이다. 도로가 평평하다면, 비도로 지점에서 도로 지점을 선택하는 것은 매우 간단하다.
이를 위해 우리는 RANSAC(random sample consensus) Algorithm을 사용하는 평면 분할이라는 방법을 사용할 것이다.
(2) How do we use LiDAR to detect object in environment?
LiDAR 에 들어오는 모든 내용을 녹화한다. 그리고 물체를 구별하는데에 사용할 수 있다. Neural Network를 사용하여 우리가 나눈 여러 클래스로 인식하거나 구별할 수 있다.
[2] Point Processing
[2 -1] Creating Point Processor
경로 : environment.cpp => void simpleHighway function
실수 코드]
ProcessPointClouds<pcl::PointXYZ>::Ptr pointProcessor(new ProcessPointClouds<pcl::PointXYZ>);
정정 코드]
ProcessPointClouds<pcl::PointXYZ> *pointProcessor(new ProcessPointClouds<pcl::PointXYZ>);
이유 : PointCloud의 경우 pcl::PointCloud<pcl::PointXYZ>::Ptr 과 같이 pointer를 쓰기위해 내부에 처리가 되어있지만, ProcessPointClouds는 그렇지 않기 때문이다.
[2 -2] Using PCL to segment Plane
pair로 두가지 포인트클라우드를 받게 되는데, 하나는 obstacle이고, 다른 하나는 plane road 이다.
우리는 포인트 클라우드를 SeparateCloud 함수(from processPointCloud)를 호출하여 분리할 수 있다. 우리는 이 함수를 SegmentPlane 안에서 calculated inliers와 input cloud와 함께 사용할 수 있다.
plane cloud 얻기 : inliers가 처리되는 방식은 inlier indices 내부를 살펴서 상응하는 inlier point를 plane cloud에 push 하며 adding 되게 된다.
obstacle cloud 얻기 : pcl 을 사용하여 obstacle cloud를 동작시키기 위한 한 방법으로는 extract object를 사용하는 것이다. 해당 방법은 input cloud에서 plane cloud를 빼내는 것이다.
이 후 우리는 std::pair 에 obastacle cloud 와 plane cloud를 리턴할 수 있게 되는 것이다.
[2-3] Segment Simulation PCD : 도로는 장애물로 처리하지 않으며, 이후 포인트 처리에서 제외시킨다.
inliers 의 인덱스에 해당하는 cloud값을 모두 planeCloud에 넣어주는 것으로 보아 inliers는 plane 도로를 표현해주는 것으로 판단된다.
[1] processPointClouds.cpp 에서 SeperateClouds 함수로 간다.
[2] obstCloud 와 planeCloud 를 각각 생성한다.
[3] planeCloud에 inliers와 동일한 인덱스 값에 해당하는 값을 넣어준다.
[4] extract 클래스를 사용하여, cloud에서 inliers 인덱스에 해당하는 인덱스를 빼주면 obstCloud만이 남게 된다.
[5] SegmentPlane 함수에서 SeparatedClouds가 어떻게 사용하는지 보고 이해할 수 있다.
[6] environment.cpp 에서
내 예상으로는 SegmentPlane에서 inliers를 정의하게 되는데 모든것은 seg.segment(*inliers, *coefficients); 라인에서 결정되는 것같다. 해당 라인 이전 줄에서 seg.setInputCloud(cloud); 에서 cloud를 입력받고, "largest planar component"를 Ransac 기법을 통해 coefficients 값을 고려하여, inliers의 인덱스들로 저장해주는 것으로 판단된다.
[3] RANSAC
RANSAC 의미 : 데이터에서 outliers 를 detect 하는 방법이다.
RANSAC 작동방식 : 설정한 max number of iterations 만큼 동작하고, best fit을 가진 모델을 리턴한다.
또한 매 반복마다 데이터에서 서브 샘플을 랜덤으로 추출(선은 2개의 점, 면은 3개의 점)해와서 모델을 fit 한다.(such as a line or a plane)
Then the iteration with the highest number of inliers or the lowest noise is used as the best model.
(랜덤으로 뽑아올때, 대부분을 차지하는 inliers 의 값을 가져올 확률이 높다. 해당 확률을 처리하여 최적의 모델을 찾는것)
(2D의 경우는 선, 3D의 경우는 면이 모델이 되며, 매 iteration 마다 inliers가 카운트 된다. 모델에서 특정 설정 거리 내에 있으면 inliers로 카운팅 된다. 따라서 가장 많은 수의 inliers를 가지고 있으면 best model이 된다.
(이해 : 임의로 선(면)을 긋고(모델을 그리고) 해당 선에서 설정한 거리내에 몇개의 점이 있는지 확인한다. 여기서 점은 inliers이다. 설정한 iteration만큼 반복을 하게 되며, 그 중 가장 많은 inliers를 가진 모델이 최적의 모델이다.)
여기서 설정한 거리가 distance tolerance이다.
[3 - 1] Implementing RANSAC for Lines
-
Line formula Ax + By + C = 0
-
Point (x_0,y_0)
-
Distance d = |Ax_0+By_0+C|/sqrt(A^2+B^2)
방정식 링크 : https://www.youtube.com/watch?v=bh7X3mTJF9A
[3-2] 퀴즈 수행하기
환경 : quiz => ransac2d.cpp
(1) inliers 선언
std::unordered_set<int> inliers;