繁体   English   中英

使用 C 在 24 位 bmp 中进行边缘检测

[英]Edge detection in 24-bit bmp using C

你好吗? 我有一个关于我一直在学习的算法的问题。 它是一种相对简单的算法,有助于检测图像的边缘。

总之,该算法的工作原理如下:它采用任意尺寸的 24 位.bmp 图像,并应用 Sobel 算子来检测图像中的边缘。

我几乎设法用下面的代码得到了令人满意的结果。

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


[![#pragma pack(push, 1)
    typedef struct 
    {
      char bitmapSignatureBytes\[2\];
      uint32_t sizeOfBitmapImageBytes;
      uint16_t reserved1;
      uint16_t reserved2;
      uint32_t pixelOffset;][1]][1]
      
}bmpFileHeader;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
  uint32_t  dib_header_size;  // DIB Header size in bytes (40 bytes)
  int32_t   width;         // Width of the image
  int32_t   height;        // Height of image
  uint16_t  num_planes;       // Number of color planes
  uint16_t  bits_per_pixel;   // Bits per pixel
  uint32_t  compression;      // Compression type
  uint32_t  image_size_bytes; // Image size in bytes
  int32_t   x_resolution_ppm; // Pixels per meter
  int32_t   y_resolution_ppm; // Pixels per meter
  uint32_t  num_colors;       // Number of colors  
  uint32_t  important_colors; // Important colors 
  
}bmpInfoHeader;
#pragma pack(pop)

#pragma pack(push,1)
typedef struct 
{
  uint8_t blue;
  uint8_t green;
  uint8_t red; 
  
}pixel;

#pragma pack(pop)

