OpenCV C++如何自定义位置拼接两张图片并保存为单张图片
问题解答
完全可以实现,OpenCV的ROI(感兴趣区域)机制刚好匹配自定义位置拼接图片的需求,你描述的场景实现逻辑非常清晰。
实现思路
- 先读取两张PNG原图,若需要保留PNG的透明通道,读取时需携带
cv::IMREAD_UNCHANGED参数 - 计算合成画布的尺寸:宽度取「第一张图宽度」和「第二张图X偏移值+第二张图宽度」的最大值,高度取「第一张图高度」和「第二张图Y偏移值+第二张图高度」的最大值,确保两张图都能完整显示在画布内
- 初始化和画布尺寸一致的空白底图,背景可根据需求设置为透明、白色或其他自定义颜色
- 将第一张图拷贝到画布从(0,0)坐标开始的对应ROI区域
- 将第二张图拷贝到画布从(50,50)坐标开始的对应ROI区域,若图片携带透明通道需要额外做alpha融合,避免透明区域直接覆盖画布内容
- 最后调用
cv::imwrite导出合成后的单张图片
可直接运行的示例代码
#include <opencv2/opencv.hpp> int main() { // 读取两张PNG图,保留透明通道 cv::Mat img1 = cv::imread("img1.png", cv::IMREAD_UNCHANGED); cv::Mat img2 = cv::imread("img2.png", cv::IMREAD_UNCHANGED); if (img1.empty() || img2.empty()) { printf("图片读取失败,请检查文件路径是否正确\n"); return -1; } // 计算画布尺寸 int canvas_width = std::max(img1.cols, 50 + img2.cols); int canvas_height = std::max(img1.rows, 50 + img2.rows); // 初始化四通道空白画布,默认背景全透明 cv::Mat canvas(canvas_height, canvas_width, CV_8UC4, cv::Scalar(0, 0, 0, 0)); // 拷贝第一张图到(0,0)位置 cv::Rect roi1(0, 0, img1.cols, img1.rows); img1.copyTo(canvas(roi1)); // 拷贝第二张图到(50,50)位置,兼容透明通道融合 cv::Rect roi2(50, 50, img2.cols, img2.rows); if (img2.channels() == 4) { // 带透明通道的融合逻辑 for (int y = 0; y < img2.rows; y++) { for (int x = 0; x < img2.cols; x++) { cv::Vec4b &pixel_canvas = canvas.at<cv::Vec4b>(y + 50, x + 50); cv::Vec4b &pixel_img2 = img2.at<cv::Vec4b>(y, x); double alpha = pixel_img2[3] / 255.0; // 融合RGB通道 pixel_canvas[0] = pixel_img2[0] * alpha + pixel_canvas[0] * (1 - alpha); pixel_canvas[1] = pixel_img2[1] * alpha + pixel_canvas[1] * (1 - alpha); pixel_canvas[2] = pixel_img2[2] * alpha + pixel_canvas[2] * (1 - alpha); // 更新alpha通道 pixel_canvas[3] = std::max(pixel_canvas[3], pixel_img2[3]); } } } else { // 无透明通道直接拷贝 img2.copyTo(canvas(roi2)); } // 导出合成结果 cv::imwrite("merged.png", canvas); return 0; }
注意事项
- 若不需要保留透明通道,读取图片时可以省略
cv::IMREAD_UNCHANGED参数,画布也可以改为三通道CV_8UC3 - 偏移坐标可根据需求任意调整,需要保证ROI区域不超出画布边界,否则OpenCV会直接抛出异常
- 如果需要调整单张图的尺寸再拼接,可以先调用
cv::resize处理原图,再拷贝到画布对应位置
内容的提问来源于stack exchange,提问作者curiousJorgeXX
相关产品推荐
相关产品推荐

