[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n\nbuild/"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8.11)\nproject(FISHEYE_STEREO)\n\nset(CMAKE_INCLUDE_CURRENT_DIR ON)\n\nfind_package(OpenCV REQUIRED)\ninclude_directories($(OpenCV_INCLUDE_DIRS))\n\nadd_executable(calibrate calibrate.cpp)\ntarget_link_libraries(calibrate ${OpenCV_LIBS} \"-lpopt\")"
  },
  {
    "path": "README.md",
    "content": "## OpenCV C++ Stereo Fisheye Calibration\n\n_**Note**_: I don't actively maintain this repository anymore. PRs are more than welcome to help improve it.\n\nThis contains a source file to calibrate a stereo system comprising of fisheye lenses. It calibrates the extrinsics and the intrinsics of the cameras without any initial guesses. If you are looking for stereo calibration with lenses which follow the pinhole model check [here](https://github.com/sourishg/stereo_calibration).\n\n### Dependencies\n\n- OpenCV\n- popt\n\n### Compilation\n\nCompile all the files using the following commands.\n\n```bash\nmkdir build && cd build\ncmake ..\nmake\n```\n\nMake sure your are in the `build` folder to run the executables.\n\n### Data\n\nSome sample calibration images are stored in the `imgs` folder.\n\n### Running calibration\n\nRun the executable with the following command\n\n```bash\n./calibrate -w [board_width] -h [board_height] -s [square_size] -n [num_imgs] -d [img_dir] -l [left_img_prefix] -r [right_img_prefix] -o [calib_file]\n```\n\nFor example if you use the images in the `imgs` folder run the following command\n\n```bash\n./calibrate -w 9 -h 6 -s 0.02423 -n 29 -d ../imgs/ -l left -r right -o cam_stereo.yml\n```\n"
  },
  {
    "path": "calibrate.cpp",
    "content": "#include <opencv2/core/core.hpp>\n#include <opencv2/calib3d/calib3d.hpp>\n#include <opencv2/highgui/highgui.hpp>\n#include <opencv2/imgproc/imgproc.hpp>\n#include <stdio.h>\n#include <iostream>\n#include \"popt_pp.h\"\n\nusing namespace std;\nusing namespace cv;\n\nvector< vector< Point3d > > object_points;\nvector< vector< Point2f > > imagePoints1, imagePoints2;\nvector< Point2f > corners1, corners2;\nvector< vector< Point2d > > left_img_points, right_img_points;\n\nMat img1, img2, gray1, gray2, spl1, spl2;\n\nvoid load_image_points(int board_width, int board_height, float square_size, int num_imgs, \n                      char* img_dir, char* leftimg_filename, char* rightimg_filename) {\n  Size board_size = Size(board_width, board_height);\n  int board_n = board_width * board_height;\n\n  for (int i = 1; i <= num_imgs; i++) {\n    char left_img[100], right_img[100];\n    sprintf(left_img, \"%s%s%d.jpg\", img_dir, leftimg_filename, i);\n    sprintf(right_img, \"%s%s%d.jpg\", img_dir, rightimg_filename, i);\n    img1 = imread(left_img, CV_LOAD_IMAGE_COLOR);\n    img2 = imread(right_img, CV_LOAD_IMAGE_COLOR);\n    cv::cvtColor(img1, gray1, CV_BGR2GRAY);\n    cv::cvtColor(img2, gray2, CV_BGR2GRAY);\n\n    bool found1 = false, found2 = false;\n\n    found1 = cv::findChessboardCorners(img1, board_size, corners1,\n  CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);\n    found2 = cv::findChessboardCorners(img2, board_size, corners2,\n  CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);\n\n    if (found1)\n    {\n      cv::cornerSubPix(gray1, corners1, cv::Size(5, 5), cv::Size(-1, -1),\n  cv::TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1));\n      cv::drawChessboardCorners(gray1, board_size, corners1, found1);\n    }\n    if (found2)\n    {\n      cv::cornerSubPix(gray2, corners2, cv::Size(5, 5), cv::Size(-1, -1),\n  cv::TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1));\n      cv::drawChessboardCorners(gray2, board_size, corners2, found2);\n    }\n\n    vector<cv::Point3d> obj;\n    for( int i = 0; i < board_height; ++i )\n      for( int j = 0; j < board_width; ++j )\n        obj.push_back(Point3d(double( (float)j * square_size ), double( (float)i * square_size ), 0));\n\n    if (found1 && found2) {\n      cout << i << \". Found corners!\" << endl;\n      imagePoints1.push_back(corners1);\n      imagePoints2.push_back(corners2);\n      object_points.push_back(obj);\n    }\n  }\n  for (int i = 0; i < imagePoints1.size(); i++) {\n    vector< Point2d > v1, v2;\n    for (int j = 0; j < imagePoints1[i].size(); j++) {\n      v1.push_back(Point2d((double)imagePoints1[i][j].x, (double)imagePoints1[i][j].y));\n      v2.push_back(Point2d((double)imagePoints2[i][j].x, (double)imagePoints2[i][j].y));\n    }\n    left_img_points.push_back(v1);\n    right_img_points.push_back(v2);\n  }\n}\n\nint main(int argc, char const *argv[])\n{\n  int board_width, board_height, num_imgs;\n  float square_size;\n  char* img_dir;\n  char* leftimg_filename;\n  char* rightimg_filename;\n  char* out_file;\n\n  static struct poptOption options[] = {\n    { \"board_width\",'w',POPT_ARG_INT,&board_width,0,\"Checkerboard width\",\"NUM\" },\n    { \"board_height\",'h',POPT_ARG_INT,&board_height,0,\"Checkerboard height\",\"NUM\" },\n    { \"square_size\",'s',POPT_ARG_FLOAT,&square_size,0,\"Checkerboard square size\",\"NUM\" },\n    { \"num_imgs\",'n',POPT_ARG_INT,&num_imgs,0,\"Number of checkerboard images\",\"NUM\" },\n    { \"img_dir\",'d',POPT_ARG_STRING,&img_dir,0,\"Directory containing images\",\"STR\" },\n    { \"leftimg_filename\",'l',POPT_ARG_STRING,&leftimg_filename,0,\"Left image prefix\",\"STR\" },\n    { \"rightimg_filename\",'r',POPT_ARG_STRING,&rightimg_filename,0,\"Right image prefix\",\"STR\" },\n    { \"out_file\",'o',POPT_ARG_STRING,&out_file,0,\"Output calibration filename (YML)\",\"STR\" },\n    POPT_AUTOHELP\n    { NULL, 0, 0, NULL, 0, NULL, NULL }\n  };\n\n  POpt popt(NULL, argc, argv, options, 0);\n  int c;\n  while((c = popt.getNextOpt()) >= 0) {}\n\n  load_image_points(board_width, board_height, square_size, num_imgs, img_dir, leftimg_filename, rightimg_filename);\n\n  printf(\"Starting Calibration\\n\");\n  cv::Matx33d K1, K2, R;\n  cv::Vec3d T;\n  cv::Vec4d D1, D2;\n  int flag = 0;\n  flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;\n  flag |= cv::fisheye::CALIB_CHECK_COND;\n  flag |= cv::fisheye::CALIB_FIX_SKEW;\n  //flag |= cv::fisheye::CALIB_FIX_K2;\n  //flag |= cv::fisheye::CALIB_FIX_K3;\n  //flag |= cv::fisheye::CALIB_FIX_K4;\n  cv::fisheye::stereoCalibrate(object_points, left_img_points, right_img_points,\n      K1, D1, K2, D2, img1.size(), R, T, flag,\n      cv::TermCriteria(3, 12, 0));\n\n  cv::FileStorage fs1(out_file, cv::FileStorage::WRITE);\n  fs1 << \"K1\" << Mat(K1);\n  fs1 << \"K2\" << Mat(K2);\n  fs1 << \"D1\" << D1;\n  fs1 << \"D2\" << D2;\n  fs1 << \"R\" << Mat(R);\n  fs1 << \"T\" << T;\n  printf(\"Done Calibration\\n\");\n\n  printf(\"Starting Rectification\\n\");\n\n  cv::Mat R1, R2, P1, P2, Q;\n  cv::fisheye::stereoRectify(K1, D1, K2, D2, img1.size(), R, T, R1, R2, P1, P2, \nQ, CV_CALIB_ZERO_DISPARITY, img1.size(), 0.0, 1.1);\n\n  fs1 << \"R1\" << R1;\n  fs1 << \"R2\" << R2;\n  fs1 << \"P1\" << P1;\n  fs1 << \"P2\" << P2;\n  fs1 << \"Q\" << Q;\n\n  printf(\"Done Rectification\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "popt_pp.h",
    "content": "#ifndef _INCLUDED_POPT_PP_H_\n#define _INCLUDED_POPT_PP_H_\n\n#include <popt.h>\n\nclass POpt{\nprotected:\n  poptContext con;\npublic:\n  // creation and deletion\n  POpt(const char *name, int argc, const char **argv,\n       const poptOption *options, int flags)\n    {con = poptGetContext(name,argc,argv,options,flags);}\n  POpt(const char *name, int argc, char **argv,\n       const poptOption *options, int flags)\n    {con = poptGetContext(name,argc,(const char **)argv,options,flags);}\n  ~POpt()\n    {poptFreeContext(con);}\n\n  // functions for processing options\n  int getNextOpt()\n    {return(poptGetNextOpt(con));}\n  void ignoreOptions()\n    {while(getNextOpt() >= 0);}\n  const char *getOptArg()\n    {return(poptGetOptArg(con));}\n  const char *strError(int error)\n    {return(poptStrerror(error));}\n  const char *badOption(int flags = POPT_BADOPTION_NOALIAS)\n    {return(poptBadOption(con,flags));}\n\n  // processing other arguments\n  const char *getArg()\n    {return(poptGetArg(con));}\n  void ignoreArgs()\n    {while(getArg());}\n};\n\n#endif\n"
  }
]