openMVG 파이프라인에서 C++ 코드 디버깅을 위한 명령줄 인수 시뮬레이션 방법

Python 스크립트를 통해 실행되는 openMVG C++ 도구 디버그하기

openMVG의 tutorial_demo.py, SfM_SequentialPipeline.py, 또는 SfM_GlobalPipeline.py와 같은 파이썬 파이프라인을 사용할 때, 내부적으로 호출되는 C++ 바이너리(예: openMVG_main_SfMInit_ImageListing)의 동작을 디버깅해야 할 경우가 있다. 이때 파이썬 코드는 단지 외부 실행 파일을 호출할 뿐이며, 실제 로직은 컴파일된 C++ 프로그램에 포함되어 있으므로, Visual Studio에서 직접 해당 C++ 코드를 분석하고 중단점을 설정하려면 명령줄 인수를 수동으로 재현해야 한다.

디버깅 절차 개요

  1. 먼저 파이썬 스크립트를 실행하여 실제 전달되는 경로 및 인수 값을 기록한다.
  2. Visual Studio에서 openMVG.sln 솔루션을 열고, 대상 C++ 소스 파일(main_SfMInit_ImageListing.cpp)로 이동한다.
  3. main() 함수 내에서 임의의 인수 배열을 생성하여 argcargv를 대체한다.
  4. 기존의 cmd.process(argc, argv) 부분을 수정하여 시뮬레이션된 인수를 사용하도록 변경한다.

실제 예시: SfM 초기화 단계 디버깅

다음은 파이썬 코드에서 발생하는 호출 예시이다:

subprocess.Popen([
    os.path.join(OPENMVG_SFM_BIN, "openMVG_main_SfMInit_ImageListing"),
    "-i", input_dir,
    "-o", matches_dir,
    "-d", camera_file_params,
    "-c", "3"
])

이때 input_dir, matches_dir, camera_file_params 등의 실제 값은 다음과 같았다고 가정하자:

  • input_dir: E:\...\ImageDataset_SceauxCastle\images
  • matches_dir: E:\...\tutorial_out\matches
  • camera_file_params: E:/.../sensor_width_camera_database.txt

C++ 코드 내에서 인수 시뮬레이션

해당 정보를 바탕으로 main_SfMInit_ImageListing.cppmain() 함수를 아래와 같이 수정할 수 있다:

int main(int argc, char** argv) {
    // 디버그 모드 활성화 플래그
    const bool useSimulatedArgs = true;

    if (useSimulatedArgs) {
        // 프로그램 이름 및 각 옵션을 붙여서 정의 (공백 없이)
        char programName[] = "E:/path/to/openMVG_main_SfMInit_ImageListing";
        char argImage[] = "-iE:\\path\\to\\images";
        char argOutput[] = "-oE:\\path\\to\\matches";
        char argDatabase[] = "-dE:/path/to/sensor_width_camera_database.txt";
        char argCameraType[] = "-c3";

        // argv 배열 동적 생성
        char* simulatedArgv[5];
        simulatedArgv[0] = programName;
        simulatedArgv[1] = argImage;
        simulatedArgv[2] = argOutput;
        simulatedArgv[3] = argDatabase;
        simulatedArgv[4] = argCameraType;

        // argc와 argv 교체
        argc = 5;
        argv = simulatedArgv;
    }

    // 명령어 파서 설정
    using namespace openMVG;
    CmdLine cmd;
    std::string sImageDir, sOutDir, sCameraDatabasePath;
    int i_Camera_type = -1;

    cmd.add(make_option('i', sImageDir, "imageDirectory"));
    cmd.add(make_option('o', sOutDir, "outputDir"));
    cmd.add(make_option('d', sCameraDatabasePath, "cameraDatabasePath"));
    cmd.add(make_option('c', i_Camera_type, "cameraType"));

    try {
        cmd.process(argc, argv);

        // 디렉터리 존재 여부 검사
        if (!stlplus::folder_exists(sImageDir)) {
            OPENMVG_LOG_ERROR << "입력 이미지 폴더가 존재하지 않습니다: " << sImageDir;
            return EXIT_FAILURE;
        }
        if (!stlplus::folder_exists(sOutDir)) {
            stlplus::folder_create(sOutDir);
        }
        // ... 나머지 로직 수행
    }
    catch (const std::string& error) {
        std::cerr << "오류: " << error << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

중요한 주의사항

  • 옵션과 값 사이에 공백을 넣지 마라: -i path 대신 -ipath 형태로 결합해야 CmdLine 파서가 올바르게 인식한다. 그렇지 않으면 sImageDir에 공백 앞까지의 문자만 저장되어 folder_exists 체크에서 실패한다.
  • argc 값은 전달된 인수 개수에 맞게 정확히 설정해야 한다. 예제에서는 5개의 인수(programName 포함)를 전달하므로 argc = 5로 설정.
  • 디버그 후에는 반드시 원본 cmd.process(argc, argv)로 복구하거나 조건문으로 제어하여 일반 실행 환경에 영향을 주지 않도록 한다.

대안 접근법

보다 간단한 방법으로는 CmdLine 사용을 아예 제거하고, 필요한 변수들을 직접 하드코딩하는 것도 가능하다:

sImageDir = "E:/path/to/images";
sOutDir = "E:/path/to/matches";
sCameraDatabasePath = "E:/path/to/sensor_width_camera_database.txt";
i_Camera_type = 3;

이 방식은 빠른 테스트에는 유리하지만, 재사용성과 유지보수성이 떨어진다.

결론

파이썬 기반 파이프라인에서 호출되는 openMVG의 C++ 도구들은 독립적인 실행 파일로 작동하므로, 디버깅을 위해서는 실제 전달되는 인수를 재현하는 것이 핵심이다. 위의 방법을 통해 Visual Studio에서 중단점을 설정하고 변수 상태를 실시간으로 확인함으로써, 알고리즘 흐름과 오류 원인을 효과적으로 분석할 수 있다.

태그: openMVG C++ python Visual Studio 디버깅

6월 25일 19:56에 게시됨