opencv/apps/opencv_stitching_tool/opencv_stitching_tool.py
Lukas-Alexander Weber fa5c7a9e75
Merge pull request #21020 from lukasalexanderweber:squash
Created Stitching Tool based on stitching_detailed.py
2021-11-08 11:54:06 +00:00

233 lines
8.4 KiB
Python

"""
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_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(
'--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()