""" Stitching sample (advanced) =========================== Show how to use Stitcher API from python. """ # Python 2/3 compatibility from __future__ import print_function import argparse import cv2 as cv import numpy as np from opencv_stitching.stitcher import Stitcher from opencv_stitching.image_handler import ImageHandler from opencv_stitching.feature_detector import FeatureDetector from opencv_stitching.feature_matcher import FeatureMatcher from opencv_stitching.subsetter import Subsetter from opencv_stitching.camera_estimator import CameraEstimator from opencv_stitching.camera_adjuster import CameraAdjuster from opencv_stitching.camera_wave_corrector import WaveCorrector from opencv_stitching.warper import Warper from opencv_stitching.exposure_error_compensator import ExposureErrorCompensator # noqa from opencv_stitching.seam_finder import SeamFinder from opencv_stitching.blender import Blender from opencv_stitching.timelapser import Timelapser parser = argparse.ArgumentParser( prog="opencv_stitching_tool.py", description="Rotation model images stitcher" ) parser.add_argument( 'img_names', nargs='+', help="Files to stitch", type=str ) parser.add_argument( '--medium_megapix', action='store', default=ImageHandler.DEFAULT_MEDIUM_MEGAPIX, help="Resolution for image registration step. " "The default is %s Mpx" % ImageHandler.DEFAULT_MEDIUM_MEGAPIX, type=float, dest='medium_megapix' ) parser.add_argument( '--detector', action='store', default=FeatureDetector.DEFAULT_DETECTOR, help="Type of features used for images matching. " "The default is '%s'." % FeatureDetector.DEFAULT_DETECTOR, choices=FeatureDetector.DETECTOR_CHOICES.keys(), type=str, dest='detector' ) parser.add_argument( '--nfeatures', action='store', default=500, help="Type of features used for images matching. " "The default is 500.", type=int, dest='nfeatures' ) parser.add_argument( '--matcher_type', action='store', default=FeatureMatcher.DEFAULT_MATCHER, help="Matcher used for pairwise image matching. " "The default is '%s'." % FeatureMatcher.DEFAULT_MATCHER, choices=FeatureMatcher.MATCHER_CHOICES, type=str, dest='matcher_type' ) parser.add_argument( '--range_width', action='store', default=FeatureMatcher.DEFAULT_RANGE_WIDTH, help="uses range_width to limit number of images to match with.", type=int, dest='range_width' ) parser.add_argument( '--try_use_gpu', action='store', default=False, help="Try to use CUDA. The default value is no. " "All default values are for CPU mode.", type=bool, dest='try_use_gpu' ) parser.add_argument( '--match_conf', action='store', help="Confidence for feature matching step. " "The default is 0.3 for ORB and 0.65 for other feature types.", type=float, dest='match_conf' ) parser.add_argument( '--confidence_threshold', action='store', default=Subsetter.DEFAULT_CONFIDENCE_THRESHOLD, help="Threshold for two images are from the same panorama confidence. " "The default is '%s'." % Subsetter.DEFAULT_CONFIDENCE_THRESHOLD, type=float, dest='confidence_threshold' ) parser.add_argument( '--matches_graph_dot_file', action='store', default=Subsetter.DEFAULT_MATCHES_GRAPH_DOT_FILE, help="Save matches graph represented in DOT language to file.", type=str, dest='matches_graph_dot_file' ) parser.add_argument( '--estimator', action='store', default=CameraEstimator.DEFAULT_CAMERA_ESTIMATOR, help="Type of estimator used for transformation estimation. " "The default is '%s'." % CameraEstimator.DEFAULT_CAMERA_ESTIMATOR, choices=CameraEstimator.CAMERA_ESTIMATOR_CHOICES.keys(), type=str, dest='estimator' ) parser.add_argument( '--adjuster', action='store', default=CameraAdjuster.DEFAULT_CAMERA_ADJUSTER, help="Bundle adjustment cost function. " "The default is '%s'." % CameraAdjuster.DEFAULT_CAMERA_ADJUSTER, choices=CameraAdjuster.CAMERA_ADJUSTER_CHOICES.keys(), type=str, dest='adjuster' ) parser.add_argument( '--refinement_mask', action='store', default=CameraAdjuster.DEFAULT_REFINEMENT_MASK, help="Set refinement mask for bundle adjustment. It looks like 'x_xxx', " "where 'x' means refine respective parameter and '_' means don't " "refine, and has the following format:. " "The default mask is '%s'. " "If bundle adjustment doesn't support estimation of selected " "parameter then the respective flag is ignored." "" % CameraAdjuster.DEFAULT_REFINEMENT_MASK, type=str, dest='refinement_mask' ) parser.add_argument( '--wave_correct_kind', action='store', default=WaveCorrector.DEFAULT_WAVE_CORRECTION, help="Perform wave effect correction. " "The default is '%s'" % WaveCorrector.DEFAULT_WAVE_CORRECTION, choices=WaveCorrector.WAVE_CORRECT_CHOICES.keys(), type=str, dest='wave_correct_kind' ) parser.add_argument( '--warper_type', action='store', default=Warper.DEFAULT_WARP_TYPE, help="Warp surface type. The default is '%s'." % Warper.DEFAULT_WARP_TYPE, choices=Warper.WARP_TYPE_CHOICES, type=str, dest='warper_type' ) parser.add_argument( '--low_megapix', action='store', default=ImageHandler.DEFAULT_LOW_MEGAPIX, help="Resolution for seam estimation and exposure estimation step. " "The default is %s Mpx." % ImageHandler.DEFAULT_LOW_MEGAPIX, type=float, dest='low_megapix' ) parser.add_argument( '--compensator', action='store', default=ExposureErrorCompensator.DEFAULT_COMPENSATOR, help="Exposure compensation method. " "The default is '%s'." % ExposureErrorCompensator.DEFAULT_COMPENSATOR, choices=ExposureErrorCompensator.COMPENSATOR_CHOICES.keys(), type=str, dest='compensator' ) parser.add_argument( '--nr_feeds', action='store', default=ExposureErrorCompensator.DEFAULT_NR_FEEDS, help="Number of exposure compensation feed.", type=np.int32, dest='nr_feeds' ) parser.add_argument( '--block_size', action='store', default=ExposureErrorCompensator.DEFAULT_BLOCK_SIZE, help="BLock size in pixels used by the exposure compensator. " "The default is '%s'." % ExposureErrorCompensator.DEFAULT_BLOCK_SIZE, type=np.int32, dest='block_size' ) parser.add_argument( '--finder', action='store', default=SeamFinder.DEFAULT_SEAM_FINDER, help="Seam estimation method. " "The default is '%s'." % SeamFinder.DEFAULT_SEAM_FINDER, choices=SeamFinder.SEAM_FINDER_CHOICES.keys(), type=str, dest='finder' ) parser.add_argument( '--final_megapix', action='store', default=ImageHandler.DEFAULT_FINAL_MEGAPIX, help="Resolution for compositing step. Use -1 for original resolution. " "The default is %s" % ImageHandler.DEFAULT_FINAL_MEGAPIX, type=float, dest='final_megapix' ) parser.add_argument( '--blender_type', action='store', default=Blender.DEFAULT_BLENDER, help="Blending method. The default is '%s'." % Blender.DEFAULT_BLENDER, choices=Blender.BLENDER_CHOICES, type=str, dest='blender_type' ) parser.add_argument( '--blend_strength', action='store', default=Blender.DEFAULT_BLEND_STRENGTH, help="Blending strength from [0,100] range. " "The default is '%s'." % Blender.DEFAULT_BLEND_STRENGTH, type=np.int32, dest='blend_strength' ) parser.add_argument( '--timelapse', action='store', default=Timelapser.DEFAULT_TIMELAPSE, help="Output warped images separately as frames of a time lapse movie, " "with 'fixed_' prepended to input file names. " "The default is '%s'." % Timelapser.DEFAULT_TIMELAPSE, choices=Timelapser.TIMELAPSE_CHOICES, type=str, dest='timelapse' ) parser.add_argument( '--output', action='store', default='result.jpg', help="The default is 'result.jpg'", type=str, dest='output' ) __doc__ += '\n' + parser.format_help() if __name__ == '__main__': print(__doc__) args = parser.parse_args() args_dict = vars(args) # Extract In- and Output img_names = args_dict.pop("img_names") img_names = [cv.samples.findFile(img_name) for img_name in img_names] output = args_dict.pop("output") stitcher = Stitcher(**args_dict) panorama = stitcher.stitch(img_names) cv.imwrite(output, panorama) zoom_x = 600.0 / panorama.shape[1] preview = cv.resize(panorama, dsize=None, fx=zoom_x, fy=zoom_x) cv.imshow(output, preview) cv.waitKey() cv.destroyAllWindows()