opencv_stitching_tool.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. """
  2. Stitching sample (advanced)
  3. ===========================
  4. Show how to use Stitcher API from python.
  5. """
  6. # Python 2/3 compatibility
  7. from __future__ import print_function
  8. import argparse
  9. import cv2 as cv
  10. import numpy as np
  11. from opencv_stitching.stitcher import Stitcher
  12. from opencv_stitching.image_handler import ImageHandler
  13. from opencv_stitching.feature_detector import FeatureDetector
  14. from opencv_stitching.feature_matcher import FeatureMatcher
  15. from opencv_stitching.subsetter import Subsetter
  16. from opencv_stitching.camera_estimator import CameraEstimator
  17. from opencv_stitching.camera_adjuster import CameraAdjuster
  18. from opencv_stitching.camera_wave_corrector import WaveCorrector
  19. from opencv_stitching.warper import Warper
  20. from opencv_stitching.cropper import Cropper
  21. from opencv_stitching.exposure_error_compensator import ExposureErrorCompensator # noqa
  22. from opencv_stitching.seam_finder import SeamFinder
  23. from opencv_stitching.blender import Blender
  24. from opencv_stitching.timelapser import Timelapser
  25. parser = argparse.ArgumentParser(
  26. prog="opencv_stitching_tool.py",
  27. description="Rotation model images stitcher"
  28. )
  29. parser.add_argument(
  30. 'img_names', nargs='+',
  31. help="Files to stitch", type=str
  32. )
  33. parser.add_argument(
  34. '--medium_megapix', action='store',
  35. default=ImageHandler.DEFAULT_MEDIUM_MEGAPIX,
  36. help="Resolution for image registration step. "
  37. "The default is %s Mpx" % ImageHandler.DEFAULT_MEDIUM_MEGAPIX,
  38. type=float, dest='medium_megapix'
  39. )
  40. parser.add_argument(
  41. '--detector', action='store',
  42. default=FeatureDetector.DEFAULT_DETECTOR,
  43. help="Type of features used for images matching. "
  44. "The default is '%s'." % FeatureDetector.DEFAULT_DETECTOR,
  45. choices=FeatureDetector.DETECTOR_CHOICES.keys(),
  46. type=str, dest='detector'
  47. )
  48. parser.add_argument(
  49. '--nfeatures', action='store',
  50. default=500,
  51. help="Type of features used for images matching. "
  52. "The default is 500.",
  53. type=int, dest='nfeatures'
  54. )
  55. parser.add_argument(
  56. '--matcher_type', action='store', default=FeatureMatcher.DEFAULT_MATCHER,
  57. help="Matcher used for pairwise image matching. "
  58. "The default is '%s'." % FeatureMatcher.DEFAULT_MATCHER,
  59. choices=FeatureMatcher.MATCHER_CHOICES,
  60. type=str, dest='matcher_type'
  61. )
  62. parser.add_argument(
  63. '--range_width', action='store',
  64. default=FeatureMatcher.DEFAULT_RANGE_WIDTH,
  65. help="uses range_width to limit number of images to match with.",
  66. type=int, dest='range_width'
  67. )
  68. parser.add_argument(
  69. '--try_use_gpu', action='store', default=False,
  70. help="Try to use CUDA. The default value is no. "
  71. "All default values are for CPU mode.",
  72. type=bool, dest='try_use_gpu'
  73. )
  74. parser.add_argument(
  75. '--match_conf', action='store',
  76. help="Confidence for feature matching step. "
  77. "The default is 0.3 for ORB and 0.65 for other feature types.",
  78. type=float, dest='match_conf'
  79. )
  80. parser.add_argument(
  81. '--confidence_threshold', action='store',
  82. default=Subsetter.DEFAULT_CONFIDENCE_THRESHOLD,
  83. help="Threshold for two images are from the same panorama confidence. "
  84. "The default is '%s'." % Subsetter.DEFAULT_CONFIDENCE_THRESHOLD,
  85. type=float, dest='confidence_threshold'
  86. )
  87. parser.add_argument(
  88. '--matches_graph_dot_file', action='store',
  89. default=Subsetter.DEFAULT_MATCHES_GRAPH_DOT_FILE,
  90. help="Save matches graph represented in DOT language to <file_name> file.",
  91. type=str, dest='matches_graph_dot_file'
  92. )
  93. parser.add_argument(
  94. '--estimator', action='store',
  95. default=CameraEstimator.DEFAULT_CAMERA_ESTIMATOR,
  96. help="Type of estimator used for transformation estimation. "
  97. "The default is '%s'." % CameraEstimator.DEFAULT_CAMERA_ESTIMATOR,
  98. choices=CameraEstimator.CAMERA_ESTIMATOR_CHOICES.keys(),
  99. type=str, dest='estimator'
  100. )
  101. parser.add_argument(
  102. '--adjuster', action='store',
  103. default=CameraAdjuster.DEFAULT_CAMERA_ADJUSTER,
  104. help="Bundle adjustment cost function. "
  105. "The default is '%s'." % CameraAdjuster.DEFAULT_CAMERA_ADJUSTER,
  106. choices=CameraAdjuster.CAMERA_ADJUSTER_CHOICES.keys(),
  107. type=str, dest='adjuster'
  108. )
  109. parser.add_argument(
  110. '--refinement_mask', action='store',
  111. default=CameraAdjuster.DEFAULT_REFINEMENT_MASK,
  112. help="Set refinement mask for bundle adjustment. It looks like 'x_xxx', "
  113. "where 'x' means refine respective parameter and '_' means don't "
  114. "refine, and has the following format:<fx><skew><ppx><aspect><ppy>. "
  115. "The default mask is '%s'. "
  116. "If bundle adjustment doesn't support estimation of selected "
  117. "parameter then the respective flag is ignored."
  118. "" % CameraAdjuster.DEFAULT_REFINEMENT_MASK,
  119. type=str, dest='refinement_mask'
  120. )
  121. parser.add_argument(
  122. '--wave_correct_kind', action='store',
  123. default=WaveCorrector.DEFAULT_WAVE_CORRECTION,
  124. help="Perform wave effect correction. "
  125. "The default is '%s'" % WaveCorrector.DEFAULT_WAVE_CORRECTION,
  126. choices=WaveCorrector.WAVE_CORRECT_CHOICES.keys(),
  127. type=str, dest='wave_correct_kind'
  128. )
  129. parser.add_argument(
  130. '--warper_type', action='store', default=Warper.DEFAULT_WARP_TYPE,
  131. help="Warp surface type. The default is '%s'." % Warper.DEFAULT_WARP_TYPE,
  132. choices=Warper.WARP_TYPE_CHOICES,
  133. type=str, dest='warper_type'
  134. )
  135. parser.add_argument(
  136. '--low_megapix', action='store', default=ImageHandler.DEFAULT_LOW_MEGAPIX,
  137. help="Resolution for seam estimation and exposure estimation step. "
  138. "The default is %s Mpx." % ImageHandler.DEFAULT_LOW_MEGAPIX,
  139. type=float, dest='low_megapix'
  140. )
  141. parser.add_argument(
  142. '--crop', action='store', default=Cropper.DEFAULT_CROP,
  143. help="Crop black borders around images caused by warping using the "
  144. "largest interior rectangle. "
  145. "Default is '%s'." % Cropper.DEFAULT_CROP,
  146. type=bool, dest='crop'
  147. )
  148. parser.add_argument(
  149. '--compensator', action='store',
  150. default=ExposureErrorCompensator.DEFAULT_COMPENSATOR,
  151. help="Exposure compensation method. "
  152. "The default is '%s'." % ExposureErrorCompensator.DEFAULT_COMPENSATOR,
  153. choices=ExposureErrorCompensator.COMPENSATOR_CHOICES.keys(),
  154. type=str, dest='compensator'
  155. )
  156. parser.add_argument(
  157. '--nr_feeds', action='store',
  158. default=ExposureErrorCompensator.DEFAULT_NR_FEEDS,
  159. help="Number of exposure compensation feed.",
  160. type=np.int32, dest='nr_feeds'
  161. )
  162. parser.add_argument(
  163. '--block_size', action='store',
  164. default=ExposureErrorCompensator.DEFAULT_BLOCK_SIZE,
  165. help="BLock size in pixels used by the exposure compensator. "
  166. "The default is '%s'." % ExposureErrorCompensator.DEFAULT_BLOCK_SIZE,
  167. type=np.int32, dest='block_size'
  168. )
  169. parser.add_argument(
  170. '--finder', action='store', default=SeamFinder.DEFAULT_SEAM_FINDER,
  171. help="Seam estimation method. "
  172. "The default is '%s'." % SeamFinder.DEFAULT_SEAM_FINDER,
  173. choices=SeamFinder.SEAM_FINDER_CHOICES.keys(),
  174. type=str, dest='finder'
  175. )
  176. parser.add_argument(
  177. '--final_megapix', action='store',
  178. default=ImageHandler.DEFAULT_FINAL_MEGAPIX,
  179. help="Resolution for compositing step. Use -1 for original resolution. "
  180. "The default is %s" % ImageHandler.DEFAULT_FINAL_MEGAPIX,
  181. type=float, dest='final_megapix'
  182. )
  183. parser.add_argument(
  184. '--blender_type', action='store', default=Blender.DEFAULT_BLENDER,
  185. help="Blending method. The default is '%s'." % Blender.DEFAULT_BLENDER,
  186. choices=Blender.BLENDER_CHOICES,
  187. type=str, dest='blender_type'
  188. )
  189. parser.add_argument(
  190. '--blend_strength', action='store', default=Blender.DEFAULT_BLEND_STRENGTH,
  191. help="Blending strength from [0,100] range. "
  192. "The default is '%s'." % Blender.DEFAULT_BLEND_STRENGTH,
  193. type=np.int32, dest='blend_strength'
  194. )
  195. parser.add_argument(
  196. '--timelapse', action='store', default=Timelapser.DEFAULT_TIMELAPSE,
  197. help="Output warped images separately as frames of a time lapse movie, "
  198. "with 'fixed_' prepended to input file names. "
  199. "The default is '%s'." % Timelapser.DEFAULT_TIMELAPSE,
  200. choices=Timelapser.TIMELAPSE_CHOICES,
  201. type=str, dest='timelapse'
  202. )
  203. parser.add_argument(
  204. '--output', action='store', default='result.jpg',
  205. help="The default is 'result.jpg'",
  206. type=str, dest='output'
  207. )
  208. __doc__ += '\n' + parser.format_help()
  209. if __name__ == '__main__':
  210. print(__doc__)
  211. args = parser.parse_args()
  212. args_dict = vars(args)
  213. # Extract In- and Output
  214. img_names = args_dict.pop("img_names")
  215. img_names = [cv.samples.findFile(img_name) for img_name in img_names]
  216. output = args_dict.pop("output")
  217. stitcher = Stitcher(**args_dict)
  218. panorama = stitcher.stitch(img_names)
  219. cv.imwrite(output, panorama)
  220. zoom_x = 600.0 / panorama.shape[1]
  221. preview = cv.resize(panorama, dsize=None, fx=zoom_x, fy=zoom_x)
  222. cv.imshow(output, preview)
  223. cv.waitKey()
  224. cv.destroyAllWindows()