全新超详细!实验二来袭!2024 CSU 多媒体技术与应用实验二(详细版)

目录

软件设备

实验内容

内容1:加载多个位图文件

内容二:利用像素操作实现单色(R、G、B)、灰度图像的显示

内容三:倒立和正立

内容四:图像叠加

内容五:波纹显示

参考文章:


软件设备

Visual Studio2022

实验内容

1.向内存加载两个或多个 BMP位图文件

2.利用像素操作实现单色(R、G、B)、灰度图像的显示

3.通过操作像素实现图像的倒立和正立显示

4.实现两个图像的叠加(一张风景照 一张自己的人物照)

5.改变教材给出的波纹模拟程序中石头大小(stonesize)、石头重量(stoneweight)和显示帧频率等参数,观察模拟效果,并分析所看到现象的原因。

内容1:加载多个位图文件

  1. 首先,创建一个WIN32项目,如何创建项目?请参考这篇文章:全新超详细!2024 CSU 多媒体技术与应用实验一(详细版)-CSDN博客

  2. 接下来,我们按照教材中的步骤进行操作,首先添加全局变量,位置注释里有写,创建的代码模板中是会有的:

  3. 添加图片显示的代码,这段代码是添加在wWinMain函数中的,你也可以自己写一个函数封装这个代码,然后在wWinMain中去调用,并做好前置声明。代码的内容如下,这里是两张图片的添加:

也可以封装这两个代码,再放到wWinMain函数中:

