C语言中位图文件的像素操作

C语言中位图文件的像素操作,c,image-processing,memory-management,bitmap,C,Image Processing,Memory Management,Bitmap,我已经用C语言创建了一个程序,它读取.bmp文件并应用模糊效果。算法简单。读取文件,分离每个颜色通道,用给定的矩阵进行通道卷积。我的图像是每像素24位。这是我的程序的结果:这是原始的。我想我在访问单独通道中的数据时出错了,但我不知道如何才能做到这一点。我知道行和列包含像素数而不是字节数,但当我将其乘以3时,我在channelBlur[y*cols+x]=toWrite上得到分段错误。我是用gcc-m32编译的…下面是用于读取文件和处理图像的结构和代码: typedef struct __attr

我已经用C语言创建了一个程序,它读取
.bmp
文件并应用模糊效果。算法简单。读取文件,分离每个颜色通道,用给定的矩阵进行通道卷积。我的图像是每像素24位。这是我的程序的结果:这是原始的。我想我在访问单独通道中的数据时出错了,但我不知道如何才能做到这一点。我知道
包含像素数而不是字节数,但当我将其乘以3时,我在
channelBlur[y*cols+x]=toWrite上得到分段错误。我是用gcc-m32编译的…

下面是用于读取文件和处理图像的结构和代码:

typedef struct __attribute__((__packed__))
{
    WORD fType;
    DWORD byteSize;
    WORD reserved1;
    WORD reserved2;
    DWORD offsetToImage;

}BITMAPHEADER;

typedef struct __attribute__((__packed__))
{
    DWORD structSize;
    LONG width;
    LONG height;
    WORD planes;
    WORD bitsPerPix;
    DWORD compression;
    DWORD imgSizeBytes;
    LONG pixPerMeterX;
    LONG pixPerMeterY;
    DWORD colorUsd;
    DWORD colorImp;
}BITMAPINFOHEADER;

typedef unsigned char* IMAGE;
加载函数:

IMAGE loadImg(const char* filename, BITMAPINFOHEADER* infoHeader)
{
    FILE* fImg;
    BITMAPHEADER header;
    IMAGE bitmap;

    fImg = fopen(filename,"rb");
    if(fImg == NULL)
        return NULL;

    fread(&header,sizeof(BITMAPHEADER),1,fImg);
    if(header.fType != 0x4D42)
    {
        fclose(fImg);
        return NULL;
    }

    fread(infoHeader,sizeof(BITMAPINFOHEADER),1,fImg);
    fseek(fImg,header.offsetToImage, SEEK_SET);

    bitmap = (unsigned char*)malloc(infoHeader->imgSizeBytes);
    fread(bitmap,infoHeader->imgSizeBytes,1,fImg);
    fclose(fImg);    
    return bitmap;
}
void separateChannels(const IMAGE src,unsigned int nPixels, unsigned char* red, unsigned char* green,unsigned char* blue)
{
    PIXEL pix;
    unsigned int i;
    for(i=0;i<nPixels;i=i+3)
    {
        blue[i] = src[i];
        green[i] = src[i+1];
        red[i] = src[i+2];
    }  
}

IMAGE combineChannels(unsigned char* red, unsigned char* green,unsigned char* blue, unsigned int nPixels, BITMAPINFOHEADER infoHeader)
{    
    IMAGE image = createNewImage(infoHeader);
    unsigned int i;
    for(i=0;i<nPixels;i=i+3)
    {
        image[i] = blue[i];
        image[i+1] = green[i];
        image[i+2] = red[i];
    }
    return image;
}
void applyFilterOnChannel(const unsigned char* channel,unsigned char* channelBlur ,unsigned int cols,unsigned int rows, const float* filter)
{
    unsigned int x;
    unsigned int y;

    for(y=0;y<cols;++y)
    {
        for(x=0;x<rows;++x)
        {
            float value = 0;
            unsigned int filterX;
            unsigned int filterY;
            for(filterY=0;filterY<filterSize/2;++filterY)
            {
                for(filterX=0;filterX<filterSize/2;++filterX)
                {
                    int pixelPosY = min(max(y+filterY,0),(int)rows-1);
                    int pixelPosX = min(max(x+filterX,0),(int)cols-1);

                    float pixelVal = (float)channel[pixelPosY*cols+pixelPosX];
                    float filterVal = filter[(filterY+filterSize/2)*filterSize+filterX+filterSize/2];
                    value += pixelVal*filterVal;
                }
            }
            unsigned char toWrite = (unsigned char)value;
            channelBlur[y*cols+x] = toWrite;
        }
    }
}
和朴素的分离通道和组合功能:

