099. 编写代码实现简单的机器视觉算法

在C语言中实现一个简单的机器视觉算法可以帮助你理解图像处理和计算机视觉的基本概念。这里我将展示一个简单的边缘检测算法,使用Sobel算子来检测图像中的边缘。Sobel算子是一种常用的梯度计算方法,用于突出图像中亮度变化快的区域,通常用于边缘检测。

Sobel边缘检测算法简介

Sobel算子通过计算图像中每个像素的水平和垂直梯度来检测边缘。它使用两个3x3的卷积核分别计算水平和垂直方向的梯度。

水平方向的Sobel算子:Gx​=​−1−2−1​000​121​​

垂直方向的Sobel算子:Gy​=​−101​−202​−101​​

每个像素的梯度幅度可以通过以下公式计算:G=Gx2​+Gy2​​

通常,为了简化计算,可以使用:G=∣Gx​∣+∣Gy​∣

示例代码:简单的Sobel边缘检测

用C语言实现的简单Sobel边缘检测算法。为了简化实现,我们假设输入图像为灰度图像,并使用简单的二维数组来表示图像数据。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAX_IMAGE_SIZE 512

// 图像结构
typedef struct {
    int width;
    int height;
    unsigned char data[MAX_IMAGE_SIZE][MAX_IMAGE_SIZE];
} Image;

// 读取PGM图像文件
int readPGM(const char* filename, Image* img) {
    FILE* file = fopen(filename, "rb");
    if (!file) {
        printf("Error opening file %s\n", filename);
        return -1;
    }

    char header[3];
    fscanf(file, "%s", header);
    if (strcmp(header, "P5") != 0) {
        printf("Invalid PGM file format\n");
        fclose(file);
        return -1;
    }

    fscanf(file, "%d %d", &img->width, &img->height);
    int maxVal;
    fscanf(file, "%d", &maxVal);
    if (maxVal != 255) {
        printf("Unsupported PGM file format\n");
        fclose(file);
        return -1;
    }

    for (int i = 0; i < img->height; i++) {
        for (int j = 0; j < img->width; j++) {
            img->data[i][j] = fgetc(file);
        }
    }

    fclose(file);
    return 0;
}

// 写入PGM图像文件
int writePGM(const char* filename, Image* img) {
    FILE* file = fopen(filename, "wb");
    if (!file) {
        printf("Error opening file %s\n", filename);
        return -1;
    }

    fprintf(file, "P5\n%d %d\n255\n", img->width, img->height);
    for (int i = 0; i < img->height; i++) {
        for (int j = 0; j < img->width; j++) {
            fputc(img->data[i][j], file);
        }
    }

    fclose(file);
    return 0;
}

// Sobel边缘检测
void sobelEdgeDetection(Image* input, Image* output) {
    int width = input->width;
    int height = input->height;

    // Sobel算子
    int Gx[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
    int Gy[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};

    for (int y = 1; y < height - 1; y++) {
        for (int x = 1; x < width - 1; x++) {
            int gx = 0, gy = 0;

            for (int i = -1; i <= 1; i++) {
                for (int j = -1; j <= 1; j++) {
                    unsigned char pixel = input->data[y + i][x + j];
                    gx += pixel * Gx[i + 1][j + 1];
                    gy += pixel * Gy[i + 1][j + 1];
                }
            }

            int gradient = abs(gx) + abs(gy);
            output->data[y][x] = (gradient > 255) ? 255 : gradient;
        }
    }
}

int main() {
    Image input, output;

    if (readPGM("input.pgm", &input) != 0) {
        printf("Failed to read input.pgm\n");
        return -1;
    }

    output.width = input.width;
    output.height = input.height;

    sobelEdgeDetection(&input, &output);

    if (writePGM("output.pgm", &output) != 0) {
        printf("Failed to write output.pgm\n");
        return -1;
    }

    printf("Edge detection completed. Output saved to output.pgm\n");

    return 0;
}

代码说明

图像结构

  • 定义了一个 Image 结构来存储图像的宽度、高度和像素数据。

读取PGM图像

  • 使用 readPGM 函数读取灰度图像文件(PGM格式)。

  • PGM格式是一种简单的灰度图像格式,适合用于简单的图像处理任务。

写入PGM图像

  • 使用 writePGM 函数将处理后的图像保存为PGM文件。

Sobel边缘检测

  • 使用 sobelEdgeDetection 函数对输入图像进行边缘检测。

  • 使用Sobel算子计算每个像素的水平和垂直梯度。

  • 计算梯度幅度并将其值存储在输出图像中。

主函数

  • 读取输入图像。

  • 调用边缘检测函数。

  • 将结果保存为输出图像。

示例运行

假设你有一个输入图像 input.pgm,运行程序后,输出图像 output.pgm 将包含检测到的边缘。

扩展功能

  1. 支持彩色图像:可以扩展算法以支持彩色图像,通过分别处理RGB通道来计算边缘。
  2. 优化性能:使用多线程或并行计算来加速边缘检测过程。
  3. 其他边缘检测算法:实现其他边缘检测算法,如Canny边缘检测。
  4. 图像预处理:在边缘检测之前对图像进行预处理,如降噪或对比度增强。

视频讲解

BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)