Simple tool that overlays a transparent foreground image onto a background image.
The first two arguments are the background and foreground images respectively. Optional arguments three and four are the x and y position that determine where to overlay the foreground image relative to the background.
#include <algorithm>
#include <cassert>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <string>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
using std::cout;
using std::endl;
template <class T>
int main(
int argc,
char *argv[]) {
if (argc <= 2) {
return argc == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
}
std::string bg_fname = argv[1];
std::string fg_fname = argv[2];
int x = argc > 3 ? std::stoi(argv[3]) : 0;
int y = argc > 4 ? std::stoi(argv[4]) : 0;
int repeat = argc > 5 ? std::stoi(argv[5]) : 1;
cv::Mat
bg_img = imread(bg_fname, cv::IMREAD_UNCHANGED);
cv::Mat
fg_img = imread(fg_fname, cv::IMREAD_UNCHANGED);
throw std::runtime_error("unable to load " + bg_fname);
throw std::runtime_error("unable to load " + fg_fname);
throw std::runtime_error("incorrect background image color format");
throw std::runtime_error("foreground image without alpha channel");
throw std::runtime_error("x coordinate out of bounds");
throw std::runtime_error("y coordinate out of bounds");
int fg_x = std::max(0, -x);
int fg_y = std::max(0, -y);
int bg_x = std::max(0, x);
int bg_y = std::max(0, y);
int fg_width = std::min(
fg_img.cols - fg_x,
bg_img.cols - x);
int fg_height = std::min(
fg_img.rows - fg_y,
bg_img.rows - y);
auto start = std::chrono::high_resolution_clock::now();
for (int r = 0; r < repeat; ++r) {
fg_img.at<uint8_t[4]>(fg_y, fg_x),
bg_img.at<uint8_t[4]>(bg_y, bg_x),
fg_height, fg_width,
}
auto finish = std::chrono::high_resolution_clock::now();
long fg_pixels = 1L * fg_width * fg_height;
cv::imwrite(
"output.png",
bg_img);
}
cout << "Usage: " << cmd << " <background> <overlay> <x> <y>" << endl;
}
using namespace std::chrono_literals;
std::cout << std::fixed << std::setprecision(3);
if (duration < 1000ns) {
return std::cout << duration.count() * 1e9 << " ns";
} else if (duration < 1000us) {
return std::cout << duration.count() * 1e6 << " µs";
} else if (duration < 1000ms) {
return std::cout << duration.count() * 1e3 << " ms";
} else {
return std::cout << duration.count() * 1e0 << " s";
}
}
template <class T>
auto duration_s = std::chrono::duration_cast<float_seconds>(duration);
cout << duration_s << " = " << duration_s / double(repeat)
<< "/it = " << duration_s / double(num_pixels * repeat) << "/px"
<< endl;
}