软件设备

Visual Studio2022

实验内容

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

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

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

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

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

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

  1. 首先,创建一个WIN32项目,如何创建项目?请参考这篇文章:https://blog.csdn.net/cds008/article/details/137749511?spm=1001.2014.3001.5501
  2. 接下来,我们按照教材中的步骤进行操作,首先添加全局变量,位置注释里有写,创建的代码模板中是会有的:01添加全局变量
  3. 添加图片显示的代码,这段代码是添加在wWinMain函数中的,你也可以自己写一个函数封装这个代码,然后在wWinMain中去调用,并做好前置声明。代码的内容如下,这里是两张图片的添加:02添加图片显示代码

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

02封装一层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//加载第一张图片
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. 重写重绘事件函数,具体代码参考如下:02重绘函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    //获取位图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);
    }
  2. 导入素材,素材来自于老师的软件资源:03导入素材

  3. 接下来直接编译运行项目,即可看到我们的两个位图文件:03显示两张图片

    到此,内容一结束。

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
//单色显示
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. 结果显示如下:05单色显示

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

封装后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//灰度显示
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. 灰度图像的显示结果:07灰度显示图片

内容三:倒立和正立

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //倒立显示
    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 的任何绘图代码…**这段代码后面。

内容四:图像叠加

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//叠加显示
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));
}
}

效果图如下:

10叠加显示(本人照片)

内容五:波纹显示

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

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

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

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

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

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

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

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

  8. 设置计时器:

    17设置计时器

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

    18添加过程

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    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;
    }
  10. 将声明的三个函数全部添加进来:

    19三个函数

  11. 效果如下:

    20效果

到此,实验二完成了。

参考文章:

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

更多内容可以查看:https://blog.csdn.net/cds008/article/details/137754611

有问题可在评论区交流~

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