//加载第一张图片
void loadImage1(HINSTANCE hInstance) {
    if (LoadImage(hInstance, L"image_1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE) == NULL)
    {
        MessageBox(NULL, L"加载图像错误", L"message", NULL);
    }
    else
    {
        hbmp = (HBITMAP)LoadImage(hInstance, L"image_1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    }
    GetObject(hbmp, sizeof(BITMAP), &bmp);
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bmp.bmWidth;
    bi.biHeight = bmp.bmHeight;
    bi.biPlanes = bmp.bmPlanes;
    bi.biBitCount = bmp.bmBitsPixel;
    bi.biCompression = bmp.bmType;
    bi.biSizeImage = bmp.bmWidth * bmp.bmHeight * bmp.bmBitsPixel / 8;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrImportant = 0;
    hDib = GlobalAlloc(GHND, bi.biSizeImage);
    lpbitmap = (BYTE*)GlobalLock(hDib);
}
​
void loadImage2(HINSTANCE hInstance) {
    if (LoadImage(hInstance, L"image_3.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE) == NULL)
    {
        MessageBox(NULL, L"加载图像错误", L"message", NULL);
    }
    else
    {
        hbmp2 = (HBITMAP)LoadImage(hInstance, L"image_3.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    }
    GetObject(hbmp2, sizeof(BITMAP), &bmp2);
    bi2.biSize = sizeof(BITMAPINFOHEADER);
    bi2.biWidth = bmp2.bmWidth;
    bi2.biHeight = bmp2.bmHeight;
    bi2.biPlanes = bmp2.bmPlanes;
    bi2.biBitCount = bmp2.bmBitsPixel;
    bi2.biCompression = bmp2.bmType;
    bi2.biSizeImage = bmp2.bmWidth * bmp2.bmHeight * bmp2.bmBitsPixel / 8;
    bi2.biXPelsPerMeter = 0;
    bi2.biYPelsPerMeter = 0;
    bi2.biClrImportant = 0;
    hDib2 = GlobalAlloc(GHND, bi2.biSizeImage);
    lpbitmap2 = (BYTE*)GlobalLock(hDib2);
}
  1. 重写重绘事件函数,具体代码参考如下:

    //获取位图1
    GetDIBits(hdc,
        hbmp,
        0,
        (UINT)bmp.bmHeight,
        lpbitmap,
        (BITMAPINFO*)&bi,
        DIB_RGB_COLORS);
    //获取位图2
    GetDIBits(hdc,
        hbmp2,
        0,
        (UINT)bmp2.bmHeight,
        lpbitmap2,
        (BITMAPINFO*)&bi2,
        DIB_RGB_COLORS);
    //显示单张图片
    void SetDIBits1(HDC hdc) {
        SetDIBitsToDevice(hdc,
        20,//x
        20,//y
        bi.biWidth,
        bi.biHeight,
        0,
        0,
        0,
        bi.biHeight,
        lpbitmap,
        (BITMAPINFO*)&bi,
        DIB_RGB_COLORS);
    }
    ​
    //显示单张图片2
    void SetDIBits2(HDC hdc) {
        SetDIBitsToDevice(hdc,
            300,//x
            20,//y
            bi2.biWidth,
            bi2.biHeight,
            0,
            0,
            0,
            bi2.biHeight,
            lpbitmap2,
            (BITMAPINFO*)&bi2,
            DIB_RGB_COLORS);
    }

  1. 导入素材,素材来自于老师的软件资源:

  2. 接下来直接编译运行项目,即可看到我们的两个位图文件:

    到此,内容一结束。

内容二:利用像素操作实现单色(R、G、B)、灰度图像的显示

  1. 在内容一完成的基础上,我们可以直接在重写重绘函数中的区域中添加如下代码,具体是那条注释下面的代码,注释上面那个是内容一的部分:

当然,我们也可以将这部分代码封装起来,成为一个函数,代码如下:

//单色显示
void ShowRGB(HDC hdc) {
    // RGB单色显示
    for (int i = 0; i < bi.biHeight; i++)
        for (int j = 0; j < bi.biWidth; j++) {
            BYTE r = *(lpbitmap + 2 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            BYTE g = *(lpbitmap + 1 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            BYTE b = *(lpbitmap + 0 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            SetPixel(hdc, j + 100, i + 50, RGB(r, 0, 0));
            SetPixel(hdc, j + 100 + bi.biWidth, i + 50, RGB(0, g, 0));
            SetPixel(hdc, j + 100 + bi.biWidth * 2, i + 50, RGB(0, 0, b));
        }
}
  1. 结果显示如下:

  1. 灰度图像的显示,依然是只有一段代码:

封装后的代码如下:

//灰度显示
void ShowGray(HDC hdc) {
    for (int i = 0; i < bi.biHeight; i++)
        for (int j = 0; j < bi.biWidth; j++) {
            BYTE r = *(lpbitmap + 2 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            BYTE g = *(lpbitmap + 1 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            BYTE b = *(lpbitmap + 0 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            BYTE average = (r + g + b) / 3;
            BYTE y = r * 0.299 + g * 0.58 + b * 0.114;
            SetPixel(hdc, j + 500, i + 50, RGB(g, g, g));
            SetPixel(hdc, j + 500 + bi.biWidth + 2, i + 50, RGB(average, average, average));
            SetPixel(hdc, j + 500 + bi.biWidth * 2 + 4, i + 50, RGB(y, y, y));
        }
}
  1. 灰度图像的显示结果:

内容三:倒立和正立

  1. 这一部分依然很简单,跟内容二的步骤几乎是一样的,我们直接给代码即可。

    //倒立显示
    void daoli(HDC hdc) {
        //倒立
        for (int i = 0; i < bi.biHeight; i++)
            for (int j = 0; j < bi.biWidth; j++) {
                BYTE r = *(lpbitmap + 2 + j * 4 + i * bi.biWidth * 4);
                BYTE g = *(lpbitmap + 1 + j * 4 + i * bi.biWidth * 4);
                BYTE b = *(lpbitmap + 0 + j * 4 + i * bi.biWidth * 4);
                SetPixel(hdc, j + 100, i + 50, RGB(r, g, b));
            }
    }
    ​
    //正立显示
    void zhengli(HDC hdc) {
        //正立
        for (int i = 0; i < bi.biHeight; i++)
            for (int j = 0; j < bi.biWidth; j++) {
                BYTE r = *(lpbitmap + 2 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
                BYTE g = *(lpbitmap + 1 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
                BYTE b = *(lpbitmap + 0 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
                SetPixel(hdc, j + 500, i + 50, RGB(r, g, b));
            }
    }

    只需要将这段代码放到重绘函数中即可,也就是// TODO: 在此处添加使用 hdc 的任何绘图代码...这段代码后面。

内容四:图像叠加

内容依然是跟上面的步骤一样的,很简单。直接给代码了:

//叠加显示
void diejia(HDC hdc) {
    for (int i = 0; i < bi.biHeight; i++)
        for (int j = 0; j < bi.biWidth; j++) {
            BYTE r1 = *(lpbitmap + 2 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            BYTE g1 = *(lpbitmap + 1 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            BYTE b1 = *(lpbitmap + 0 + j * 4 + (bi.biHeight - i - 1) * bi.biWidth * 4);
            //读取第二幅图像的RGB分量
            BYTE r2 = *(lpbitmap2 + 2 + j * 4 + (bi2.biHeight - i - 1) * bi2.biWidth * 4);
            BYTE g2 = *(lpbitmap2 + 1 + j * 4 + (bi2.biHeight - i - 1) * bi2.biWidth * 4);
            BYTE b2 = *(lpbitmap2 + 0 + j * 4 + (bi2.biHeight - i - 1) * bi2.biWidth * 4);
            //两幅图像的对应分量按比例叠加,a=0.5
            BYTE r = r1 / 2 + r2 / 2;
            BYTE g = g1 / 2 + g2 / 2;
            BYTE b = b1 / 2 + b2 / 2;
            //显示合成图像
            SetPixel(hdc, j + 180 + bi.biWidth * 2, i + 20, RGB(r, g, b));
        }
}

效果图如下:

内容五:波纹显示

这个有点复杂,我们重新新建了一个项目用来完成这部分内容(所有的代码均来自老师所给的软件资源或者教材中)。

  1. 新建一个WIN32项目,并导入stone.bmp的素材;

  2. 在framework.h头文件中添加内容:

  3. 在主函数中最前面添加宏定义:

  4. 定义水波纹全局变量:

  5. 对接下来需要添加的函数进行前向声明:

  6. 波能初始化,此段代码加在wWinMain函数中:

  7. 定义一个计时器(在Resource.h文件中):

  8. 设置计时器:

  1. 添加过程函数(再添加一个WM_TIMER):

    这一部分的完整代码是这样的,如果编译运行不了可以直接复制我的代码:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 分析菜单选择:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
            break;
        }
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此处添加使用 hdc 的任何绘图代码...
            //获取位图1
            GetDIBits(hdc,
                hbmp,
                0,
                (UINT)bmp.bmHeight,
                lpbitmap,
                (BITMAPINFO*)&bi,
                DIB_RGB_COLORS);
            //获取位图2
            GetDIBits(hdc,
                hbmp2,
                0,
                (UINT)bmp2.bmHeight,
                lpbitmap2,
                (BITMAPINFO*)&bi2,
                DIB_RGB_COLORS);
    ​
            //显示位图1
            SetDIBits1(hdc);
            //显示位图2
            SetDIBits2(hdc);
            //单色rgb
            ShowRGB(hdc);
            //灰度图显示
            ShowGray(hdc);
            //倒立显示
            daoli(hdc);
            //正立显示
            zhengli(hdc);
            //叠加显示
            diejia(hdc);
            //波纹模拟
            //setDiBitsStone(hdc);
    ​
            EndPaint(hWnd, &ps);
        }
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
  1. 将声明的三个函数全部添加进来:

  1. 效果如下:

到此,实验二完成了。

参考文章:

https://www.codenong.com/cs106759209/#google_vignette

更多内容可以查看:https://cds007.github.io/

有问题可在评论区交流~

实验三过两天再写,码字累了。

  • 33
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值