本次实验课实现了对于16色图像、256色图像、24位真彩图像的读取显示,以及灰度变换功能,对于不同深度的图像结构有了进一步的了解,部分代码展示如下,便于温习巩固
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 #include "stdafx.h" BITMAPINFO* lpBitsInfo = NULL ; BOOL LoadBmpFile (char * BmpFileName) { FILE* fp; if (NULL == (fp = fopen(BmpFileName,"rb" ))) return FALSE; BITMAPFILEHEADER bf; BITMAPINFOHEADER bi; fread(&bf,14 ,1 ,fp); fread(&bi,40 ,1 ,fp); DWORD NumColors; if (bi.biClrUsed != 0 ) NumColors = bi.biClrUsed; else { switch (bi.biBitCount) { case 1 : NumColors = 2 ; break ; case 4 : NumColors = 16 ; break ; case 8 : NumColors = 256 ; break ; case 24 : NumColors = 0 ; break ; } } DWORD PalSize = NumColors * 4 ; DWORD ImgSize = (bi.biWidth * bi.biBitCount + 31 )/32 * 4 * bi.biHeight; DWORD Size = 40 + PalSize + ImgSize; if (NULL == (lpBitsInfo = (BITMAPINFO*)malloc (Size))) return FALSE; fseek(fp,14 ,SEEK_SET); fread((char *)lpBitsInfo,Size,1 ,fp); lpBitsInfo->bmiHeader.biClrUsed = NumColors; return TRUE; }void Gray () { int w = lpBitsInfo->bmiHeader.biWidth; int h = lpBitsInfo->bmiHeader.biHeight; int LineBytes = (w * lpBitsInfo->bmiHeader.biBitCount + 31 )/ 32 * 4 ; BYTE* lpBits = (BYTE*)&lpBitsInfo->bmiColors[lpBitsInfo->bmiHeader.biClrUsed]; int LineBytes_gray = (w * 8 + 31 )/ 32 * 4 ; BITMAPINFO* lpBitsInfo_gray = (BITMAPINFO*)malloc (40 + 1024 + LineBytes_gray * h); memcpy (lpBitsInfo_gray, lpBitsInfo, 40 ); lpBitsInfo_gray->bmiHeader.biBitCount = 8 ; lpBitsInfo_gray->bmiHeader.biClrUsed = 256 ; int i,j; for (i = 0 ; i < 256 ; i++) { lpBitsInfo_gray->bmiColors[i].rgbRed = i; lpBitsInfo_gray->bmiColors[i].rgbGreen = i; lpBitsInfo_gray->bmiColors[i].rgbBlue = i; lpBitsInfo_gray->bmiColors[i].rgbReserved = 0 ; } BYTE* lpBits_gray = (BYTE*)&lpBitsInfo_gray->bmiColors[256 ]; BYTE *pixel; switch (lpBitsInfo->bmiHeader.biBitCount) { case 4 : for (i = 0 ; i < h; i++) { for (j = 0 ; j < w; j++) { if (j % 2 == 1 ) { pixel = lpBits + LineBytes * (h - 1 - i) + j / 2 ; BYTE lowFourBits = *pixel & 0x0F ; int R = lpBitsInfo->bmiColors[lowFourBits].rgbRed; int G = lpBitsInfo->bmiColors[lowFourBits].rgbGreen; int B = lpBitsInfo->bmiColors[lowFourBits].rgbBlue; int avg = (R + B + G) / 3 ; pixel = lpBits_gray + LineBytes_gray * (h - 1 - i) + j; *pixel = avg; } else { pixel = lpBits + LineBytes * (h - 1 - i) + j / 2 ; BYTE highFourBits = *pixel >> 4 ; int R = lpBitsInfo->bmiColors[highFourBits].rgbRed; int G = lpBitsInfo->bmiColors[highFourBits].rgbGreen; int B = lpBitsInfo->bmiColors[highFourBits].rgbBlue; int avg = (R + B + G) / 3 ; pixel = lpBits_gray + LineBytes_gray * (h - 1 - i) + j; *pixel = avg; } } } break ; case 8 : for (i = 0 ; i < h; i++) { for (j = 0 ; j < w; j++) { pixel = lpBits + LineBytes * (h - 1 - i) + j; int R = lpBitsInfo->bmiColors[*pixel].rgbRed; int G = lpBitsInfo->bmiColors[*pixel].rgbGreen; int B = lpBitsInfo->bmiColors[*pixel].rgbBlue; int avg = (R + B + G) / 3 ; pixel = lpBits_gray + LineBytes_gray * (h - 1 - i) + j; *pixel = avg; } } break ; case 24 : for (i = 0 ; i < h; i++) { for (j = 0 ; j < w; j++) { BYTE *B = lpBits + LineBytes * (h - 1 - i) + j * 3 ; BYTE *G = B + 1 ; BYTE *R = G + 1 ; int avg = (*R + *B + *G)/3 ; pixel = lpBits_gray + LineBytes_gray * (h - 1 - i) + j; *pixel = avg; } } break ; } free (lpBitsInfo); lpBitsInfo = lpBitsInfo_gray; }
画程序的流程图或N-S图
使用在线工具:https://mermaid.nodejs.cn/intro/
graph TD
A[开始] --> B[打开位图文件]
B --> C{文件打开成功?}
C -- 是 --> D[读取位图文件头]
D --> E[读取位图信息头]
E --> F[确定颜色数量]
F --> G[计算调色板大小]
G --> H[计算图像大小]
H --> I[分配内存]
I --> J[读取位图信息]
J --> K[设置位图信息头中的颜色使用量]
K --> L[结束]
C -- 否 --> M[返回FALSE]
graph TD
A[开始] --> B[获取位图宽度和高度]
B --> C[计算每行字节数]
C --> D[定位到像素数据]
D --> E[计算灰度图像每行字节数]
E --> F[分配灰度图像内存]
F --> G[复制位图信息头]
G --> H[设置灰度图像位深度]
H --> I[设置灰度图像颜色表大小]
I --> J[初始化灰度图像颜色表]
J --> K[定位到灰度图像像素数据]
K --> L{根据位图位深度处理每个像素}
L -->|4位图像| M[处理每个像素的高低4位]
M --> N[计算灰度值并存储]
L -->|8位图像| O[直接处理每个像素]
O --> P[计算灰度值并存储]
L -->|24位图像| Q[处理每个像素的RGB值]
Q --> R[计算灰度值并存储]
N --> S[释放原始位图内存]
P --> S
R --> S
S --> T[更新位图信息指针]
T --> U[结束]
graph TD
A[开始] --> B{位图信息为空?}
B -- 是 --> C[返回]
B -- 否 --> D[获取位图宽度和高度]
D --> E[计算每行字节数]
E --> F[定位到像素数据]
F --> G{坐标超出边界?}
G -- 是 --> H[返回]
G -- 否 --> I{根据位图位深度获取像素值}
I -->|1位图像| J{是前景点?}
J -- 是 --> K[前景点]
J -- 否 --> L[背景点]
I -->|4位图像| M{处理每个像素的高低4位}
M --> N[获取RGB值并存储]
I -->|8位图像| O[直接处理每个像素]
O --> P{是否为灰度值?}
P -- 是 --> Q[存储灰度值]
P -- 否 --> R[获取RGB值并存储]
I -->|24位图像| S[处理每个像素的RGB值]
S --> T[获取RGB值并存储]
K --> U[将结果存储到字符串中]
L --> U
N --> U
Q --> U
R --> U
T --> U
U --> V[结束]