int randNum(void);
int main(void){
  
  bmpFileHeader myBmpFileHeader;
  bmpInfoHeader myBmpInfoHeader;


  FILE *bmpImage = fopen("work.bmp", "rb");
  FILE *newBmpImage = fopen("border_work.bmp", "wb");

  if (bmpImage == NULL)
  {
    printf("Error occured when opening file\n");
  }
    


    fread(&myBmpFileHeader, sizeof(myBmpFileHeader), 1, bmpImage);
    fread(&myBmpInfoHeader, sizeof(myBmpInfoHeader), 1, bmpImage);

    if (myBmpFileHeader.bitmapSignatureBytes[0]==0x42 && myBmpFileHeader.bitmapSignatureBytes[1]==0x4D && myBmpInfoHeader.dib_header_size == 40 && myBmpInfoHeader.bits_per_pixel == 24 && myBmpInfoHeader.compression ==0 )
    {
      printf(" File is probably BMP\n");
    }else{
      printf("Error\n");
    }
    int width = myBmpInfoHeader.width;
    //printf("Width %i\n", width );
    int height = abs(myBmpInfoHeader.height);
    //printf("Height: %i\n", height );


    pixel(*image)[width] = calloc(height, width * sizeof(pixel));
    pixel(*image_blur)[width] = calloc(height, width * sizeof(pixel));

    int padding = (4 - (width * sizeof(pixel)) % 4) % 4;

    for (int i = 0; i < height; ++i)
    {
      fread(image[i], sizeof(pixel), width, bmpImage);
      fseek(bmpImage, padding, SEEK_CUR);

    }

    int gx[3][3];
    int gy[3][3];

    gx[0][0] = -1;
    gx[0][1] = 0;
    gx[0][2] = 1;

    gx[1][0] = -2;
    gx[1][1] = 0;
    gx[1][2] = 2;

    gx[2][0] = -1;
    gx[2][1] = 0;
    gx[2][2] = 1;


    gy[0][0] = -1;
    gy[0][1] = -2;
    gy[0][2] = -1;

    gy[1][0] = 0;
    gy[1][1] = 0;
    gy[1][2] = 0;

    gy[2][0] = 1;
    gy[2][1] = 2;
    gy[2][2] = 1;

    int gxValBlue;
    int gyValBlue;

    int gxValGreen;
    int gyValGreen;

    int gxValRed;
    int gyValRed;

    int squaredBlue;
    int squaredGreen;
    int squaredRed;



    

       for (int lin = 0; lin < height; ++lin)
    {

      for (int col = 0; col < width; ++col)
      {



        if (lin !=0 && lin != height && col != 0 && col != width)// tem todos os vizinhos
        {




          gxValBlue = (image[lin-1][col-1].blue * gx[0][0] + image[lin-1][col].blue * gx[0][1] + image[lin-1][col+1].blue * gx[0][2] + image[lin][col-1].blue * gx[1][0] + image[lin][col].blue * gx[1][1] + image[lin][col+1].blue * gx[1][2] + image[lin-1][col-1].blue * gx[2][0] + image[lin+1][col].blue * gx[2][1] + image[lin+1][col+1].blue * gx[2][2]);
          gyValBlue = (image[lin-1][col-1].blue * gy[0][0] + image[lin-1][col].blue * gy[0][1] + image[lin-1][col+1].blue * gy[0][2] + image[lin][col-1].blue * gy[1][0] + image[lin][col].blue * gy[1][1] + image[lin][col+1].blue * gy[1][2] + image[lin-1][col-1].blue * gy[2][0] + image[lin+1][col].blue * gy[2][1] + image[lin+1][col+1].blue * gy[2][2]);
          
          squaredBlue = (int)sqrt(gxValBlue*gxValBlue + gyValBlue*gyValBlue);

          gxValGreen = (image[lin-1][col-1].green * gx[0][0] + image[lin-1][col].green * gx[0][1] + image[lin-1][col+1].green * gx[0][2] + image[lin][col-1].green * gx[1][0] + image[lin][col].green * gx[1][1] + image[lin][col+1].green * gx[1][2] + image[lin-1][col-1].green * gx[2][0] + image[lin+1][col].green * gx[2][1] + image[lin+1][col+1].green * gx[2][2]);
          gyValGreen = (image[lin-1][col-1].green * gy[0][0] + image[lin-1][col].green * gy[0][1] + image[lin-1][col+1].green * gy[0][2] + image[lin][col-1].green * gy[1][0] + image[lin][col].green * gy[1][1] + image[lin][col+1].green * gy[1][2] + image[lin-1][col-1].green * gy[2][0] + image[lin+1][col].green * gy[2][1] + image[lin+1][col+1].green * gy[2][2]);
          
          squaredGreen = (int)sqrt(gxValGreen*gxValGreen + gyValGreen*gyValGreen);

          gxValRed = (image[lin-1][col-1].red * gx[0][0] + image[lin-1][col].red * gx[0][1] + image[lin-1][col+1].red * gx[0][2] + image[lin][col-1].red * gx[1][0] + image[lin][col].red * gx[1][1] + image[lin][col+1].red * gx[1][2] + image[lin-1][col-1].red * gx[2][0] + image[lin+1][col].red * gx[2][1] + image[lin+1][col+1].red * gx[2][2]);
          gyValRed = (image[lin-1][col-1].red * gy[0][0] + image[lin-1][col].red * gy[0][1] + image[lin-1][col+1].red * gy[0][2] + image[lin][col-1].red * gy[1][0] + image[lin][col].red * gy[1][1] + image[lin][col+1].red * gy[1][2] + image[lin-1][col-1].red * gy[2][0] + image[lin+1][col].red * gy[2][1] + image[lin+1][col+1].red * gy[2][2]);
          
          squaredRed = (int)sqrt(gxValRed*gxValRed + gyValRed*gyValRed);

         

          if (squaredBlue > 255)
          {
            image_blur[lin][col].blue = 255;
          }else{
            image_blur[lin][col].blue = squaredBlue;
          }

         

          if (squaredGreen > 255)
          {
            image_blur[lin][col].green = 255;
          }else{
            image_blur[lin][col].green = squaredGreen;
          }


          if (squaredRed > 255)
          {
            image_blur[lin][col].red = 255;
          }else{
            image_blur[lin][col].red = squaredRed;
          }
          
          
          
          

        }else { // bottom

          
          image_blur[lin][col].blue = 0;
          image_blur[lin][col].green = 0;
          image_blur[lin][col].red = 0;


        }




      
    }
 
      }
fwrite(&myBmpFileHeader, sizeof(myBmpFileHeader),1, newBmpImage);
fwrite(&myBmpInfoHeader, sizeof(myBmpInfoHeader), 1, newBmpImage);


for (int i = 0; i < width; ++i)
{
  
  for (int k = 0; k < padding; ++k)
  {
    fputc(0x00, newBmpImage);
  }
  fwrite(image_blur[i], sizeof(pixel), width, newBmpImage);
}


fclose(newBmpImage);
fclose(bmpImage);
free(image);
free(image_blur);
return 0;
}

我还发送了原始图像和修改图像的示例。 如您所见,修改后的图像被裁剪了。 两个图像具有相同的尺寸,但修改后的图像出现裁剪。

我假设它可能正在发生:

  1. 滥用 calloc () 未提供足够的 memory 来存储修改后的图像
  2. 填充问题

这个问题困扰我很久了,想请社区帮助解决这个问题,提高我在C的水平。 这是输出图像的示例

裁剪 output 的原因是 user3386109 所说的:在编写 output BMP 时,外循环

for (int i = 0; i < width; ++i)

应该迭代到height ,而不是width BMP 从底行开始存储,这就是图像顶部的一部分丢失的原因。

关于过滤的一个小评论:有一个检查似乎打算排除边界处理的一个像素边距,

if (lin !=0 && lin != height && col != 0 && col != width)

请注意,右侧和底部边缘存在差一错误。 由于linlin < height进行迭代,因此底行是lin == height - 1 ,而不是height 同样col == width - 1是最右边的列。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM