用c语言完成基于数学形态学的边缘检测。

必做: bmp图像读取,二值形态学边缘检测,灰度形态学边缘检测。读取bmp图像后,对图像进行边缘检测,并将边缘图像保存为新的bmp图像

我尝试了你的边缘图像,需要告诉你心目中的图像特征要多细腻,我研究图像很多年,总的来说c语言实现效果达不到那么完美,最好要用OpenCV和libbmp实现,边缘检测是得靠模型不断训练得到的,我保留意见
原图

img

生成图

img

#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图像的位深度等。你可以根据实际需求进行修改和优化。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/158065
  • 你也可以参考下这篇文章:bmp图片灰度化和二值化
  • 除此之外, 这篇博客: C语言读取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
    
  • 您还可以看一下 韦东山老师的嵌入式Linux项目实战:三个大项目(数码相框、摄像头驱动和电源管理),九个衍生项目视频教程课程中的 bmp数据提取用于图标显示小节, 巩固相关知识点

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

这个 还是很复杂的,提供一点未微薄的思路,不一定准确:

  1. BMP图像读取。 BMP是一种常见的图像文件格式,可以使用许多编程语言的库对其进行读写。对于Go语言,可以使用imageimage/color包中的函数进行读取。具体的实现方法请参考官方文档。

  2. 二值形态学边缘检测。 二值形态学边缘检测主要是通过膨胀、腐蚀两种形态学变换,在二值图像上找到目标的轮廓,也可以使用其他的边缘检测算法,例如Sobel算子、Canny算子等。需要注意的是,膨胀和腐蚀过程中需要选择适当的结构元素。

  3. 灰度形态学边缘检测。 灰度形态学边缘检测主要是通过对灰度图像进行形态学的开运算、闭运算等操作来提取目标的轮廓。同样需要选择合适的结构元素和参数,以达到最佳的边缘检测效果。

  4. 保存bmp图像。 保存BMP图像可以使用image包中的函数,具体的实现方法请参考官方文档。

https://www.cnblogs.com/GoldBeetle/p/9982086.html