Reputation: 225
I've created program in C witch reads .bmp
file and apply on it blur effect. Algorithm is simple. Read file, separate each colour channel and do channel convolution with given matrix.My image is 24 bits per pixel.Here is result of my program: https://i.sstatic.net/jZ331.jpg while this is original https://i.sstatic.net/6gTX3.jpg . I think I'm making error when accessing data in separate channels, but I have no idea how I can do this. I know that rows
and cols
contain number of pixels not bytes but when I multiply this by 3 I get segmentation-fault on channelBlur[y*cols+x] = toWrite
. I'm compile this with gcc -m32 ...
Below are structures and code used to read file and process image:
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;
Load function:
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;
}
And naive separate channel and combine function:
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;
}
createNewImage
works properly
Allocating channels:
unsigned char* redBlur = (unsigned char*)malloc(infoHeader.imgSizeBytes);
unsigned char* greenBlur = (unsigned char*)malloc(infoHeader.imgSizeBytes);
unsigned char* blueBlur = (unsigned char*)malloc(infoHeader.imgSizeBytes);
Here is the problematic function:
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;
}
}
}
Upvotes: 1
Views: 3484
Reputation: 79033
There are several problems. Some might apply in your case, some might not (depending on specific image and processor architecture):
First, separateChannel and combineChannel don't work properly. You only access every third byte of the array. It should be (and similarly for combineChannel):
void separateChannels(const IMAGE src, unsigned int nPixels, unsigned char* red, unsigned char* green, unsigned char* blue)
{
unsigned int i, j;
for(i = 0, j = 0; i < nPixels; i++, j = j + 3)
{
blue[i] = src[j];
green[i] = src[j + 1];
red[i] = src[j + 2];
}
}
The allocated arrays for the three channels can be accordingly smaller.
Next, you seem to process a BGR file, i.e. every pixel requires 3 bytes. Part of the BMP standard is that the size of every row is rounded to a multiple of 4 bytes so that each pixel rows starts on a double word boundary.
Next, I assume that you run the code on a little endian processor architecture. Otherwise, your code for reading the BMP header is invalid.
Finally, the BMP format covers a wide range of image types but your code only handles 24-bit per pixel, top to bottom BGR files.
Upvotes: 1