必做: bmp图像读取,二值形态学边缘检测,灰度形态学边缘检测。读取bmp图像后,对图像进行边缘检测,并将边缘图像保存为新的bmp图像
我尝试了你的边缘图像,需要告诉你心目中的图像特征要多细腻,我研究图像很多年,总的来说c语言实现效果达不到那么完美,最好要用OpenCV和libbmp实现,边缘检测是得靠模型不断训练得到的,我保留意见
原图
生成图
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#pragma pack(1)
typedef struct {
unsigned char magic[2];
unsigned int fileSize;
unsigned short reserved1;
unsigned short reserved2;
unsigned int offset;
} BMPHeader;
typedef struct {
unsigned int headerSize;
int width;
int height;
unsigned short planes;
unsigned short bitsPerPixel;
unsigned int compression;
unsigned int imageSize;
int xPixelsPerMeter;
int yPixelsPerMeter;
unsigned int colorsUsed;
unsigned int colorsImportant;
} BMPInfoHeader;
typedef struct {
unsigned char blue;
unsigned char green;
unsigned char red;
} RGB;
void readBmp(const char* filename, RGB** image, int* width, int* height) {
FILE* fp = fopen(filename, "rb");
if (!fp) {
printf("Failed to open file: %s\n", filename);
exit(1);
}
BMPHeader header;
BMPInfoHeader infoHeader;
if (fread(&header, sizeof(header), 1, fp) != 1) {
printf("Failed to read BMP header\n");
exit(1);
}
if (fread(&infoHeader, sizeof(infoHeader), 1, fp) != 1) {
printf("Failed to read BMP info header\n");
exit(1);
}
if (header.magic[0] != 'B' || header.magic[1] != 'M') {
printf("Invalid BMP magic number: %c%c\n", header.magic[0], header.magic[1]);
exit(1);
}
if (infoHeader.bitsPerPixel != 24) {
printf("Unsupported BMP format: %d bits per pixel\n", infoHeader.bitsPerPixel);
exit(1);
}
if (infoHeader.compression != 0) {
printf("Unsupported BMP compression method: %d\n", infoHeader.compression);
exit(1);
}
*width = infoHeader.width;
*height = infoHeader.height;
*image = (RGB*)malloc(*width * *height * sizeof(RGB));
if (!*image) {
printf("Memory allocation failed\n");
exit(1);
}
int rowSize = (*width * 3 + 3) / 4 * 4 - (*width * 3 % 4);
int i, j;
for (i = 0; i < *height; i++) {
for (j = 0; j < *width; j++) {
RGB pixel;
if (fread(&pixel, sizeof(pixel), 1, fp) != 1) {
printf("Failed to read pixel at (%d, %d)\n", j, i);
exit(1);
}
(*image)[(*height - i - 1) * *width + j] = pixel;
}
fseek(fp, rowSize - *width * 3, SEEK_CUR);
}
fclose(fp);
}
void saveBmp(const char* filename, RGB* image, int width, int height) {
FILE* fp = fopen(filename, "wb");
if (!fp) {
printf("Failed to create file: %s\n", filename);
exit(1);
}
BMPHeader header;
BMPInfoHeader infoHeader;
header.magic[0] = 'B';
header.magic[1] = 'M';
header.fileSize = sizeof(header) + sizeof(infoHeader) + (width * height * 3);
header.reserved1 = 0;
header.reserved2 = 0;
header.offset = sizeof(header) + sizeof(infoHeader);
infoHeader.headerSize = sizeof(infoHeader);
infoHeader.width = width;
infoHeader.height = height;
infoHeader.planes = 1;
infoHeader.bitsPerPixel = 24;
infoHeader.compression = 0;
infoHeader.imageSize = width * height * 3;
infoHeader.xPixelsPerMeter = 0;
infoHeader.yPixelsPerMeter = 0;
infoHeader.colorsUsed = 0;
infoHeader.colorsImportant = 0;
if (fwrite(&header, sizeof(header), 1, fp) != 1) {
printf("Failed to write BMP header\n");
exit(1);
}
if (fwrite(&infoHeader, sizeof(infoHeader), 1, fp) != 1) {
printf("Failed to write BMP info header\n");
exit(1);
}
int rowSize = (width * 3 + 3) / 4 * 4 - (width * 3 % 4);
int i, j;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
RGB pixel = image[(height - i - 1) * width + j];
if (fwrite(&pixel, sizeof(pixel), 1, fp) != 1) {
printf("Failed to write pixel at (%d, %d)\n", j, i);
exit(1);
}
}
unsigned char padding[3] = {0};
if (fwrite(padding, sizeof(padding), 1, fp) != 1) {
printf("Failed to write padding\n");
exit(1);
}
}
fclose(fp);
printf("图像处理成功!\n");
}
void gray(RGB* image, int width, int height) {
int i, j;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
unsigned char gray = (unsigned char)(0.299 * image[width*i + j].red + 0.587 * image[width*i + j].green + 0.114 * image[width*i + j].blue);
image[width*i + j].red = gray;
image[width*i + j].green = gray;
image[width*i + j].blue = gray;
}
}
}
void binarize(RGB* image, int width, int height) {
int i, j;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
unsigned char gray = image[width*i + j].red;
if (gray < 128) {
image[width*i + j].red = 0;
image[width*i + j].green = 0;
image[width*i + j].blue = 0;
}
else {
image[width*i + j].red = 255;
image[width*i + j].green = 255;
image[width*i + j].blue = 255;
}
}
}
}
void dilate(RGB* image, int width, int height) {
int i, j, k, l, m, n;
RGB* temp = (RGB*)malloc(width*height * sizeof(RGB));
if (!temp) {
printf("Memory allocation failed\n");
exit(1);
}
memcpy(temp, image, width*height * sizeof(RGB));
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
int flag = 1;
for (k = -1; k <= 1; k++) {
for (l = -1; l <= 1; l++) {
m = i + k;
n = j + l;
if (m >= 0 && m < height && n >= 0 && n < width) {
if (temp[width*m + n].red == 0) {
flag = 0;
break;
}
}
}
if (!flag) {
break;
}
}
if (flag) {
image[width*i + j].red = 0;
image[width*i + j].green = 0;
image[width*i + j].blue = 0;
}
}
}
free(temp);
}
void erode(RGB* image, int width, int height) {
int i, j, k, l, m, n;
RGB* temp = (RGB*)malloc(width*height * sizeof(RGB));
if (!temp) {
printf("Memory allocation failed\n");
exit(1);
}
memcpy(temp, image, width*height * sizeof(RGB));
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
int flag = 1;
for (k = -1; k <= 1; k++) {
for (l = -1; l <= 1; l++) {
m = i + k;
n = j + l;
if (m >= 0 && m < height && n >= 0 && n < width) {
if (temp[width*m + n].red == 255) {
flag = 0;
break;
}
}
}
if (!flag) {
break;
}
}
if (flag) {
image[width*i + j].red = 255;
image[width*i + j].green = 255;
image[width*i + j].blue = 255;
}
}
}
free(temp);
}
void edgeDetection(RGB* image, int width, int height) {
int i, j, k, l, m, n;
RGB* temp = (RGB*)malloc(width*height * sizeof(RGB));
if (!temp) {
printf("Memory allocation failed\n");
exit(1);
}
memcpy(temp, image, width*height * sizeof(RGB));
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
int flag = 0;
for (k = -1; k <= 1; k++) {
for (l = -1; l <= 1; l++) {
m = i + k;
n = j + l;
if (m >= 0 && m < height && n >= 0 && n < width) {
if (temp[width*m + n].red == 0) {
int diff = abs(k) + abs(l);
if (diff == 1 || diff == 2) {
flag = 1;
break;
}
}
}
}
if (flag) {
break;
}
}
if (flag) {
image[width*i + j].red = 0;
image[width*i + j].green = 0;
image[width*i + j].blue = 0;
}
else {
image[width*i + j].red = 255;
image[width*i + j].green = 255;
image[width*i + j].blue = 255;
}
}
}
free(temp);
}
int main() {
RGB* image;
int width, height;
readBmp("/Users/dezhiwoxing/Desktop/3.bmp", &image, &width, &height);
// Image processing
gray(image, width, height);
binarize(image, width, height);
dilate(image, width, height);
erode(image, width, height);
edgeDetection(image, width, height);
saveBmp("/Users/dezhiwoxing/Desktop/result.bmp", image, width, height);
free(image);
return 0;
}
可参考
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// 定义BMP文件头结构体
#pragma pack(2)
typedef struct {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} BMPFileHeader;
// 定义BMP图像信息头结构体
#pragma pack(2)
typedef struct {
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} BMPInfoHeader;
// 读取BMP图像
void readBMP(const char* filename, uint8_t** image, BMPInfoHeader* infoHeader) {
FILE* file = fopen(filename, "rb");
if (file == NULL) {
printf("打开BMP文件失败.\n");
exit(1);
}
BMPFileHeader fileHeader;
fread(&fileHeader, sizeof(BMPFileHeader), 1, file);
fread(infoHeader, sizeof(BMPInfoHeader), 1, file);
int width = infoHeader->biWidth;
int height = abs(infoHeader->biHeight);
int padding = (4 - (width * 3) % 4) % 4;
*image = (uint8_t*)malloc(width * height);
fseek(file, fileHeader.bfOffBits, SEEK_SET);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uint8_t pixel;
fread(&pixel, sizeof(uint8_t), 1, file);
(*image)[x + y * width] = pixel;
}
fseek(file, padding, SEEK_CUR);
}
fclose(file);
}
// 保存BMP图像
void saveBMP(const char* filename, const uint8_t* image, const BMPInfoHeader* infoHeader) {
FILE* file = fopen(filename, "wb");
if (file == NULL) {
printf("保存BMP文件失败.\n");
exit(1);
}
BMPFileHeader fileHeader;
fileHeader.bfType = 0x4D42;
fileHeader.bfSize = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + infoHeader->biSizeImage;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader);
fwrite(&fileHeader, sizeof(BMPFileHeader), 1, file);
fwrite(infoHeader, sizeof(BMPInfoHeader), 1, file);
int width = infoHeader->biWidth;
int height = abs(infoHeader->biHeight);
int padding = (4 - (width * 3) % 4) % 4;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uint8_t pixel = image[x + y * width];
fwrite(&pixel, sizeof(uint8_t), 1, file);
}
uint8_t paddingByte = 0;
fwrite(&paddingByte, sizeof(uint8_t), padding, file);
}
fclose(file);
}
// 二值形态学边缘检测
void binaryMorphologicalEdgeDetection(uint8_t* image, int width, int height) {
uint8_t* tempImage = (uint8_t*)malloc(width * height);
// 膨胀
for (int y = 1; y < height - 1; y++) {
for (int x = 1; x < width - 1; x++) {
uint8_t maxPixel = 0;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
uint8_t pixel = image[x + dx + (y + dy) * width];
if (pixel > maxPixel) {
maxPixel = pixel;
}
}
}
tempImage[x + y * width] = maxPixel;
}
}
// 腐蚀
for (int y = 1; y < height - 1; y++) {
for (int x = 1; x < width - 1; x++) {
uint8_t minPixel = 255;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
uint8_t pixel = tempImage[x + dx + (y + dy) * width];
if (pixel < minPixel) {
minPixel = pixel;
}
}
}
image[x + y * width] = minPixel;
}
}
free(tempImage);
}
// 灰度形态学边缘检测
void grayMorphologicalEdgeDetection(uint8_t* image, int width, int height) {
uint8_t* tempImage = (uint8_t*)malloc(width * height);
// 膨胀
for (int y = 1; y < height - 1; y++) {
for (int x = 1; x < width - 1; x++) {
uint8_t maxPixel = 0;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
uint8_t pixel = image[x + dx + (y + dy) * width];
if (pixel > maxPixel) {
maxPixel =pixel;
}
}
}
tempImage[x + y * width] = maxPixel;
}
}
// 腐蚀
for (int y = 1; y < height - 1; y++) {
for (int x = 1; x < width - 1; x++) {
uint8_t minPixel = 255;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
uint8_t pixel = tempImage[x + dx + (y + dy) * width];
if (pixel < minPixel) {
minPixel = pixel;
}
}
}
image[x + y * width] = minPixel;
}
}
free(tempImage);
}
int main() {
const char* filename = "image.bmp";
BMPInfoHeader infoHeader;
uint8_t* image;
loadBMP(filename, &image, &infoHeader);
int width = infoHeader.biWidth;
int height = abs(infoHeader.biHeight);
// 转化为灰度图像
for (int i = 0; i < width * height; i++) {
uint8_t pixel = image[i];
image[i] = (uint8_t)(0.299 * pixel + 0.587 * pixel + 0.114 * pixel);
}
// 二值化
for (int i = 0; i < width * height; i++) {
uint8_t pixel = image[i];
if (pixel > 128) {
image[i] = 255;
} else {
image[i] = 0;
}
}
// 形态学边缘检测
binaryMorphologicalEdgeDetection(image, width, height);
// 保存结果
saveBMP("edge.bmp", image, &infoHeader);
free(image);
return 0;
}
基于数学形态学的边缘检测在图像处理领域中有着广泛的应用,可以通过以下步骤进行实现:
图像读取:使用 C 语言中的 BMP 库打开 BMP 图像文件,并读取图像数据。BMP 图像格式具有简单、直观且易于编程的特点,因此十分适合使用 C 语言进行图像处理操作。
灰度化处理:将 BMP 图像转换为灰度图像。在 C 语言中,我们可以根据 RGB 值的加权平均值来计算灰度值,或者使用 OpenCV 等图像处理库中提供的函数进行灰度化处理。
二值化处理:通过设定阈值,将灰度图像转换为二值图像。在二值形态学边缘检测中,我们需要将图像中的前景和背景区分开来,可以通过手动设置阈值或使用 Otsu 算法等方法进行二值化处理。
形态学运算:利用图像形态学中的腐蚀、膨胀、开运算和闭运算等操作进行边缘检测。对于灰度图像和二值图像,均可使用形态学运算进行边缘检测。具体实现方法可以参考 C 语言中的 OpenCV 等图像处理库,或者自行编写相关函数。
图像保存:将边缘检测后的图像数据保存为新的 BMP 图像文件。在 C 语言中,我们可以使用 BMP 库中提供的函数将图像数据写入到 BMP 文件中,并设置相应的图像参数和文件头信息。
总之,数学形态学边缘检测是一项较为复杂的图像处理任务,需要充分掌握数学和算法知识,熟悉 C 语言及相关图像处理库。
以下是基于数学形态学的边缘检测的C语言代码。这个代码使用了OpenCV图像处理库,实现的功能包括 BMP 图像读取,二值形态学边缘检测,灰度形态学边缘检测,以及将边缘图像保存为新的 BMP 图像。
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
using namespace cv;
// 二值形态学边缘检测
Mat binaryMorphologyEdgeDetection(Mat& src)
{
// 阈值处理(反转二值化)
Mat thresholded;
threshold(src, thresholded, 128, 255, THRESH_BINARY_INV);
// 反转图像(使前景为1,背景为0)
Mat inverted;
bitwise_not(thresholded, inverted);
// 利用开运算和闭运算提取边缘
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(inverted, inverted, MORPH_CLOSE, kernel); // 闭操作
morphologyEx(inverted, inverted, MORPH_OPEN, kernel); // 开操作
// 再次反转图像(还原二值化)
Mat edge;
bitwise_not(inverted, edge);
return edge;
}
// 灰度形态学边缘检测
Mat grayMorphologyEdgeDetection(Mat& src)
{
// 利用 Sobel 算子计算梯度
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
Sobel(src, grad_x, CV_16S, 1, 0, 3);
Sobel(src, grad_y, CV_16S, 0, 1, 3);
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
Mat grad;
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
// 阈值处理(反转二值化)
Mat thresholded;
threshold(grad, thresholded, 128, 255, THRESH_BINARY_INV);
// 反转图像(使前景为1,背景为0)
Mat inverted;
bitwise_not(thresholded, inverted);
// 利用开运算和闭运算提取边缘
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(inverted, inverted, MORPH_CLOSE, kernel); // 闭操作
morphologyEx(inverted, inverted, MORPH_OPEN, kernel); // 开操作
// 再次反转图像(还原二值化)
Mat edge;
bitwise_not(inverted, edge);
return edge;
}
int main()
{
// 读取 BMP 图像
Mat image = imread("input.bmp", IMREAD_GRAYSCALE);
if (!image.data)
{
printf("Error: can't read the image file.\n");
return -1;
}
// 进行边缘检测
Mat binaryEdge = binaryMorphologyEdgeDetection(image);
Mat grayEdge = grayMorphologyEdgeDetection(image);
// 保存边缘检测结果为 BMP 图像
imwrite("binary_edge.bmp", binaryEdge);
imwrite("gray_edge.bmp", grayEdge);
return 0;
}
需要注意的是,这段代码使用了C++中的一些特性(如命名空间),如果你的项目限定了只能使用C语言,可以将其进行相应修改。
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned char blue;
unsigned char green;
unsigned char red;
} Pixel;
#pragma pack(push, 1)
typedef struct {
char signature[2];
unsigned int fileSize;
unsigned int reserved;
unsigned int dataOffset;
} BMPHeader;
#pragma pack(pop)
int main() {
// 读取BMP图像
FILE *file = fopen("input.bmp", "rb");
if (file == NULL) {
printf("Failed to open the file.\n");
return 1;
}
BMPHeader header;
fread(&header, sizeof(BMPHeader), 1, file);
fseek(file, header.dataOffset, SEEK_SET);
int width = (header.fileSize - header.dataOffset) / sizeof(Pixel);
Pixel *image = (Pixel *)malloc(sizeof(Pixel) * width);
fread(image, sizeof(Pixel), width, file);
fclose(file);
// 边缘检测
Pixel *edge = (Pixel *)malloc(sizeof(Pixel) * width);
for (int i = 0; i < width; i++) {
if (i == 0 || i == width - 1) {
edge[i].blue = 0;
edge[i].green = 0;
edge[i].red = 0;
continue;
}
edge[i].blue = abs(image[i - 1].blue - image[i + 1].blue);
edge[i].green = abs(image[i - 1].green - image[i + 1].green);
edge[i].red = abs(image[i - 1].red - image[i + 1].red);
}
// 保存边缘图像为新的BMP图像
file = fopen("edge.bmp", "wb");
if (file == NULL) {
printf("Failed to create the file.\n");
return 1;
}
fwrite(&header, sizeof(BMPHeader), 1, file);
fwrite(edge, sizeof(Pixel), width, file);
fclose(file);
free(image);
free(edge);
return 0;
}
以下是一个使用C语言实现基于数学形态学的边缘检测的示例代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned char b, g, r;
} Pixel;
typedef struct {
int width, height;
Pixel *data;
} Image;
Image *readBMP(const char *filename) {
FILE *file = fopen(filename, "rb");
if (!file) {
printf("Failed to open the file.\n");
return NULL;
}
unsigned char header[54];
fread(header, sizeof(unsigned char), 54, file);
int width = *(int*)&header[18];
int height = *(int*)&header[22];
int dataSize = width * height * 3;
unsigned char *imageData = (unsigned char*)malloc(dataSize);
fread(imageData, sizeof(unsigned char), dataSize, file);
fclose(file);
Image *image = (Image*)malloc(sizeof(Image));
image->width = width;
image->height = height;
image->data = (Pixel*)malloc(width * height * sizeof(Pixel));
int i, j, k = 0;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
image->data[i * width + j].b = imageData[k++];
image->data[i * width + j].g = imageData[k++];
image->data[i * width + j].r = imageData[k++];
}
}
free(imageData);
return image;
}
void writeBMP(const char *filename, Image *image) {
int width = image->width;
int height = image->height;
Pixel *data = image->data;
int dataSize = width * height * 3;
unsigned char *imageData = (unsigned char*)malloc(dataSize);
int i, j, k = 0;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
imageData[k++] = data[i * width + j].b;
imageData[k++] = data[i * width + j].g;
imageData[k++] = data[i * width + j].r;
}
}
FILE *file = fopen(filename, "wb");
if (!file) {
printf("Failed to create the file.\n");
return;
}
unsigned char header[54] = {
0x42, 0x4D, 0x36, 0xA2, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x40, 0x01,
0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x05, 0x00, 0x00, 0x12,
0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 以下是一个基于数学形态学的边缘检测的示例代码,使用C语言实现。这个示例代码可以读取BMP图像,进行二值形态学和灰度形态学边缘检测,并将边缘图像保存为新的BMP图像。
```c
#include <stdio.h>
#include <stdlib.h>
#pragma pack(2)
typedef struct {
unsigned short type;
unsigned int size;
unsigned short reserved1;
unsigned short reserved2;
unsigned int offset;
} BMPHeader;
typedef struct {
unsigned int size;
int width;
int height;
unsigned short planes;
unsigned short bitCount;
unsigned int compression;
unsigned int imageSize;
int xPixelsPerMeter;
int yPixelsPerMeter;
unsigned int colorsUsed;
unsigned int colorsImportant;
} BMPInfoHeader;
#pragma pack()
void binaryMorphologicalEdgeDetection(unsigned char* input, unsigned char* output, int width, int height) {
// 二值形态学边缘检测
// 这里只实现了简单的膨胀操作,你可以根据需要进行其他操作
for (int i = 1; i < height - 1; i++) {
for (int j = 1; j < width - 1; j++) {
if (input[i * width + j] == 0) {
// 膨胀操作
output[(i-1) * width + j] = 0;
output[i * width + (j-1)] = 0;
output[i * width + j] = 0;
output[i * width + (j+1)] = 0;
output[(i+1) * width + j] = 0;
} else {
output[i * width + j] = 255;
}
}
}
}
void grayscaleMorphologicalEdgeDetection(unsigned char* input, unsigned char* output, int width, int height) {
// 灰度形态学边缘检测
// 这里只实现了简单的膨胀操作,你可以根据需要进行其他操作
for (int i = 1; i < height - 1; i++) {
for (int j = 1; j < width - 1; j++) {
int max = 0;
for (int m = -1; m <= 1; m++) {
for (int n = -1; n <= 1; n++) {
if (input[(i+m) * width + (j+n)] > max) {
max = input[(i+m) * width + (j+n)];
}
}
}
output[i * width + j] = max;
}
}
}
int main() {
FILE* file = fopen("input.bmp", "rb");
if (!file) {
printf("Failed to open input.bmp\n");
return 1;
}
BMPHeader header;
BMPInfoHeader infoHeader;
fread(&header, sizeof(BMPHeader), 1, file);
fread(&infoHeader, sizeof(BMPInfoHeader), 1, file);
int width = infoHeader.width;
int height = infoHeader.height;
int imageSize = infoHeader.imageSize ? infoHeader.imageSize : width * height;
unsigned char* input = (unsigned char*)malloc(imageSize);
unsigned char* output = (unsigned char*)malloc(imageSize);
fread(input, sizeof(unsigned char), imageSize, file);
fclose(file);
// 二值形态学边缘检测
binaryMorphologicalEdgeDetection(input, output, width, height);
file = fopen("binary_edge.bmp", "wb");
fwrite(&header, sizeof(BMPHeader), 1, file);
fwrite(&infoHeader, sizeof(BMPInfoHeader), 1, file);
fwrite(output, sizeof(unsigned char), imageSize, file);
fclose(file);
// 灰度形态学边缘检测
grayscaleMorphologicalEdgeDetection(input, output, width, height);
file = fopen("grayscale_edge.bmp", "wb");
fwrite(&header, sizeof(BMPHeader), 1, file);
fwrite(&infoHeader, sizeof(BMPInfoHeader), 1, file);
fwrite(output, sizeof(unsigned char), imageSize, file);
fclose(file);
free(input);
free(output);
return 0;
}
在这个示例代码中,使用了简单的膨胀操作来进行形态学边缘检测。你可以根据需要修改和扩展这些函数来实现其他形态学操作。
请确保将要处理的BMP图像命名为"input.bmp",然后运行代码。运行结束后,会生成两个新的BMP图像文件,分别是"binary_edge.bmp"和"grayscale_edge.bmp",分别对应二值形态学和灰度形态学边缘检测的结果。
请注意,这只是一个简单的示例代码,可能还有其他需要考虑的因素,如BMP图像的位深度等。你可以根据实际需求进行修改和优化。
不知道你这个问题是否已经解决, 如果还没有解决的话:读取文件之后第一件事即判断我们读取的是否为BMP图像,即
//判断是否是位图,在0-1字节
int IsBitMap(FILE *fp){
ushort s;
fread(&s,1,2,fp);
return s==BM ? 1 : 0;
}
其中,fread
命令表示读取文件fp
,并将读取到的内容存储在s
中。1
表示要读取的数据的大小,2
表示将要读取的元素的个数。由前文可知,位图的文件类型必须是BM
,十六进制下0x4d42,十进制为19778。
然后需要得到图像的宽度和高度,从而确定数据区的范围
//获得图片的宽度,在18-21字节
int getWidth(FILE *fp){
int width;
fseek(fp,18,SEEK_SET);
fread(&width,1,4,fp);
return width;
}
//获得图片的高度 ,在22-25字节
int getHeight(FILE *fp){
int height;
fseek(fp,22,SEEK_SET);
fread(&height,1,4,fp);
return height;
}
其中,fseek
可以为fp
提供一个偏移量,SEEK_SET
表示从文件的开头进行移动。由上文可知,图片高度所在位置是第22个字节。
若想读取其他信息,以此类推即可。
//test.c
#include<stdio.h>
#include<malloc.h>
#define BM 19778 // 位图的标志
#define PATH "1.bmp" //打开的文件路径
#define ushort unsigned short
#define uint unsigned int
#define uchar unsigned char
//判断是否是位图,在0-1字节
int IsBitMap(FILE *fp){
ushort s;
fread(&s,1,2,fp);
return s==BM ? 1 : 0;
}
//获得图片的宽度,在18-21字节
int getWidth(FILE *fp){
int width;
fseek(fp,18,SEEK_SET);
fread(&width,1,4,fp);
return width;
}
//获得图片的高度 ,在22-25字节
int getHeight(FILE *fp){
int height;
fseek(fp,22,SEEK_SET);
fread(&height,1,4,fp);
return height;
}
//获得每个像素的位数,在28-29字节
ushort getBit(FILE *fp)
{
ushort bit;
fseek(fp,28,SEEK_SET);
fread(&bit,1,2,fp);
return bit;
}
//获得数据的起始位置,在10-13字节
uint getOffSet(FILE *fp){
uint OffSet;
fseek(fp,10L,SEEK_SET);
fread(&OffSet,1,4,fp);
return OffSet;
}
int main(){
int width,height;
FILE *fp=fopen(PATH,"r");
uchar *r,*g,*b;
int i,j;
r=(uchar *)malloc(4000);
b=(uchar *)malloc(4000);
g=(uchar *)malloc(4000);
if(!IsBitMap(fp)){
printf("format error!\n");
fclose(fp);
return 0;
}
printf("this file is a bitmap picture\n");
printf("width = %ld\nheight = %ld\n",getWidth(fp),getHeight(fp));
printf("bit size = %d bit\n",getBit(fp));
printf("OffSet = %d\n",getOffSet(fp));
return 0;
}
验证
> gcc .\test.c
> .\a.exe
this file is a bitmap picture
width = 3840
height = 2160
bit size = 24 bit
OffSet = 138
这个 还是很复杂的,提供一点未微薄的思路,不一定准确:
BMP图像读取。 BMP是一种常见的图像文件格式,可以使用许多编程语言的库对其进行读写。对于Go语言,可以使用image
和image/color
包中的函数进行读取。具体的实现方法请参考官方文档。
二值形态学边缘检测。 二值形态学边缘检测主要是通过膨胀、腐蚀两种形态学变换,在二值图像上找到目标的轮廓,也可以使用其他的边缘检测算法,例如Sobel算子、Canny算子等。需要注意的是,膨胀和腐蚀过程中需要选择适当的结构元素。
灰度形态学边缘检测。 灰度形态学边缘检测主要是通过对灰度图像进行形态学的开运算、闭运算等操作来提取目标的轮廓。同样需要选择合适的结构元素和参数,以达到最佳的边缘检测效果。
保存bmp图像。 保存BMP图像可以使用image
包中的函数,具体的实现方法请参考官方文档。