目录
软件设备
Visual Studio2022
实验内容
1.向内存加载两个或多个 BMP位图文件
2.利用像素操作实现单色(R、G、B)、灰度图像的显示
3.通过操作像素实现图像的倒立和正立显示
4.实现两个图像的叠加(一张风景照 一张自己的人物照)
5.改变教材给出的波纹模拟程序中石头大小(stonesize)、石头重量(stoneweight)和显示帧频率等参数,观察模拟效果,并分析所看到现象的原因。
内容1:加载多个位图文件
-
首先,创建一个WIN32项目,如何创建项目?请参考这篇文章:全新超详细!2024 CSU 多媒体技术与应用实验一(详细版)-CSDN博客
-
接下来,我们按照教材中的步骤进行操作,首先添加全局变量,位置注释里有写,创建的代码模板中是会有的:
-
添加图片显示的代码,这段代码是添加在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 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); }
-
导入素材,素材来自于老师的软件资源:
-
接下来直接编译运行项目,即可看到我们的两个位图文件:
到此,内容一结束。
内容二:利用像素操作实现单色(R、G、B)、灰度图像的显示
-
在内容一完成的基础上,我们可以直接在重写重绘函数中的区域中添加如下代码,具体是那条注释下面的代码,注释上面那个是内容一的部分:
当然,我们也可以将这部分代码封装起来,成为一个函数,代码如下:
//单色显示
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));
}
}
-
结果显示如下:
-
灰度图像的显示,依然是只有一段代码:
封装后的代码如下:
//灰度显示
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));
}
}
-
灰度图像的显示结果:
内容三:倒立和正立
-
这一部分依然很简单,跟内容二的步骤几乎是一样的,我们直接给代码即可。
//倒立显示 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));
}
}
效果图如下:
内容五:波纹显示
这个有点复杂,我们重新新建了一个项目用来完成这部分内容(所有的代码均来自老师所给的软件资源或者教材中)。
-
新建一个WIN32项目,并导入stone.bmp的素材;
-
在framework.h头文件中添加内容:
-
在主函数中最前面添加宏定义:
-
定义水波纹全局变量:
-
对接下来需要添加的函数进行前向声明:
-
波能初始化,此段代码加在wWinMain函数中:
-
定义一个计时器(在Resource.h文件中):
-
设置计时器:
-
添加过程函数(再添加一个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; }
-
将声明的三个函数全部添加进来:
-
效果如下:
到此,实验二完成了。
参考文章:
https://www.codenong.com/cs106759209/#google_vignette
更多内容可以查看:https://cds007.github.io/
有问题可在评论区交流~
实验三过两天再写,码字累了。