Photometric Stereo 3D
1 개요
한 물체를 같은 위치에서 찍은 여러 이미지와 각 이미지에서 광원의 위치를 사용하여 Albedo, Curvature, Height Map을 구하는 알고리즘입니다.
2 알고리즘 상세 설명
Photometric Stereo는 카메라의 위치와 물체의 위치를 고정하고 광원의 위치를 바꿔가며 구한 이미지를 사용하여 3D 모델을 구하는 알고리즘입니다.
- 알고리즘의 실행을 위해서 광원의 위치를 바꾼 이미지가 총 3개 이상이 필요합니다. 광원의 위치를 바꾼 이미지의 수가 많을수록 결과 모델의 정확도가 올라갑니다.
- 이미지는 찍는 과정에서 카메라의 위치와 모델의 위치가 같아야 됩니다. 모든 이미지에서의 모델의 위치가 동일해야 합니다. 이미지 간의 모델의 위치가 다른 경우 결과에 오류가 발생할 확률이 상당히 높습니다.
- 해당 알고리즘은 모델의 표면이 램버시안 반사율을 가진다고 가정합니다. 모델의 반사율이 더 높거나 낮은 경우 결과에 오류가 발생할 수 있습니다.
Photometric Stereo의 광원 위치 입력하는 방식에 여러 방식이 있습니다.
- Slant, Tilt: 광원의 위치를 2개의 각도로 받습니다. 각도를 표현하는 방식으로 Degree와 Radian이 있습니다. 광원의 거리가 1이라고 고정하고 연산을 합니다.
- X, Y, Z: 광원의 위치를 3개의 좌표를 받습니다. 모든 광원의 거리가 1이라고 예상하는 각도와는 다르게 각각 광원의 거리를 다르게 설정할 수 있습니다.
| Position(XYZ) Diagram | Slant Diagram | Tilt Diagram |
|---|---|---|
![]() |
![]() |
![]() |
Photometric Stereo는 총 3개의 출력을 가집니다.
- Albedo
- 모델의 표면 색을 표현하는 이미지 입니다. 그림자 등의 불필요한 데이터를 제거한 이미지가 나옵니다. 결과 3D 모델의 Texture에 사용됩니다.
- Curvature Image
- 모델의 높이의 2차 미분을 표현합니다. 모델 내에 급격한 높이의 변화가 확인 가능합니다. 모델 내에 균열 등의 결함을 확인하기 위하여 사용됩니다. Curvature Mode로 Mean와 Gaussian Mode를 지원합니다.
- Height Map:
- 각 픽셀의 값이 높이가 되는 실제 모델을 출력합니다. 해당 값을 사용하여 3D 모델의 생성이 가능합니다.
Photometric Stereo는 Calibration을 사용하여 광원의 위치 설정이 가능합니다.
- 구의 이미지와 입력에 사용될 모델의 이미지가 같은 광원의 위치를 가진 상태여야 됩니다. 잘못된 이미지 순서나 두 이미지 간에 다른 광원의 위치를 사용한 경우 실행에 잘못된 광원의 위치를 입력하여 오류가 발생할 확률이 높습니다.
- Calibration을 하기 위하여 구 이미지의 수와 모델의 이미지의 수가 같아야 됩니다.
- 구의 이미지가 모델의 이미지 보다 많은 경우 동작에는 오류가 없으나 모델 이미지를 추가하여 더 정확한 결과를 얻을 수 있습니다.
- 구의 이미지가 모델의 이미지 보다 적은 경우 알고리즘이 동작하지 않습니다.
- 구의 위치는, 입력 모델 이미지와 같이, 모든 이미지 내에 같은 위치에 고정되어 있어야 합니다.
| Source Image | Calibration Image | Destination Image |
|---|---|---|
![]() |
![]() |
![]() |
| Curvature Mean Mode Image | Curvature Gaussian Mode Image |
|---|---|
![]() |
![]() |
모든 Slant, Tilt / X, Y, Z 값을 직접 코드에 적어 넣는 방식보다는 CSV 파일을 CMatrix에 로드하여 이를 Photometric Stereo의 입력으로 간단한 사용이 가능합니다.
Calibration 이후 광원의 위치 재사용을 위하여 CMatrix으로 광원의 위치를 받고 CSV로 저장하여 사용이 가능합니다.
3 예제 코드
다음 코드를 사용하여 기본적인 알고리즘의 동작이 가능합니다.
// 객체 생성
CPhotometricStereo3D photometricStereo;
// 입력 이미지
CFLImage fliSourceImage;
// 입력 이미지 설정
photometricStereo.SetSourceImage(fliSourceImage);
// 출력 Height Map 이미지
CFLImage fliDestinationHeightMapImage;
// 출력 Height Map 이미지 설정
photometricStereo.SetDestinationHeightMapImage(fliDestinationHeightMapImage);
// 출력 3D Object Height Map 이미지
CFL3DObjectHeightMap floHeightMap;
// 출력 3D Object Height Map 이미지 설정
photometricStereo.SetDestinationObject(floHeightMap);
// 출력 Texture 이미지
CFLImage fliDestinationTextureImage;
// 출력 Texture 이미지 설정
photometricStereo.SetDestinationTextureImage(fliDestinationTextureImage);
// 출력 Curvature 이미지
CFLImage fliDestinationCurvatureImage;
// 출력 Curvature 이미지 설정
photometricStereo.SetCurvatureImage(fliDestinationCurvatureImage);
// Curvature Mode
CPhotometricStereo3D::ECurvatureMode eCurvatureMode = CPhotometricStereo::ECurvatureMode_Mean;
// Curvature Mode 설정
photometricStereo.SetCurvatureMode(eCurvatureMode);
// Curvature 이미지 Normalized 여부
bool bNormalized = true;
// Curvature 이미지 Normalized 여부 설정
photometricStereo.EnableCurvatureNormalization(bNormalized);
// 각 광원의 위치
CMultiVar<double> mvSlant;
CMultiVar<double> mvTilt;
CMultiVar<double> mvPositionX;
CMultiVar<double> mvPositionY;
CMultiVar<double> mvPositionZ;
// 각 광원의 위치 설정
photometricStereo.SetLightAngleRadians(mvSlant, mvTilt);
photometricStereo.SetLightAngleDegrees(mvSlant, mvTilt);
photometricStereo.SetLightPositions(mvPositionX, mvPositionY, mvPositionZ);
// Reconstruction Mode
CPhotometricStereo3D::EReconstructionMode eReconMode = CPhotometricStereo3D::EReconstructionMode_Poisson_FP32;
// Reconstruction Mode 설정
photometricStereo.SetReconstructionMode(eReconMode);
// 알고리즘 실행
photometricStereo.Execute();
// 3D Object Height Map에 Texture 설정
floHeightMap.SetTextureImage(fliDestinationTextureImage);
// 3D Object Height Map에 Texture 사용 여부
bool bApplyTexture = true;
// 3D Object Height Map에 Texture 사용 여부 설정
floHeightMap.ActivateVertexColorTexture(bApplyTexture);
다음 코드와 구의 이미지를 사용하여 광원의 위치 설정이 가능합니다.
// 객체 생성
CPhotometricStereo3D photometricStereo;
// 구 ROI
CFLCircle<double> flfCalibROI;
// 구 이미지
CFLImage fliCalibImage;
// Calibration 이미지 설정
photometricStereo.SetCalibrationImage(fliCalibImage);
// 구 ROI 설정
photometricStereo.SetCalibrationCircleROI(flfCalibROI);
// Calibration 방식
CPhotometricStereo3D::ECalibrationMode eCalibrationMode = CPhotometricStereo3D::ECalibrationMode_Angle_Radians;
// Calibration 방식 설정
photometricStereo.SetCalibrationMode(eCalibrationMode);
// Calibration 실행
photometricStereo.Calibrate();
다음 코드를 사용하여 CSV를 CMatrix에 로드하여 이를 Photometric Stereo의 입력으로 사용이 가능합니다. Calibrate 함수 사용 이후 Source 이미지를 설정하고 바로 Execute가 사용 가능합니다.
// 객체 생성
CPhotometricStereo3D photometricStereo3D;
// 광원의 위치
CMatrix<double> matPos;
// CSV 파일 위치
CFLString<wchar_t> strFilePath;
// CSV 로드
matPos.LoadCSV(strFilePath);
// CSV가 광원의 위치를 X, Y, Z로 저장하면
photometricStereo3D.SetLightPositions(matPos);
// CSV가 광원의 위치를 Slant와 Tilt로 Degree 방식으로 저장하면
photometricStereo3D.SetLightAngleDegrees(matPos);
// CSV가 광원의 위치를 Slant와 Tilt로 Radian 방식으로 저장하면
photometricStereo3D.SetLightAngleRadians(matPos);
4 추가 함수 설명
Calibration을 위한 데이터 설정 및 실행
// 객체 생성
CPhotometricStereo3D photometricStereo3D;
// Calibration 방식
CPhotometricStereo3D::ECalibrationMode eCalibrationModeSet = CPhotometricStereo3D::ECalibrationMode_Angle_Radians;
// Degree 각도 모드로 Calibration 모드 설정
eCalibrationModeSet = CPhotometricStereo3D::ECalibrationMode_Angle_Degrees;
// Radians 각도 모드로 Calibration 모드 설정
eCalibrationModeSet = CPhotometricStereo3D::ECalibrationMode_Angle_Radians;
// 위치 모드로 Calibration 모드 설정
eCalibrationModeSet = CPhotometricStereo3D::ECalibrationMode_Positions;
// Calibration 모드 설정
photometricStereo3D.SetCalibrationMode(eCalibrationModeSet);
// 설정된 Calibration 모드를 가져옵니다.
CPhotometricStereo3D::ECalibrationMode eCalibrationModeGet = photometricStereo3D.GetCalibrationMode();
// 설정된 Execution 모드를 가져옵니다.
CPhotometricStereo3D::ECalibrationMode eExecutionModeGet = photometricStereo3D.GetExecutionMode();
함수 SetCalibrationMode는 Calibration 실행 시 저장될 광원의 위치를 표시하는 방식을 설정합니다.
함수 GetCalibrationMode는 Calibration 실행 시 저장될 광원의 위치를 표시하는 방식을 가져옵니다.
함수 GetExecutionMode는 Execute 실행 시 사용될 광원의 위치를 표시하는 방식을 가져옵니다.
// 객체 생성
CPhotometricStereo3D photometricStereo3D;
// 이미지로 Calibration 이미지 설정
CFLImage fliSetCalibImage;
photometricStereo3D.SetCalibrationImage(fliSetCalibImage);
// 이미지 포인터로 Calibration 이미지 설정
CFLImage* pFliSetCalibImage = &fliSetCalibImage;
photometricStereo3D.SetCalibrationImage(pFliSetCalibImage);
// 설정된 Calibration 이미지 불러오기
CFLImage fliGetCalibImage;
fliGetCalibImage = photometricStereo3D.GetCalibrationImage();
// 구의 위치를 표시하는 ROI를 설정합니다.
CFLCircle<double> flfSetCircleROI;
photometricStereo3D.SetCalibrationCircleROI(flfSetCircleROI);
// 구의 위치를 표시하는 포인터 ROI를 설정합니다.
CFLFigure* pFlfSetCircleROI = &flfSetCircleROI;
photometricStereo3D.SetCalibrationCircleROI(pFlfSetCircleROI);
// 설정된 구의 위치를 표시하는 ROI를 가져옵니다.
CFLCircle<double> flfGetCircleROI;
photometricStereo3D.GetCalibrationCircleROI(flfGetCircleROI);
// 설정된 구의 위치를 표시하는 포인터 ROI를 가져옵니다.
CFLFigure* pFlfGetCircleROI = &flfGetCircleROI;
photometricStereo3D.GetCalibrationCircleROI(pFlfGetCircleROI);
// 입력된 이미지와 ROI를 사용하여 Calibration을 진행합니다.
photometricStereo3D.Calibrate();
함수 SetCalibrationImage는 이미지와 이미지 포인터를 입력으로 받습니다.
함수 GetCalibrationImage는 설정한 Calibration 이미지를 포인터로 가져옵니다.
함수 SetCalibrationCircleROI는 구 ROI를 설정합니다.
함수 GetCalibrationCircleROI는 설정된 구 ROI를 가져옵니다.
함수 Calibrate를 사용하면 위에 SetCalibrationImage를 사용하여 설정한 거울 구의 이미지들과 SetCalibrationCircleROI로 설정한 구의 위치를 사용하여 빛의 위치를 구하는 Calibration을 실행합니다. 두 입력 변수에 오차가 있으면 오류가 발생할 가능성이 큽니다.
SetCalibrationCircleROI에서 Circle이 아닌 다른 모양의 ROI를 입력하는 경우 오류를 반환합니다.
설정된 Calibration 이미지가 3개 미만의 Page가 있는 경우 오류를 반환합니다.
SetCalibrationImage에 사용된 이미지 들는 입력되는 모델 이미지 들과 촬영 시 광원의 위치가 같아야 합니다. 두 이미지의 Page가 섞인 경우 결과에 오류가 발생합니다.
Reconstruction Parameter 설정 및 가져오기
// 객체 생성
CPhotometricStereo3D photometricStereo3D;
// 광원의 위치를 Radian으로 입력
CMultiVar<double> mvSetAngleRadianSlant;
CMultiVar<double> mvSetAngleRadianTilt;
photometricStereo3D.SetLightAngleRadians(mvSetAngleRadianSlant, mvSetAngleRadianTilt);
// 설정된 광원의 위치를 Radian으로 받아옵니다.
CMultiVar<double> mvGetAngleRadianSlant;
CMultiVar<double> mvGetAngleRadianTilt;
photometricStereo3D.GetLightAngleRadians(mvGetAngleRadianSlant, mvGetAngleRadianTilt);
// 광원의 위치를 Degree로 입력
CMultiVar<double> mvSetAngleDegreeSlant;
CMultiVar<double> mvSetAngleDegreeTilt;
photometricStereo3D.SetLightAngleDegrees(mvSetAngleDegreeSlant, mvSetAngleDegreeTilt);
// 설정된 광원의 위치를 Degree로 받아옵니다.
CMultiVar<double> mvGetAngleDegreeSlant;
CMultiVar<double> mvGetAngleDegreeTilt;
photometricStereo3D.GetLightAngleDegrees(mvGetAngleDegreeSlant, mvGetAngleDegreeTilt);
// 광원의 위치를 Position으로 입력
CMultiVar<double> mvSetPositionX;
CMultiVar<double> mvSetPositionY;
CMultiVar<double> mvSetPositionZ;
photometricStereo3D.SetLightPositions(mvSetPositionX, mvSetPositionY, mvSetPositionZ);
// 설정된 광원의 위치를 Position으로 받아옵니다.
CMultiVar<double> mvGetPositionX;
CMultiVar<double> mvGetPositionY;
CMultiVar<double> mvGetPositionZ;
photometricStereo3D.GetLightPositions(mvGetPositionX, mvGetPositionY, mvGetPositionZ);
함수 SetLightAngleRadians는 광원의 위치를 Radian Slant와 Tilt로 설정합니다.
함수 GetLightAngleRadians는 설정된 광원의 위치를 Radian Slant와 Tilt로 받아옵니다.
함수 SetLightAngleDegrees는 광원의 위치를 Degree Slant와 Tilt로 설정합니다.
함수 GetLightAngleDegrees는 설정된 광원의 위치를 Degree Slant와 Tilt로 받아옵니다.
함수 SetLightPositions는 광원의 위치를 Position으로 설정합니다.
함수 GetLightPositions는 설정된 광원의 위치를 Position으로 가져옵니다.
위 Set 함수를 사용하면 설정한 데이터의 방식으로 Calibrate 방식이 설정됩니다. SetLightAngleRadians으로 설정을 진행한 경우 Calibration이 ECalibrationMode_Angle_Radians으로 설정됩니다.
위 Get 함수를 설정되지 않은 Calibrate 방식으로 불러오면 오류를 반환합니다. Calibration 방식이 ECalibrationMode_Angle_Radians으로 설정된 경우 GetLightAngleRadians으로 광원의 위치를 받을 수 있고 GetLightAngleDegrees으로는 오류를 반환합니다.
// 객체 생성
CPhotometricStereo3D photometricStereo3D;
// 광원의 위치를 Radian으로 입력
CMatrix<double> matSetAngleRadian;
photometricStereo3D.SetLightAngleRadians(matSetAngleRadian);
// 설정된 광원의 위치를 Radian으로 받아옵니다.
CMatrix<double> matGetAngleRadian;
photometricStereo3D.GetLightAngleRadians(matGetAngleRadian);
// 광원의 위치를 Degree로 입력
CMatrix<double> matSetAngleDegree;
photometricStereo3D.SetLightAngleDegrees(matSetAngleDegree);
// 설정된 광원의 위치를 Degree로 받아옵니다.
CMatrix<double> matGetAngleDegree;
photometricStereo3D.GetLightAngleDegrees(matGetAngleDegree);
// 광원의 위치를 Position으로 입력
CMatrix<double> matSetPosition;
photometricStereo3D.SetLightPositions(matSetPosition);
// 설정된 광원의 위치를 Position으로 받아옵니다.
CMatrix<double> matGetPosition;
photometricStereo3D.GetLightPositions(matGetPosition);
함수들은 위 결과와 같은 출력/입력을 받습니다.
Matrix의 경우 함수를 사용하여 CSV로 저장 및 불러오기가 가능합니다.
// 객체 생성
CPhotometricStereo3D photometricStereo3D;
// Photometric Stereo Reconstruction 모드 설정
CPhotometricStereo3D::EReconstructionMode eReconstructionMode = CPhotometricStereo3D::EReconstructionMode_Poisson_FP32;
// 3D 모델 재구성 방식을 RFT Floating 32로 설정합니다.
eReconstructionMode = CPhotometricStereo3D::EReconstructionMode_RFT_FP32;
// 3D 모델 재구성 방식을 RFT Floating 64로 설정합니다.
eReconstructionMode = CPhotometricStereo3D::EReconstructionMode_RFT_FP64;
// 3D 모델 재구성 방식을 FFT Floating 32로 설정합니다.
eReconstructionMode = CPhotometricStereo3D::EReconstructionMode_FFT_FP32;
// 3D 모델 재구성 방식을 FFT Floating 64로 설정합니다.
eReconstructionMode = CPhotometricStereo3D::EReconstructionMode_FFT_FP64;
// 3D 모델 재구성 방식을 Poisson Floating 32로 설정합니다.
eReconstructionMode = CPhotometricStereo3D::EReconstructionMode_Poisson_FP32;
// 3D 모델 재구성 방식을 Poisson Floating 64로 설정합니다.
eReconstructionMode = CPhotometricStereo3D::EReconstructionMode_Poisson_FP64;
// Reconstruction 모드를 설정합니다.
CPhotometricStereo3D::EReconstructionMode eSetReconstructionMode = eReconstructionMode;
photometricStereo3D.SetReconstructionMode(eSetReconstructionMode);
// 설정된 Reconstruction 모드를 가져옵니다.
CPhotometricStereo3D::EReconstructionMode eGetReconstructionMode = photometricStereo3D.GetReconstructionMode();
CPhotometricStereo3D::EReconstructionMode은 CPhotometricStereo3D의 알고리즘 Reconstruction 방식을 저장하는 데 사용됩니다.
함수 SetReconstructionMode를 사용하면 Reconstruction 방식의 설정이 가능합니다.
함수 GetReconstructionMode를 사용하면 반환되는 값이 알고리즘에 설정된 Reconstruction 방식입니다.







