4、实现简单数字图像处理[问题描述] 一幅图像就是一个从位置集到颜色集的变换。考虑二维图像,位置集实际上就是一个矩阵,此时一幅图像实际上就是一个内容为颜色矩阵。如果颜色为0-255 间的整数,表示该位置的灰度等级,0 为黑色,255 为白色,此时的图像称为灰度图。 而图像的处理就是在该矩阵进行相关计算。一种常见的计算就是通过一点和周围8个点的信息共同决定该点的新值:如一点的新值为该点和周围8点颜色值之和的均值,这一操作可用下+表示。 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 图像,+模板 显然这样处理后,图像会变得平滑,因此称为平滑操作。显然将上述操作变为下图时,就成为锐化操作。 -1 -1 -1 -1 9 -1 -1-1 -1图像锐化模板 要求实现若于基本的图像处理操作。[基本要求] ①熟悉 Windows下BMP 文件的格式,能够实现其读写(只考虑灰度图像)。②实现图像的平滑和锐化操作,其它处理操作选做。③需用 VC++作为语言。具体代码和详细步骤
时间: 2023-12-10 19:37:23 浏览: 77
以下是基于Windows下BMP格式的灰度图像的平滑和锐化操作的实现步骤:
1. 读取BMP文件并将其转换为灰度图像
BMP文件的文件头和信息头中包含了文件的一些基本信息,如图像宽度、高度、位深等。我们可以通过读取这些信息来确定图像的大小和像素值。对于灰度图像,每个像素值只需要一个字节来表示。读取完像素值后,我们可以将其存储在一个二维数组中。
2. 实现平滑操作
平滑操作可以通过卷积来实现。我们可以定义一个3x3的卷积核,将其与每个像素的周围8个像素进行卷积操作,得到新的像素值。卷积的过程可以使用两层循环来实现。
3. 实现锐化操作
锐化操作同样可以通过卷积来实现。我们可以定义一个3x3的卷积核,将其与每个像素的周围8个像素进行卷积操作,得到新的像素值。不同的是,卷积核中心的系数为9,其余系数为-1。卷积的过程同样可以使用两层循环来实现。
4. 写入新的BMP文件
在完成图像处理后,我们需要将处理后的像素值写入新的BMP文件中。写入BMP文件的过程与读取BMP文件的过程类似,只需要按照BMP文件格式的要求来设置文件头、信息头和像素值即可。
以下是基于VC++实现的代码示例(仅供参考):
```c++
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
#pragma pack(push, 1)
// BMP文件头
typedef struct {
unsigned short bfType; // 文件类型,必须为0x4D42
unsigned int bfSize; // 文件大小,单位为字节
unsigned short bfReserved1; // 保留字段
unsigned short bfReserved2; // 保留字段
unsigned int bfOffBits; // 像素数据偏移量,单位为字节
} BMPFileHeader;
// BMP信息头
typedef struct {
unsigned int biSize; // 信息头大小,单位为字节
int biWidth; // 图像宽度,单位为像素
int biHeight; // 图像高度,单位为像素
unsigned short biPlanes; // 颜色平面数,必须为1
unsigned short biBitCount; // 每个像素所需位数
unsigned int biCompression; // 压缩类型
unsigned int biSizeImage; // 图像数据大小,单位为字节
int biXPelsPerMeter; // 水平分辨率,单位为像素/米
int biYPelsPerMeter; // 垂直分辨率,单位为像素/米
unsigned int biClrUsed; // 颜色表使用的颜色数
unsigned int biClrImportant; // 重要的颜色数
} BMPInfoHeader;
#pragma pack(pop)
// 读取BMP文件
vector<vector<unsigned char>> readBMP(const char* filename) {
BMPFileHeader fileHeader;
BMPInfoHeader infoHeader;
vector<vector<unsigned char>> pixels;
ifstream fin(filename, ios::binary);
if (!fin) {
cerr << "Error opening file " << filename << endl;
return pixels;
}
fin.read((char*)&fileHeader, sizeof(BMPFileHeader));
fin.read((char*)&infoHeader, sizeof(BMPInfoHeader));
if (fileHeader.bfType != 0x4D42) {
cerr << "Error: " << filename << " is not a BMP file" << endl;
return pixels;
}
if (infoHeader.biBitCount != 8) {
cerr << "Error: " << filename << " is not a grayscale BMP file" << endl;
return pixels;
}
int width = infoHeader.biWidth;
int height = infoHeader.biHeight;
pixels.resize(height, vector<unsigned char>(width));
int bytesPerLine = (width + 3) / 4 * 4;
unsigned char padding[4] = {0};
for (int i = height - 1; i >= 0; i--) {
fin.read((char*)pixels[i].data(), width);
fin.read((char*)padding, bytesPerLine - width);
}
fin.close();
return pixels;
}
// 写入BMP文件
void writeBMP(const char* filename, const vector<vector<unsigned char>>& pixels) {
BMPFileHeader fileHeader;
BMPInfoHeader infoHeader;
int width = pixels[0].size();
int height = pixels.size();
int bytesPerLine = (width + 3) / 4 * 4;
int imageSize = bytesPerLine * height;
fileHeader.bfType = 0x4D42;
fileHeader.bfSize = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + imageSize;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader);
infoHeader.biSize = sizeof(BMPInfoHeader);
infoHeader.biWidth = width;
infoHeader.biHeight = height;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 8;
infoHeader.biCompression = 0;
infoHeader.biSizeImage = imageSize;
infoHeader.biXPelsPerMeter = 0;
infoHeader.biYPelsPerMeter = 0;
infoHeader.biClrUsed = 256;
infoHeader.biClrImportant = 0;
vector<unsigned char> palette(1024);
for (int i = 0; i < 256; i++) {
palette[i * 4] = i;
palette[i * 4 + 1] = i;
palette[i * 4 + 2] = i;
palette[i * 4 + 3] = 0;
}
ofstream fout(filename, ios::binary);
if (!fout) {
cerr << "Error opening file " << filename << endl;
return;
}
fout.write((char*)&fileHeader, sizeof(BMPFileHeader));
fout.write((char*)&infoHeader, sizeof(BMPInfoHeader));
fout.write((char*)palette.data(), palette.size());
unsigned char padding[4] = {0};
for (int i = height - 1; i >= 0; i--) {
fout.write((char*)pixels[i].data(), width);
fout.write((char*)padding, bytesPerLine - width);
}
fout.close();
}
// 平滑操作
vector<vector<unsigned char>> smooth(const vector<vector<unsigned char>>& pixels) {
int width = pixels[0].size();
int height = pixels.size();
vector<vector<unsigned char>> smoothedPixels(height, vector<unsigned char>(width));
for (int i = 1; i < height - 1; i++) {
for (int j = 1; j < width - 1; j++) {
int sum = 0;
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
sum += pixels[i + k][j + l];
}
}
smoothedPixels[i][j] = sum / 9;
}
}
return smoothedPixels;
}
// 锐化操作
vector<vector<unsigned char>> sharpen(const vector<vector<unsigned char>>& pixels) {
int width = pixels[0].size();
int height = pixels.size();
vector<vector<unsigned char>> sharpenedPixels(height, vector<unsigned char>(width));
for (int i = 1; i < height - 1; i++) {
for (int j = 1; j < width - 1; j++) {
int sum = 0;
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
sum += pixels[i + k][j + l] * (k == 0 && l == 0 ? 9 : -1);
}
}
sharpenedPixels[i][j] = max(0, min(255, pixels[i][j] + sum));
}
}
return sharpenedPixels;
}
int main() {
// 读取BMP文件
vector<vector<unsigned char>> pixels = readBMP("test.bmp");
// 平滑操作
vector<vector<unsigned char>> smoothedPixels = smooth(pixels);
// 锐化操作
vector<vector<unsigned char>> sharpenedPixels = sharpen(pixels);
// 写入新的BMP文件
writeBMP("smoothed.bmp", smoothedPixels);
writeBMP("sharpened.bmp", sharpenedPixels);
return 0;
}
```
阅读全文