Advertisement
dan-masek

Untitled

Mar 21st, 2017
669
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.61 KB | None | 0 0
  1. #include <opencv2/opencv.hpp>
  2.  
  3. #include <boost/format.hpp>
  4.  
  5. #include <cstdint>
  6. #include <vector>
  7. // ============================================================================
  8. class stitcher
  9. {
  10. public:
  11.     virtual ~stitcher() {}
  12.  
  13.     virtual void add_slice(cv::Mat image) = 0;
  14.     virtual cv::Mat stitched_image() = 0;
  15. };
  16. // ============================================================================
  17. class simple_stitcher
  18.     : public stitcher
  19. {
  20. public:
  21.     simple_stitcher(uint32_t min_overlap_width, uint32_t vertical_tolerance);
  22.  
  23.     virtual void add_slice(cv::Mat image);
  24.     virtual cv::Mat stitched_image();
  25.  
  26. private:
  27.     void add_slice(cv::Mat const& image, cv::Point2i const& offset);
  28.     cv::Point2i find_overlap(cv::Mat const& haystack, cv::Mat const& needle) const;
  29.  
  30.     static bool slice_size_matches(cv::Mat const& source, cv::Mat const& target);
  31.  
  32. private:
  33.     uint32_t min_overlap_width_;
  34.     uint32_t vertical_tolerance_;
  35.  
  36.     std::vector<cv::Mat> slices_;
  37.     std::vector<cv::Point2i> offsets_;
  38. };
  39. // ============================================================================
  40. simple_stitcher::simple_stitcher(uint32_t min_overlap_width
  41.     , uint32_t vertical_tolerance)
  42.     : min_overlap_width_(min_overlap_width)
  43.     , vertical_tolerance_(vertical_tolerance)
  44. {
  45. }
  46. // ----------------------------------------------------------------------------
  47. void simple_stitcher::add_slice(cv::Mat image)
  48. {
  49.     if (slices_.empty()) {
  50.         add_slice(image, { 0, 0 });
  51.         return;
  52.     }
  53.  
  54.     if (!slice_size_matches(image, slices_.front())) {
  55.         throw std::runtime_error("Inconsistent slice image size.");
  56.     }
  57.  
  58.     cv::Point2i offset(find_overlap(slices_.back(), image));
  59.  
  60.     add_slice(image, offset);
  61. }
  62. // ----------------------------------------------------------------------------
  63. cv::Mat simple_stitcher::stitched_image()
  64. {
  65.     if (slices_.empty()) {
  66.         return cv::Mat();
  67.     }
  68.  
  69.     // Calculate slice origins, relative to top-left of stitched image.
  70.     std::vector<cv::Point2i> origins;
  71.     origins.push_back({ 0, 0 });
  72.     for (auto it(++offsets_.begin()); it != offsets_.end(); ++it) {
  73.         origins.push_back(origins.back() + *it);
  74.     }
  75.  
  76.     auto min_max_y_origin = std::minmax_element(origins.begin(), origins.end()
  77.         , [](cv::Point2i const& l, cv::Point2i const& r) { return l.y < r.y; });
  78.  
  79.     int32_t min_y_offset(min_max_y_origin.first->y);
  80.     int32_t max_y_offset(min_max_y_origin.second->y);
  81.  
  82.     uint32_t width(origins.back().x + slices_.back().cols);
  83.     uint32_t height(max_y_offset - min_y_offset + slices_.back().rows);
  84.  
  85.     cv::Mat result(cv::Mat(height, width, slices_.front().type()));
  86.     for (uint32_t i(0); i < slices_.size(); ++i) {
  87.         cv::Mat const& slice(slices_[i]);
  88.         slice.copyTo(result(cv::Rect(origins[i], slice.size())));
  89.     }
  90.  
  91.     return result;
  92. }
  93. // ----------------------------------------------------------------------------
  94. void simple_stitcher::add_slice(cv::Mat const& image, cv::Point2i const& offset)
  95. {
  96.     std::cout << boost::format("Adding slice #%d, size=%s, offset=%s\n")
  97.         % slices_.size() % image.size() % offset;
  98.  
  99.     slices_.push_back(image);
  100.     offsets_.push_back(offset);
  101. }
  102. // ----------------------------------------------------------------------------
  103. cv::Point2i simple_stitcher::find_overlap(cv::Mat const& haystack
  104.     , cv::Mat const& needle) const
  105. {
  106.     cv::Mat needle_roi(needle
  107.         .colRange(0, min_overlap_width_)
  108.         .rowRange(vertical_tolerance_, needle.rows - vertical_tolerance_));
  109.  
  110.     cv::Mat correlation;
  111.     cv::matchTemplate(haystack
  112.         , needle_roi
  113.         , correlation
  114.         , cv::TM_CCORR_NORMED);
  115.  
  116.     cv::Point min_point, max_point;
  117.     double min_val, max_val;
  118.     cv::minMaxLoc(correlation, &min_val, &max_val, &min_point, &max_point);
  119.  
  120.     max_point.y -= vertical_tolerance_;
  121.     return max_point;
  122. }
  123. // ----------------------------------------------------------------------------
  124. bool simple_stitcher::slice_size_matches(cv::Mat const& source, cv::Mat const& target)
  125. {
  126.     return (source.rows == target.rows)
  127.         && (source.cols == target.cols)
  128.         && (source.depth() == target.depth());
  129. }
  130. // ============================================================================
  131. int main()
  132. {
  133.     simple_stitcher s(50, 4);
  134.  
  135.     for (uint32_t i(0); i < 4; ++i) {
  136.         cv::Mat slice(cv::imread(str(boost::format("slice_%d.png") % i), 0));
  137.         s.add_slice(slice);
  138.     }
  139.  
  140.     cv::imwrite("stitched.png", s.stitched_image());
  141.  
  142.     return 0;
  143. }
  144. // ============================================================================
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement