zoukankan      html  css  js  c++  java
  • 音视频技术应用(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。

    <完>

  • 相关阅读:
    [LeetCode]N-Queens
    [LeetCode]Anagrams
    [LeetCode]Permutations II
    [LeetCode]Permutations
    [STL]heap和priority_queue
    [STL]deque和stack、queue
    10、小易记单词--2017网易春招
    29、剑指offer--最小的K个数
    28、剑指offer--数组中出现次数超过一半的数字
    9、涂棋盘--2017网易春招
  • 原文地址:https://www.cnblogs.com/yongdaimi/p/15564597.html
Copyright © 2011-2022 走看看