Reputation: 11
Here is a grayscale BMP image as input This is my input for the sobel operator. A grayscale BMP image.
My output, however seems to get a bit weird. Output with sobel operator
The output seems to cut off a section of the image and puts it in the beginning.
Below is my code.
int sobeloperator(const char* inputimage, const char* outputimage)
{
const int Gx[3][3] = {
{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1}
};
const int Gy[3][3] = {
{-1, -2, -1},
{0, 0, 0},
{1, 2, 1}
};
BMPHeader header;
BMPInfoHeader infoHeader;
uint8_t* inputPixels;
uint8_t* outputPixels;
ifstream inFile(inputimage, ios::in | ios::binary);
if (!inFile.is_open()) {
cerr << "Error: Unable to open input file." << endl;
return 1;
}
// Read BMP header
inFile.read(reinterpret_cast<char*>(&header), sizeof(header));
if (header.type != 0x4D42) {
cerr << "Error: Invalid BMP file format." << endl;
return 1;
}
// Read BMP info header
inFile.read(reinterpret_cast<char*>(&infoHeader), sizeof(infoHeader));
if (infoHeader.bpp != 8) {
cerr << "Error: Only 8-bit BMP images are supported." << endl;
return 1;
}
char colors[1024] = { 0 };
for (int i = 0; i < 256; i++)
{
colors[i * 4] = (char)i;
colors[i * 4 + 1] = (char)i;
colors[i * 4 + 2] = (char)i;
}
inputPixels = new uint8_t[infoHeader.width * infoHeader.height];
outputPixels = new uint8_t[infoHeader.width * infoHeader.height];
inFile.read(reinterpret_cast<char*>(inputPixels), infoHeader.width * infoHeader.height);
for (int y = 0; y < infoHeader.height; y++)
{
for (int x = 0; x < infoHeader.width; x++)
{
int GxSum = 0;
int GySum = 0;
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
// get pixel value at current kernel position
int pos = (y + k) * infoHeader.width + (x + l); //current pos, infoHeader.width is a row, multiplied by y+k = current row.
if (pos < 0 || pos >= infoHeader.width * infoHeader.height || y <= 0 || y >= infoHeader.height || x <= 0 || x >= infoHeader.width) {
continue;
}
// add pixel value multiplied by Sobel kernel value to Gx and Gy sums
GxSum += Gx[k+1][l+1] * inputPixels[pos];
GySum += Gy[k+1][l+1] * inputPixels[pos];
}
}
int gradientMagnitude = sqrt(GxSum * GxSum + GySum * GySum);
// clip gradient magnitude to 8-bit range
if (gradientMagnitude <= 128)
{
gradientMagnitude = 0;
}
else
{
gradientMagnitude = 255;
}
//gradientMagnitude = min(255, max(0, gradientMagnitude));
// set output pixel to gradient magnitude
outputPixels[y * infoHeader.width + x] = gradientMagnitude;
}
}
infoHeader.sizeImage = infoHeader.width * infoHeader.height;
header.size = sizeof(header) + sizeof(infoHeader) + sizeof(colors) + infoHeader.sizeImage;
header.offset = sizeof(header) + sizeof(infoHeader) + sizeof(colors);
printf("\n\nbpp = %d\n", infoHeader.bpp);
printf("compression = %d", infoHeader.compression);
// Write output BMP file
ofstream outFile("sobel.bmp", ios::out | ios::binary);
if (!outFile.is_open()) {
cerr << "Error: Unable to create output file." << endl;
return 1;
}
outFile.write(reinterpret_cast<char*>(&header), sizeof(header));
outFile.write(reinterpret_cast<char*>(&infoHeader), sizeof(infoHeader));
outFile.write(colors, 1024);
outFile.write(reinterpret_cast<char*> (outputPixels), infoHeader.sizeImage);
delete[] inputPixels;
delete[] outputPixels;
inFile.close();
outFile.close();
return 0;
}
I've reviewed the code multiple times, re-read on how to apply the sobel operator, reviewed the portion where I apply the sobel operator, but I can't seem to be able to find a solution for my problem.
Upvotes: 0
Views: 43
Reputation: 2776
I would have preferred to comment instead of reply but i lack the reputation to do so.
Yet I think that your issue lies in "edge effects" : in your inner loop there
int pos = (y + k) * infoHeader.width + (x + l); //current pos, infoHeader.width is a row, multiplied by y+k = current row.
you are accessing pixels out of your image area.
In order to fix your problem there is many possibilities according to what you actually want to do. Basically you have to give values for pixels out of the image area. You may set a constant value (0 for instance), repeat the valid line/column but other strategies are possible. You may also choose to compute the output image only on valid pixels (you will have an output image smaller than the input one).
In terms of coding, there is also several possibilities:
You may find more mathematical insight about edge handling for instance there (though it does speak about strategy for setting values outside the image).
Upvotes: 0