Skip to content

add tool for selecting best calibration images across multiple cameras #27686

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: 5.x
Choose a base branch
from

Conversation

shyama7004
Copy link
Contributor

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

@asmorkalov asmorkalov self-requested a review August 19, 2025 06:41
@asmorkalov asmorkalov self-assigned this Aug 19, 2025
@asmorkalov asmorkalov added the category: apps OpenCV builtin tools label Aug 19, 2025
@asmorkalov asmorkalov added this to the 5.0-release milestone Aug 19, 2025
@asmorkalov
Copy link
Contributor

IMHO:

  • There is no much sense to clusterize images by generic metric (weighted sum of exposure, sharpnes, angles, etc). It makes sense to clasterize images just spatially and select the best image from cluster with the best score (exposure, sharpness, detected board, etc).
  • The approach is definitely useful for mono camera calibration and we need simple way to apply it.
  • The input data may be a video. The same logic may be applied to cherry-pick best calibration frames.
  • If I got correctly, the algorithm works with each camera independently. Not all cameras may see the same pattern at a time. It means that we need to take pairs into account too.

Comment on lines +32 to +36
try:
from PIL import Image, ImageOps
_PIL_OK = True
except ImportError:
_PIL_OK = False
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pillow dependency is definitely redundant. OpenCV cv::imwrite supports exif orientation by default.

Comment on lines +126 to +136
if fix_orientation and _PIL_OK:
with Image.open(path) as im:
im = ImageOps.exif_transpose(im)
im = im.convert("L")
if max_size and max_size > 0:
w, h = im.size
scale = float(max_size) / max(w, h)
if scale < 1.0:
im = im.resize((int(w * scale), int(h * scale)), Image.LANCZOS)
return np.array(im, dtype=np.uint8)
else:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose to drop Pillow related branches. OpenCV is always there.

Comment on lines +186 to +187
if s <= 0.0:
return (0.4, 0.3, 0.2, 0.1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you use such constants? It looks wired.

return True, pts.reshape(-1, 1, 2), pts.shape[0]

def detect_pattern(
gray: np.ndarray,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findCirclesGrid takes colors into account. I would say that the function should get original image and convert it to gray on demand.

ap.add_argument("--square", type=float, default=0.0, help="Square size (meters) for Charuco/GridBoard")
ap.add_argument("--marker", type=float, default=0.0, help="Marker size (meters) for Charuco/GridBoard")
ap.add_argument("--separation", type=float, default=0.0, help="Marker separation (meters) for GridBoard")
ap.add_argument("--gridboard", type=str, help="GridBoard WxH (e.g., 7x5). Only used for --pattern aruco")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose to replace aruco to aruco_grid in --pattern, use --rows and --cols for it and remove --gridboard option.

ap.add_argument("--out", required=True, help="Output directory for YAMLs")
ap.add_argument(
"--pattern",
choices=["chessboard", "charuco", "aruco", "circulargrid"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use circles and acircles in other tools and examples.

Comment on lines +923 to +926
"--yaml-legacy",
action="store_true",
help="Prepend %%YAML:1.0 for legacy consumers",
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say it should be default behaviour without option. It works with both Python and OpenCV own FileStoreage class.

ap.add_argument("--rows", type=int, required=True, help="Pattern rows (inner corners or circle rows)")
ap.add_argument("--cols", type=int, required=True, help="Pattern cols (inner corners or circle cols)")
ap.add_argument("--aruco-dict", default="DICT_5X5_1000", help="Aruco dictionary name for aruco/charuco")
ap.add_argument("--circular-type", choices=["symmetric", "asymmetric"], default="symmetric", help="Circle grid type when using circulargrid pattern")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use circles and acircles board names in other samples. Extra parameters are not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, will work on these aspects.

@shyama7004
Copy link
Contributor Author

shyama7004 commented Aug 19, 2025

  • If I got correctly, the algorithm works with each camera independently. Not all cameras may see the same pattern at a time. It means that we need to take pairs into account too.

Yes, the current logic is per-camera. With --require-all-cams you can enforce all cameras.

@shyama7004 shyama7004 changed the title add multicam_image_selector.py script for selecting best detected images add tool for selecting best calibration images across multiple cameras Aug 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category: apps OpenCV builtin tools
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants