ARM NEON Compositor  master
Fast SIMD alpha overlay and blending for ARM
examples/overlay_alpha/overlay_alpha.cpp
Go to the documentation of this file.
1 
19 #include <algorithm> // std::min, max
20 #include <cassert> // assert
21 #include <chrono> // std::chrono::high_resolution_clock
22 #include <iomanip> // std::setprecision
23 #include <iostream> // std::cout
24 #include <string> // std::string, std::stoi
25 
26 #include <opencv2/imgcodecs.hpp> // cv::imread, cv::imwrite
27 #include <opencv2/imgproc.hpp> // cv::cvtColor
28 
29 #include <alpha-lib/overlay_alpha.hpp> // overlay_alpha_stride
30 
31 using std::cout;
32 using std::endl;
33 
34 // Print the usage and command line options.
35 void print_usage(const char *);
36 
37 // Print how long it took to overlay the image.
38 template <class T>
39 void print_duration(T duration, int repeat, long num_pixels);
40 
41 int main(int argc, char *argv[]) {
42  // Parse the command line arguments
43  if (argc <= 2) {
44  print_usage(argv[0]);
45  return argc == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
46  }
47  std::string bg_fname = argv[1];
48  std::string fg_fname = argv[2];
49  int x = argc > 3 ? std::stoi(argv[3]) : 0;
50  int y = argc > 4 ? std::stoi(argv[4]) : 0;
51  int repeat = argc > 5 ? std::stoi(argv[5]) : 1;
52 
53  // Load the images
54  cv::Mat bg_img = imread(bg_fname, cv::IMREAD_UNCHANGED);
55  cv::Mat fg_img = imread(fg_fname, cv::IMREAD_UNCHANGED);
56  if (bg_img.empty())
57  throw std::runtime_error("unable to load " + bg_fname);
58  if (fg_img.empty())
59  throw std::runtime_error("unable to load " + fg_fname);
60 
61  // Check that the images are in the right format
62  if (bg_img.channels() == 3)
63  cv::cvtColor(bg_img, bg_img, cv::COLOR_BGR2BGRA);
64  if (bg_img.channels() != 4)
65  throw std::runtime_error("incorrect background image color format");
66  if (fg_img.channels() != 4)
67  throw std::runtime_error("foreground image without alpha channel");
68 
69  // Check that the x and y coordinates are inside of the background image
70  if (x >= bg_img.cols)
71  throw std::runtime_error("x coordinate out of bounds");
72  if (y >= bg_img.rows)
73  throw std::runtime_error("y coordinate out of bounds");
74 
75  // Compute what parts of the background and foreground image to use
76  int fg_x = std::max(0, -x);
77  int fg_y = std::max(0, -y);
78  int bg_x = std::max(0, x);
79  int bg_y = std::max(0, y);
80  int fg_width = std::min(fg_img.cols - fg_x, bg_img.cols - x);
81  int fg_height = std::min(fg_img.rows - fg_y, bg_img.rows - y);
82 
83  // Overlay the foreground image over the background image
84  auto start = std::chrono::high_resolution_clock::now();
85  for (int r = 0; r < repeat; ++r) {
86  overlay_alpha_stride(bg_img.at<uint8_t[4]>(bg_y, bg_x), // background
87  fg_img.at<uint8_t[4]>(fg_y, fg_x), // foreground
88  bg_img.at<uint8_t[4]>(bg_y, bg_x), // output
89  bg_img.cols, // background stride
90  fg_height, fg_width, // foreground dimensions
91  fg_img.cols); // foreground stride
92  }
93  auto finish = std::chrono::high_resolution_clock::now();
94 
95  // Print how long it took
96  long fg_pixels = 1L * fg_width * fg_height;
97  print_duration(finish - start, repeat, fg_pixels);
98 
99  // Write the result to a file
100  cv::imwrite("output.png", bg_img);
101 }
102 
103 void print_usage(const char *cmd) {
104  cout << "Usage: " << cmd << " <background> <overlay> <x> <y>" << endl;
105 }
106 
107 using float_seconds = std::chrono::duration<float>;
108 std::ostream &operator<<(std::ostream &, float_seconds duration) {
109  using namespace std::chrono_literals;
110  std::cout << std::fixed << std::setprecision(3);
111  if (duration < 1000ns) {
112  return std::cout << duration.count() * 1e9 << " ns";
113  } else if (duration < 1000us) {
114  return std::cout << duration.count() * 1e6 << " µs";
115  } else if (duration < 1000ms) {
116  return std::cout << duration.count() * 1e3 << " ms";
117  } else {
118  return std::cout << duration.count() * 1e0 << " s";
119  }
120 }
121 
122 template <class T>
123 void print_duration(T duration, int repeat, long num_pixels) {
124  auto duration_s = std::chrono::duration_cast<float_seconds>(duration);
125 
126  cout << duration_s << " = " << duration_s / double(repeat)
127  << "/it = " << duration_s / double(num_pixels * repeat) << "/px"
128  << endl;
129 }
print_duration
void print_duration(T duration, int repeat, long num_pixels)
Definition: examples/overlay_alpha/overlay_alpha.cpp:123
overlay_alpha.hpp
perf_test.fg_img
fg_img
Definition: perf_test.py:113
float_seconds
std::chrono::duration< float > float_seconds
Definition: examples/overlay_alpha/overlay_alpha.cpp:107
operator<<
std::ostream & operator<<(std::ostream &, float_seconds duration)
Definition: examples/overlay_alpha/overlay_alpha.cpp:108
print_usage
void print_usage(const char *)
Definition: examples/overlay_alpha/overlay_alpha.cpp:103
main
int main(int argc, char *argv[])
Definition: examples/overlay_alpha/overlay_alpha.cpp:41
overlay_alpha_stride
void overlay_alpha_stride(const uint8_t *bg_img, const uint8_t *fg_img, uint8_t *out_img, size_t bg_full_cols, size_t fg_rows, size_t fg_cols, size_t fg_full_cols)
Overlay a smaller image with an alpha channel over a larger background image.
Definition: src/alpha-lib/src/overlay_alpha.cpp:124
perf_test.bg_img
bg_img
Definition: perf_test.py:112