IMAGE loadImg(const char* filename, BITMAPINFOHEADER* infoHeader)
{
    FILE* fImg;
    BITMAPHEADER header;
    IMAGE bitmap;

    fImg = fopen(filename,"rb");
    if(fImg == NULL)
        return NULL;

    fread(&header,sizeof(BITMAPHEADER),1,fImg);
    if(header.fType != 0x4D42)
    {
        fclose(fImg);
        return NULL;
    }

    fread(infoHeader,sizeof(BITMAPINFOHEADER),1,fImg);
    fseek(fImg,header.offsetToImage, SEEK_SET);

    bitmap = (unsigned char*)malloc(infoHeader->imgSizeBytes);
    fread(bitmap,infoHeader->imgSizeBytes,1,fImg);
    fclose(fImg);    
    return bitmap;
}
void separateChannels(const IMAGE src,unsigned int nPixels, unsigned char* red, unsigned char* green,unsigned char* blue)
{
    PIXEL pix;
    unsigned int i;
    for(i=0;i<nPixels;i=i+3)
    {
        blue[i] = src[i];
        green[i] = src[i+1];
        red[i] = src[i+2];
    }  
}

IMAGE combineChannels(unsigned char* red, unsigned char* green,unsigned char* blue, unsigned int nPixels, BITMAPINFOHEADER infoHeader)
{    
    IMAGE image = createNewImage(infoHeader);
    unsigned int i;
    for(i=0;i<nPixels;i=i+3)
    {
        image[i] = blue[i];
        image[i+1] = green[i];
        image[i+2] = red[i];
    }
    return image;
}
void applyFilterOnChannel(const unsigned char* channel,unsigned char* channelBlur ,unsigned int cols,unsigned int rows, const float* filter)
{
    unsigned int x;
    unsigned int y;

    for(y=0;y<cols;++y)
    {
        for(x=0;x<rows;++x)
        {
            float value = 0;
            unsigned int filterX;
            unsigned int filterY;
            for(filterY=0;filterY<filterSize/2;++filterY)
            {
                for(filterX=0;filterX<filterSize/2;++filterX)
                {
                    int pixelPosY = min(max(y+filterY,0),(int)rows-1);
                    int pixelPosX = min(max(x+filterX,0),(int)cols-1);

                    float pixelVal = (float)channel[pixelPosY*cols+pixelPosX];
                    float filterVal = filter[(filterY+filterSize/2)*filterSize+filterX+filterSize/2];
                    value += pixelVal*filterVal;
                }
            }
            unsigned char toWrite = (unsigned char)value;
            channelBlur[y*cols+x] = toWrite;
        }
    }
}
下面是有问题的函数:

IMAGE loadImg(const char* filename, BITMAPINFOHEADER* infoHeader)
{
    FILE* fImg;
    BITMAPHEADER header;
    IMAGE bitmap;

    fImg = fopen(filename,"rb");
    if(fImg == NULL)
        return NULL;

    fread(&header,sizeof(BITMAPHEADER),1,fImg);
    if(header.fType != 0x4D42)
    {
        fclose(fImg);
        return NULL;
    }

    fread(infoHeader,sizeof(BITMAPINFOHEADER),1,fImg);
    fseek(fImg,header.offsetToImage, SEEK_SET);

    bitmap = (unsigned char*)malloc(infoHeader->imgSizeBytes);
    fread(bitmap,infoHeader->imgSizeBytes,1,fImg);
    fclose(fImg);    
    return bitmap;
}
void separateChannels(const IMAGE src,unsigned int nPixels, unsigned char* red, unsigned char* green,unsigned char* blue)
{
    PIXEL pix;
    unsigned int i;
    for(i=0;i<nPixels;i=i+3)
    {
        blue[i] = src[i];
        green[i] = src[i+1];
        red[i] = src[i+2];
    }  
}

