C语言中位图文件的像素操作
我已经用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
.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]
依此类推。@JongwarenPixels=BITMAPINFOHEADER.imgSizeBytes
我知道这个变量名是错误的…加载函数工作正常,我在代码中执行图像翻转,得到正确的输出。如果你不调用ApplyFilterChannel
,结果图像是否正常?它应该与原始图像相同。@Michael Walz是的,如果我只调用CombineChannels
并作为参数传递提取的颜色通道,我会得到原始图像。正如您指出的,我已经更改了separetchannels
和CombineChannels
,但这仍然没有解决问题。作为nPixels
变量,我正在传递值形式bitmapinfo.imgSizeBytes代码>。知道每行的舍入后,如何正确读取通道值/@Ufo:see