mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
8.4 KiB
232 lines
8.4 KiB
""" |
|
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()
|
|
|