音视频技术应用(9)-合并两幅图像, 使用SDL渲染并保存

本节记录下如何合并两幅图像,并且使用SDL对其渲染,然后使用QT保存合成后的图像

两幅图像我们分别选取了一幅800*500和一幅600*300的图像,目标是把它们进行横向合并

 由上图可知,如果合并完成的话,最终图像的尺寸应该是1400 * 500

首先准备好这两幅图像

800 * 500

600 * 300

 并且将其拷贝到bin/x86目录下,然后在上一节的基础上,对已有的代码进行修改:

#include "sdlqtrgb.h"

#include <iostream>
#include <qmessagebox.h>

#include <sdl/SDL.h>

#pragma comment(lib, "SDL2.lib")

using namespace std;

static int sdl_width = 0;
static int sdl_height = 0;

static SDL_Window* sdl_window = NULL;
static SDL_Renderer* sdl_render = NULL;
static SDL_Texture* sdl_texture = NULL;

static int pixel_size = 4;                  // 材质的像素格式是ARGB8888, 占4字节
static unsigned char* rgb = NULL;

SDLQtRGB::SDLQtRGB(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    // 取得label的宽高
    sdl_width = ui.label->width();
    sdl_height = ui.label->height();

    // 1. 初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO))
    {
        cout << SDL_GetError() << endl;
        return;
    }

    // 2. 创建窗口, 这里取得label所对应的窗口句柄
    sdl_window = SDL_CreateWindowFrom((void*)ui.label->winId());
    if (!sdl_window)
    {
        cout << SDL_GetError() << endl;
        return;
    }

    // 3. 创建渲染器
    sdl_render = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_ACCELERATED);
    if (!sdl_render)
    {
        cout << SDL_GetError() << endl;
        return;
    }

    // 加载两幅图片
    QImage img1("001.png");
    QImage img2("002.png");

    if (img1.isNull() || img2.isNull())
    {
        QMessageBox::information(this, "", "open image failed");
        return;
    }
        
    // 计算合并后的图片的宽高
    int out_w = img1.width() + img2.width();
    int out_h = img1.height() > img2.height() ? img1.height() : img2.height();          // 这里img1的图片尺寸略高, 横向合并的话,取img1的高度

    sdl_width = out_w;
    sdl_height = out_h;

    // 重新更新窗口的大小
    resize(sdl_width, sdl_height);

    // 重新设置lable的位置和大小
    ui.label->move(0, 0);                                                               // 令lable 移动到(0, 0)的初始位置
    ui.label->resize(sdl_width, sdl_height);


    // 4. 根据label控件的宽高来创建材质
    sdl_texture = SDL_CreateTexture(sdl_render,
        SDL_PIXELFORMAT_ARGB8888, 
        SDL_TEXTUREACCESS_STREAMING, 
        sdl_width, sdl_height
    );
    if (!sdl_texture)
    {
        cout << SDL_GetError() << endl;
        return;
    }

    // 申请一块内存空间用于存放RGB数据
    rgb = new unsigned char[sdl_width * sdl_height * pixel_size];

    // 默认设置为透明
    memset(rgb, 0, sdl_width * sdl_height * pixel_size);


    // 合并图片
    for (int i = 0; i < sdl_height; i++)                           // 遍历以行数为基准
    {
        // 首先要取得每行的起始位置,因为是横向合并,所以每行的起始位置 = 第一幅图片的行宽 + 第二幅图片的行宽)* i
        int begin = i * sdl_width * pixel_size;

        // 先复制第一幅图片这一行的内容
        if (i < img1.height())
        {
            memcpy(rgb + begin, img1.scanLine(i), img1.width() * pixel_size);           // scanLine是QT提供的函数, 用于取得图片第几行的内容
        }

        // 准备复制第二幅图像的内容,注意这里的begin不能再从起始位置开始,因为起始位置已经复制了第一幅图片的行内容,因此要加上第一行的内容,紧跟着第一幅图片这一行的
        // 后面开始复制
        begin += img1.width() * pixel_size;

        // 再复制第二幅图片这一行的内容
        if (i < img2.height())
        {
            memcpy(rgb + begin, img2.scanLine(i), img2.width() * pixel_size);           
        }
    }

    // 将合并后的图像存储到一个新的QImage对象当中
    // 注意这里保存的图像的像素格式必须与材质中的像素格式保持一致,材质中的像素格式为ARGB8888,对应QT中的像素格式为ARGB32, 否则会出错
    QImage out(rgb, sdl_width, sdl_height, QImage::Format_ARGB32);
    out.save("out.png");

    // 每隔10ms调用一次timerEvent函数
    startTimer(10);
}


void SDLQtRGB::timerEvent(QTimerEvent* ev)
{
   
    // 5. 动态更新材质信息
    if (SDL_UpdateTexture(sdl_texture, NULL, rgb, sdl_width * pixel_size))
    {
        cout << SDL_GetError() << endl;
        return;
    }

    // 6. 清理屏幕
    if (SDL_RenderClear(sdl_render))
    {
        cout << SDL_GetError() << endl;
        return;
    }

    // 7. 复制材质到渲染器对象
    SDL_Rect rect;
    rect.x = 0;
    rect.y = 0;
    rect.w = sdl_width;
    rect.h = sdl_height;
    if (SDL_RenderCopy(sdl_render, sdl_texture, NULL, &rect))
    {
        cout << SDL_GetError() << endl;
        return;
    }

    // 8. 执行渲染操作
    SDL_RenderPresent(sdl_render);

}

运行:

 打开bin\x86目录,找到out.png图片:

右键,查看该图片属性:

可以看到合并后的图像尺寸刚好是1400*500。

<完>

posted @ 2021-11-17 00:23  夜行过客  阅读(399)  评论(0编辑  收藏  举报