{"id":19795556,"url":"https://github.com/dkogan/mrgingham","last_synced_at":"2025-05-12T00:27:43.878Z","repository":{"id":136714524,"uuid":"141649231","full_name":"dkogan/mrgingham","owner":"dkogan","description":"Chessboard corner-finder for a camera calibration system","archived":false,"fork":false,"pushed_at":"2025-03-19T17:58:30.000Z","size":303,"stargazers_count":52,"open_issues_count":0,"forks_count":13,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-31T21:52:09.753Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dkogan.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-20T01:42:02.000Z","updated_at":"2025-03-19T17:58:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"9f1d8459-b4df-495a-9c87-6a22df80392e","html_url":"https://github.com/dkogan/mrgingham","commit_stats":null,"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2Fmrgingham","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2Fmrgingham/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2Fmrgingham/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2Fmrgingham/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dkogan","download_url":"https://codeload.github.com/dkogan/mrgingham/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253655180,"owners_count":21943060,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T07:16:39.371Z","updated_at":"2025-05-12T00:27:43.854Z","avatar_url":"https://github.com/dkogan.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"* SYNOPSIS\nDetect calibration boards in observed camera images\n\n#+BEGIN_EXAMPLE\n$ mrgingham /tmp/image*.jpg\n\n# filename x y level\n/tmp/image1.jpg - -\n/tmp/image2.jpg 1385.433000 1471.719000 0\n/tmp/image2.jpg 1483.597000 1469.825000 0\n/tmp/image2.jpg 1582.086000 1467.561000 1\n...\n\n\n$ mrgingham /tmp/image.jpg |\n  vnl-filter -p x,y |\n  feedgnuplot --domain --lines --points --image /tmp/image.jpg\n\n[ image pops up with the detected grid plotted on top ]\n\n\n$ mrgingham /tmp/image.jpg |\n  vnl-filter -p x,y,level |\n  feedgnuplot --domain\n              --with 'linespoints pt 7 ps 2 palette'\n              --tuplesizeall 3 --image /tmp/image.jpg\n\n[ fancy image pops up with the detected grid plotted on top, detections\n  colored by their decimation level ]\n#+END_EXAMPLE\n\n* INSTALLATION\nAs of today (2022-02-27), mrgingham is included in the bleeding-edge versions of\nDebian and Ubuntu. So if you're running at least Debian/testing or the\nnot-yet-published Debian 12 (bookworm) or Ubuntu 22.04 (jammy), you can\nsimply\n\n#+begin_src sh\napt install mrgingham libmrgingham-dev\n#+end_src\n\nto install the standalone tool and the development library respectively. For\nolder Debian and Ubuntu distros, packages are available in the mrcal\nrepositories. Please see the [[http://mrcal.secretsauce.net/install.html][mrcal installation page.]]\n\nIf running any other distro, you should build mrgingham from source. First, make\nsure all the build-time dependencies are installed. These are listed in the\n[[https://salsa.debian.org/science-team/mrgingham/-/blob/master/debian/control][=debian/control=]] file:\n\n#+begin_example\nBuild-Depends: ...,\n libopencv-dev,\n libboost-dev,\n pkg-config,\n mawk,\n perl,\n python3-all,\n python3-all-dev,\n python3-numpy\n#+end_example\n\nOn a Debian-based distro you can:\n\n#+begin_src sh\nsudo apt install \\\n libopencv-dev   \\\n libboost-dev    \\\n pkg-config      \\\n mawk            \\\n perl            \\\n python3-all     \\\n python3-all-dev \\\n python3-numpy\n#+end_src\n\nReplace the package names with their analogues on other distros. Once the\ndependencies are installed, you\n\n#+begin_src sh\nmake\n#+end_src\n\nand then the tool can be invoked with\n\n#+begin_src sh\n./mrgingham\n#+end_src\n\n* DESCRIPTION\nBoth chessboard and a square grid of circles are supported. Chessboard are the\n/strongly/ preferred choice, since the circles cannot produce accurate results:\nwe care about the center point, which we are not directly observing. Thus with\ncloseup and oblique views, the reported circle center and the real circle center\ncould be very far away from each other. Because of this, more work was put into\nthe chessboard detector. Use that one. Really.\n\nThese are both nominally supported by OpenCV, but those implementations are slow\nand not at all robust, in my experience. The implementations here are much\nfaster and work much better. I /do/ use OpenCV here, but only for some core\nfunctionality.\n\nCurrently mrgingham looks for a /square/ grid of points, with some\nuser-requestable width. Rectangular grids are /not/ supported at this time.\n\n** Approach\nThese tools work in two passes:\n\n1. Look for \"interesting\" points in the image. The goal is to find all the\n   points we care about, in any order. It is assumed that\n\n   - there will be many outliers\n   - there will be no outliers interspersed throughout the points we do care\n     about (this isn't an unreasonable requirement: areas between chessboard\n     corners have a solid color)\n\n2. Run a geometric analysis to find a grid in this set of \"interesting\" points.\n   This will throw out the outliers and it will order the output\n\nIf we return /any/ data, that means we found a full grid. The geometric search\nis fairly anal, so if we found a full grid, it's extremely likely that it is\n\"right\".\n\nOnce again: *the current implementation of mrgingham detects only complete\nchessboards*.\n\n*** Chessboards\nThis is based on the feature detector described in this paper:\nhttps://arxiv.org/abs/1301.5491\n\nThe authors provide a simple MIT-licensed implementation here:\nhttp://www-sigproc.eng.cam.ac.uk/Main/SB476Chess\n\nThis produces an image of detector response. /This/ library then aggregates\nthese responses by looking at local neighborhoods of high responses, and\ncomputing the mean of the position of the points in each candidate neighborhood,\nweighted by the detector response.\n\nAs noted earlier, I look for a square grid, 10x10 points by default. Here that\nmeans 10x10 /internal corners/, meaning a chessboard with 11 /squares/ per side.\nTo ensure robust detections, it is recommended to make the outer squares of the\nchessboard wider than the inner squares. This would ensure that we see exactly\n10 points in a row with the expected spacing. If the outer squares have the same\nsize, the edge of the board might be picked up, and we would see 11 or 12 points\ninstead.\n\nA recommended 10x10 pattern can be printed from this file: [[chessboard.10x10.pdf]].\nAnd a recommended 14x14 pattern can be printed from this file:\n[[chessboard.14x14.pdf]]. The denser chessboard containts more data, so fewer\nobservations will be required for convergence of the calibration algorithm. But\na higher-res camera is required to reliably detect the corners. A simple tool to\ngenerate these =.pdf= files is included in the mrgingham repository. To make an\nNxM chessboard figure do =make chessboard.NxM.pdf= in the mrgingham source tree.\n=N= and =M= must be even integers. Note: today mrgingham requires that =N == M=,\nbut eventually this may be lifted, so this tool does not have this requirement.\n\n*** Circles\n*This isn't recommended, and exists for legacy compatibility only*\n\nThe circle finder does mostly what the first stage of the OpenCV circle detector\ndoes:\n\n1. Find a reasonable intensity threshold\n2. Threshold the image\n3. Find blobs\n4. Return centroid of the blobs\n\nThis is relatively slow, can get confused by uneven lighting (although CLAHE can\ntake care of that), and is inaccurate: nothing says that the centroid of a blob\ncame from the center of the circle on the calibration board.\n\n** Output representation\nThe =mrgingham= tool produces its output in a [[https://github.com/dkogan/vnlog/][vnlog]] text table. The columns are:\n\n- =filename=: path to the image on disk\n- =x=, =y=: detected pixel coordinates of the chessboard corner\n- =level=: image level used in detecting this corner. Level 0 means\n  \"full-resolution\". Level 1 means \"half-resolution\" and that the noise on this\n  detection has double the standard deviation. Level 2 means\n  \"quarter-resolution\" and so on.\n\nIf no chessboard was found in an image, a single record is output:\n\n#+begin_example\nfilename - - -\n#+end_example\n\nThe corners are output in a consistent order: starting at the top-left,\ntraversing the grid, in the horizontal direction first. Usually, the chessboard\nis observed by multiple cameras mounted at a similar orientation, so this\nconsistent order is consistent across cameras.\n\nHowever, if some cameras in the set are rotated, their observed chessboard\ncorners will not be consistent anymore: the first corner will be \"top-left\" in\npixel coordinates for both, which is at the top of the chessboard for\nrightside-up cameras, but the bottom of the chessboard for upside-down cameras.\nThis situation is resolved with the =mrgingham-rotate-corners= tool. It\npost-processes =mrgingham= output to reorder detections from rotated cameras.\nSee the manpage of that tool for more detail. Eventually the implementation\ncould be extended to be able to uniquely identify each corner, obviating the\nneed for =mrgingham-rotate-corners=, but we're not there today.\n\n** API\nThe user-facing functions live in =mrgingham.hh=. Everything is in C++, mostly\nbecause some of the underlying libraries are in C++. All functions return a\n=bool= to indicate success/failure. All functions put the destination arguments\n/first/. All functions return the output points in\n=std::vector\u003cmrgingham::PointDouble\u0026 points_out\u003e=, an ordered list of found\npoints. The inputs are one of\n\n- An image filename\n- An OpenCV matrix: =cv::Mat\u0026 image=\n- A set of detected points, that are unordered, and are a superset of the points\n  we're seeking\n\nThe prototypes:\n\n#+BEGIN_SRC C++\nnamespace mrgingham\n{\n    bool find_circle_grid_from_image_array( std::vector\u003cmrgingham::PointDouble\u003e\u0026 points_out,\n                                            const cv::Mat\u0026 image );\n\n    bool find_circle_grid_from_image_file( std::vector\u003cmrgingham::PointDouble\u003e\u0026 points_out,\n                                           const char* filename );\n\n    bool find_chessboard_from_image_array( std::vector\u003cmrgingham::PointDouble\u003e\u0026 points_out,\n                                           const cv::Mat\u0026 image,\n                                           int image_pyramid_level = -1 );\n\n    int  find_chessboard_from_image_file( std::vector\u003cmrgingham::PointDouble\u003e\u0026 points_out,\n                                          const char* filename,\n                                          int image_pyramid_level = -1 );\n\n    bool find_grid_from_points( std::vector\u003cmrgingham::PointDouble\u003e\u0026 points_out,\n                                const std::vector\u003cmrgingham::Point\u003e\u0026 points );\n};\n#+END_SRC\n\nThe arguments should be clear. The only one that needs an explanation is\n=image_pyramid_level=:\n\n- if =image_pyramid_level= is 0 then we just use the image as is.\n\n- if =image_pyramid_level= \u003e 0 then we cut down the image by a factor of 2 that\n  many times. So for example, level 3 means each dimension is cut down by a\n  factor of 2^3 = 8\n\n- if =image_pyramid_level= \u003c 0 then we try several levels, taking the first one\n  that produces results\n\n** Applications\nThere're several included applications that exercise the library. The\n=mrgingham-...= tools are distributed, and their manpages appear below. The\n=test-...= tools are internal.\n\n- =mrgingham= takes in images as globs (with some optional\n  manipulation given on the cmdline), finds the grids, and returns them on\n  stdout, as a vnlog\n\n- =mrgingham-observe-pixel-uncertainty= evaluates the distribution of corner\n  detections from repeated observations of a stationary scene\n\n- =mrgingham-rotate-corners= corrects chessboard detections produced by rotated\n  cameras by reordering the points in the detection stream\n\n- =test-find-grid-from-points= ingests a file that contains an unordered set of\n  points with outliers. It the finds the grid, and returns it on stdout\n\n- =test-dump-chessboard-corners= is a lower-level tool that just finds the\n  chessboard corner features and returns them on stdout. No geometric search is\n  done.\n\n- =test-dump-chessboard-corners= similarly is a lower-level tool that just finds\n  the blob center features and returns them on stdout. No geometric search is\n  done.\n\n** Tests\nThere's a test suite in =test/test.sh=. It checks all images in =test/data/*=,\nand reports which ones produced no data. Currently I don't ship any actual data.\nI will at some point.\n\n* MANPAGES\n** mrgingham\n#+BEGIN_EXAMPLE\nNAME\n    mrgingham - Extract chessboard corners from a set of images\n\nSYNOPSIS\n      $ mrgingham image*.jpg\n\n      # filename x y level\n      image1.jpg - -\n      image2.jpg 1385.433000 1471.719000 0\n      image2.jpg 1483.597000 1469.825000 0\n      image2.jpg 1582.086000 1467.561000 1\n      ...\n\n\n      $ mrgingham image.jpg |\n        vnl-filter -p x,y,level |\n        feedgnuplot --domain \\\n                    --with 'linespoints pt 7 ps 2 palette' \\\n                    --tuplesizeall 3 \\\n                    --image image.jpg\n\n      [ image pops up with the detected grid plotted on top, detections color-coded\n        by their decimation level ]\n\nDESCRIPTION\n    The mrgingham tool detects chessboard corners from images stored on\n    disk. The images are given on the commandline, as globs. Each glob is\n    expanded, and each image is processed, possibly in parallel if -j was\n    given.\n\n    The output is a vnlog text table (\u003chttps://www.github.com/dkogan/vnlog)\u003e\n    containing columns:\n\n    - filename: path to the image on disk\n\n    - x, y: detected pixel coordinates of the chessboard corner\n\n    - level: image level used in detecting this corner. Level 0 means\n    \"full-resolution\". Level 1 means \"half-resolution\" and that the noise on\n    this detection has double the standard deviation. Level 2 means\n    \"quarter-resolution\" and so on.\n\n    If no chessboard was found in an image, a single record is output:\n\n      filename - - -\n\n    The corners are output in a consistent order: starting at the top-left,\n    traversing the grid, in the horizontal direction first. Usually, the\n    chessboard is observed by multiple cameras mounted at a similar\n    orientation, so this consistent order is consistent across cameras.\n\n    By default we look for a CHESSBOARD, not a grid of circles or Apriltags\n    or anything else. By default we apply adaptive histogram equalization\n    (CLAHE), then blur with a radius of 1. We then use an adaptive level of\n    downsampling when looking for the chessboard. These defaults work very\n    well in practice.\n\n    For debugging, pass in --debug. This will dump the various intermediate\n    results into /tmp and it will report more stuff on the console. Most of\n    the intermediate results are self-plotting data files. Run them. For\n    debugging sequence candidates, pass in --debug-sequence x,y where 'x,y'\n    are the approximate image coordinates of the start of a given sequence\n    (corner on the edge of a chessboard. This doesn't need to be exact;\n    mrgingham will report on the nearest corner\n\n    See the mrgingham project documentation for more detail:\n\n    \u003chttps://github.com/dkogan/mrgingham/\u003e\n\nOPTIONS\n  POSITIONAL ARGUMENTS\n      imageglobs\n        Globs specifying the images to process. May be given more than once\n\n  OPTIONAL ARGUMENTS\n      --blobs\n        Finds circle centers instead of chessboard corners. Not recommended\n      --gridn N\n        Requests detections of an NxN grid of corners. If omitted, N defaults to 10\n      --noclahe\n        Controls image preprocessing. Unless given, we will apply adaptive histogram\n        equalization (CLAHE algorithm) to the images. This is EXTREMELY helpful if\n        the images aren't illuminated evenly; which applies to most real-world\n        images.\n      --blur RADIUS\n        Controls image preprocessing. Applies a gaussian blur to the image after the\n        histogram equalization. A light blurring is very helpful with CLAHE, since\n        it produces noisy images. By default we will blur with radius = 1. Set to \u003c=\n        0 to disable\n      --level LEVEL\n        Controls image preprocessing. Applies a downsampling to the image (after\n        CLAHE and --blur, if those are given). Level 0 means 'use the original\n        image'. Level \u003e 0 means downsample by 2**level. Level \u003c 0 means 'try several\n        different levels until we find one that works. This is the default.\n      --no-refine\n        Disables corner refinement. By default, the coordinates of reported corners\n        are re-detected at less-downsampled zoom levels to improve their accuracy.\n        If we do not want to do that, pass --no-refine\n      --jobs N\n        Parallelizes the processing N-ways. -j is a synonym. This is just like GNU\n        make, except you're required to explicitly specify a job count.\n      --debug\n        If given, mrgingham will dump various intermediate results into /tmp and it\n        will report more stuff on the console. The output is self-documenting\n      --debug-sequence\n        If given, we report details about sequence matching. Do this if --debug\n        reports correct-looking corners (all corners detected, no doubled-up\n        detections, no detections inside the chessboard but not on a corner)\n\n\n#+END_EXAMPLE\n\n** mrgingham-observe-pixel-uncertainty\n#+BEGIN_EXAMPLE\nNAME\n    mrgingham-observe-pixel-uncertainty - Evaluate observed point\n    distribution from stationary observations\n\nSYNOPSIS\n      $ observe-pixel-uncertainty '*.png'\n        Evaluated 49 observations\n        mean 1-sigma for independent x,y: 0.26\n\n      $ mrcal-calibrate-cameras --observed-pixel-uncertainty 0.26 .....\n      [ mrcal computes a camera calibration ]\n\nDESCRIPTION\n    mrgingham has finite precision, so repeated observations of the same\n    board will produce slightly different corner coordinates. This tool\n    takes in a set of images (assumed observing a chessboard, with both the\n    camera and board stationary). It then outputs the 1-standard-deviation\n    statistic for the distribution of detected corners. This can then be\n    passed in to mrcal: 'mrcal-calibrate-cameras\n    --observed-pixel-uncertainty ...'\n\n    The distribution of the detected corners is assumed to be gaussian, and\n    INDEPENDENT in the horizontal and vertical directions. If the x and y\n    distributions are each s, then the LENGTH of the deviation of each pixel\n    is a Rayleigh distribution with expected value s*sqrt(pi/2) ~ s*1.25\n\n    THIS TOOL PERFORMS VERY LIGHT OUTLIER REJECTION; IT IS ASSUMED THAT THE\n    SCENE IS STATIONARY\n\nOPTIONS\n  POSITIONAL ARGUMENTS\n      input                 Either 1: A glob that matches images observing a\n                            stationary calibration target. This must be a GLOB. So\n                            in the shell pass in '*.png' and NOT *.png. These are\n                            processed by 'mrgingham' and the arguments passed in\n                            with --mrgingham. Or 2: a vnlog representing corner\n                            detections from these images. This is assumed to be a\n                            file with a filename ending in .vnl, formatted like\n                            'mrgingham' output: 3 columns: filename,x,y\n\n  OPTIONAL ARGUMENTS\n      -h, --help            show this help message and exit\n      --show {geometry,histograms}\n                            Visualize something. Arguments can be: \"geometry\":\n                            show the 1-stdev ellipses of the distribution for each\n                            chessboard corner separately. \"histograms\": show the\n                            distribution of all the x- and y-deviations off the\n                            mean\n      --mrgingham MRGINGHAM\n                            If we're processing images, these are the arguments\n                            given to mrgingham. If we are reading a pre-computed\n                            file, this does nothing\n      --num-corners NUM_CORNERS\n                            How many corners to expect in each image. If this is\n                            wrong I will throw an error. Defaults to 100\n      --imagersize IMAGERSIZE IMAGERSIZE\n                            Optional imager dimensions: width and height. This is\n                            optional. If given, we use it to size the \"--show\n                            geometry\" plot\n\n\n#+END_EXAMPLE\n\n** mrgingham-rotate-corners\n#+BEGIN_EXAMPLE\nNAME\n    mrgingham-rotate-corners - Adjust mrgingham corner detections from\n    rotated cameras\n\nSYNOPSIS\n      # camera A is rightside-up\n      # camera B is mounted sideways\n      # cameras C,D are upside-down\n      mrgingham --gridn N                \\\n        'frame*-cameraA.jpg'             \\\n        'frame*-cameraB.jpg'             \\\n        'frame*-cameraC.jpg'             \\\n        'frame*-cameraD.jpg' |           \\\n      mrgingham-rotate-corners --gridn N \\\n        --90 cameraB --180 'camera[CD]'\n\nDESCRIPTION\n    The mrgingham chessboard detector finds a chessboard in an image, but it\n    has no way to know whether the detected chessboard was upside-down or\n    otherwise rotated: the chessboard itself has no detectable marking to\n    make this clear. In the usual case, the cameras as all mounted in the\n    same orientation, so they all detect the same orientation of the\n    chessboard, and there is no problem. However, if some cameras are\n    mounted sideways or upside-down, the sequence of corners will correspond\n    to different corners between the cameras with different orientations.\n    This can be addressed by this tool. This tool ingests mrgingham\n    detections, and outputs them after correcting the chessboard\n    observations produced by rotated cameras.\n\n    Each rotation option is an awk regular expression used to select images\n    from specific cameras. The regular expression is tested against the\n    image filenames. Each rotation option may be given multiple times. Any\n    files not matched by any rotation option are passed through unrotated.\n\n\n#+END_EXAMPLE\n\n* MAINTAINER\nThis is maintained by Dima Kogan \u003cdima@secretsauce.net\u003e. Please let Dima know if\nsomething is unclear/broken/missing.\n* LICENSE AND COPYRIGHT\n\nThis library is free software; you can redistribute it and/or modify it under\nthe terms of the GNU Lesser General Public License as published by the Free\nSoftware Foundation; either version 2.1 of the License, or (at your option) any\nlater version.\n\nCopyright 2017-2021 California Institute of Technology\n\nCopyright 2017-2021 Dima Kogan (=dima@secretsauce.net=)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkogan%2Fmrgingham","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdkogan%2Fmrgingham","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkogan%2Fmrgingham/lists"}