[英]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;
}
我还发送了原始图像和修改图像的示例。 如您所见,修改后的图像被裁剪了。 两个图像具有相同的尺寸,但修改后的图像出现裁剪。
我假设它可能正在发生:
裁剪 output 的原因是 user3386109 所说的:在编写 output BMP 时,外循环
for (int i = 0; i < width; ++i)
应该迭代到height
,而不是width
。 BMP 从底行开始存储,这就是图像顶部的一部分丢失的原因。
关于过滤的一个小评论:有一个检查似乎打算排除边界处理的一个像素边距,
if (lin !=0 && lin != height && col != 0 && col != width)
请注意,右侧和底部边缘存在差一错误。 由于lin
对lin < height
进行迭代,因此底行是lin == height - 1
,而不是height
。 同样col == width - 1
是最右边的列。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.