123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- """
- 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.cropper import Cropper
- 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_name> 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:<fx><skew><ppx><aspect><ppy>. "
- "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(
- '--crop', action='store', default=Cropper.DEFAULT_CROP,
- help="Crop black borders around images caused by warping using the "
- "largest interior rectangle. "
- "Default is '%s'." % Cropper.DEFAULT_CROP,
- type=bool, dest='crop'
- )
- 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()
|