IMAGE combineChannels(unsigned char* red, unsigned char* green,unsigned char* blue, unsigned int nPixels, BITMAPINFOHEADER infoHeader)
{    
    IMAGE image = createNewImage(infoHeader);
    unsigned int i;
    for(i=0;i<nPixels;i=i+3)
    {
        image[i] = blue[i];
        image[i+1] = green[i];
        image[i+2] = red[i];
    }
    return image;
}
void applyFilterOnChannel(const unsigned char* channel,unsigned char* channelBlur ,unsigned int cols,unsigned int rows, const float* filter)
{
    unsigned int x;
    unsigned int y;

    for(y=0;y<cols;++y)
    {
        for(x=0;x<rows;++x)
        {
            float value = 0;
            unsigned int filterX;
            unsigned int filterY;
            for(filterY=0;filterY<filterSize/2;++filterY)
            {
                for(filterX=0;filterX<filterSize/2;++filterX)
                {
                    int pixelPosY = min(max(y+filterY,0),(int)rows-1);
                    int pixelPosX = min(max(x+filterX,0),(int)cols-1);

                    float pixelVal = (float)channel[pixelPosY*cols+pixelPosX];
                    float filterVal = filter[(filterY+filterSize/2)*filterSize+filterX+filterSize/2];
                    value += pixelVal*filterVal;
                }
            }
            unsigned char toWrite = (unsigned char)value;
            channelBlur[y*cols+x] = toWrite;
        }
    }
}
void applyFilterOnChannel(常量无符号字符*通道、无符号字符*通道模糊、无符号整数列、无符号整数行、常量浮点*过滤器)
{
无符号整数x;
无符号整数y;

对于(y=0;y有几个问题。有些可能适用于您的情况,有些可能不适用(取决于特定的映像和处理器体系结构):

首先,separateChannel和combineChannel不能正常工作。只能访问数组的每三个字节。它应该是(对于combineChannel也是如此):

void分隔通道(常量图像src、无符号整数像素、无符号字符*红色、无符号字符*绿色、无符号字符*蓝色)
{
无符号整数i,j;
对于(i=0,j=0;i
为这三个通道分配的阵列可以相应地更小

接下来,您似乎要处理一个BGR文件,即每个像素需要3个字节。BMP标准的一部分是将每行的大小舍入为4字节的倍数,以便每个像素行从双字边界开始

接下来,我假设您在一个小小的endian处理器体系结构上运行代码,否则,用于读取BMP头的代码无效


最后,BMP格式涵盖了广泛的图像类型,但您的代码只处理每像素24位的自上而下BGR文件。

如何计算
nPixels
(如果这是宽度*高度,则在处理过程中不应跳过3。)此外,请仔细检查:读取文件后,立即将其写回。这会使其失真吗?当您分离和组合通道时,您的索引是错误的。在循环中,您应仅将
i
增加一,然后计算索引,如
image[3*i+2]=red[i]
依此类推。@Jongware
nPixels=BITMAPINFOHEADER.imgSizeBytes
我知道这个变量名是错误的…加载函数工作正常,我在代码中执行图像翻转,得到正确的输出。如果你不调用
ApplyFilterChannel
,结果图像是否正常?它应该与原始图像相同。@Michael Walz是的,如果我只调用
CombineChannels
并作为参数传递提取的颜色通道,我会得到原始图像。正如您指出的,我已经更改了
separetchannels
CombineChannels
,但这仍然没有解决问题。作为
nPixels
变量,我正在传递值形式
bitmapinfo.imgSizeBytes。知道每行的舍入后,如何正确读取通道值/@Ufo:see