Reputation: 37
I'm working on a program that will slightly blur an image in c.
Knowing that I need the average and rgb values of the 8 surrounding pixels and the selected pixel to change the color of that pixel, I've added them together and taken the average.
I know that the way I'm implementing this is not the most efficient way this can be done, so if there are any suggestions on how to simplify this, please let me know.
I plan on copy tempimage
back to image
in a third for-loop at the end.
The struct RGBTRIPLE
contain the rgb values for a pixel.
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
My issue now is dealing with special cases, such as the edges of the image or the pixels on the side.
How can I get the values of the surrounding pixels when the selected pixel is not surrounded by 9 pixels?
Here is my code so far:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// copy all values to temporary image
RGBTRIPLE tempimage[height][width];
int avgRed = 0;
int avgGreen = 0;
int avgBlue = 0;
//copy pixels to temp image
for ( int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
tempimage[x][y] = image[x][y];
}
}
//get average of surrounding pixels
for ( int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
//TODO: edge check
//surrounding pixels
avgRed = round(((float)(image[i][j].rgbtRed
+ image[i][j - 1].rgbtRed + image[i][j + 1].rgbtRed
+ image[i - 1][j].rgbtRed + image[i - 1][j - 1].rgbtRed
+ image[i - 1][j + 1].rgbtRed + image[i + 1][j].rgbtRed
+ image[i + 1][j - 1].rgbtRed + image[i + 1][j + 1].rgbtRed)) / 9);
avgGreen = round(((float)(image[i][j].rgbtGreen
+ image[i][j - 1].rgbtGreen + image[i][j + 1].rgbtGreen
+ image[i - 1][j].rgbtGreen + image[i - 1][j - 1].rgbtGreen
+ image[i - 1][j + 1].rgbtGreen + image[i + 1][j].rgbtGreen
+ image[i + 1][j - 1].rgbtGreen + image[i + 1][j + 1].rgbtGreen)) / 9);
avgBlue = round(((float)(image[i][j].rgbtBlue
+ image[i][j - 1].rgbtBlue + image[i][j + 1].rgbtBlue
+ image[i - 1][j].rgbtBlue + image[i - 1][j - 1].rgbtBlue
+ image[i - 1][j + 1].rgbtBlue + image[i + 1][j].rgbtBlue
+ image[i + 1][j - 1].rgbtBlue + image[i + 1][j + 1].rgbtBlue)) / 9);
tempimage[i][j].rgbtRed = avgRed;
tempimage[i][j].rgbtGreen = avgGreen;
tempimage[i][j].rgbtBlue = avgBlue;
}
}
//TODO: for loop to copy tempimage back to image here
return;
}
Upvotes: 3
Views: 1703
Reputation: 51874
There are various ways of handling 'edge' cases in an algorithm like yours. The code below uses the current 'row' or 'column' (instead of that above/below or left/right of it) if it's on the relevant edge:
for ( int i = 0; i < height; i++)
{
// Edge check (A for 'above' index and B for 'below'):
int A = i - 1; if (A < 0) A = 0;
int B = i + 1; if (B > height - 1) B = height - 1;
for (int j = 0; j < width; j++)
{
// Edge check (L = 'left of', R = 'right of'):
int L = j - 1; if (L < 0) L = 0;
int R = j + 1; if (R > width - 1) R = width - 1;
// Then change all your 'i-1'|'i+i'|'j-i'|j+1' indexes to A|B|L|R:
avgRed = round(((float)(image[i][j].rgbtRed
+ image[i][L].rgbtRed + image[i][R].rgbtRed
+ image[A][j].rgbtRed + image[A][L].rgbtRed
+ image[A][R].rgbtRed + image[B][j].rgbtRed
+ image[B][L].rgbtRed + image[B][R].rgbtRed)) / 9);
// ... and similarly for green and blue ...
Incidentally, I notice you have your pixel indexes as image[column][row] (= column-major order). Conventionally, C
and C++
2D arrays are defined the other way round, as image[row][column] (= row-major order); however, as long as you're sure that's what you have, then no problem!
Upvotes: 2
Reputation: 1
This code in C works well when you consider blurring an image or n*n matxix using box blur. It considers top, bottom and middle rows and calculates the pixels RGB respectively.
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
int sumBlue;
int sumGreen;
int sumRed;
//create a temporary table
RGBTRIPLE temp[height][width];
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
sumBlue = 0;
sumGreen = 0;
sumRed = 0;
//Top row
if (i == 0)
{
if (j == 0) //top row left corner
{
sumBlue = round(ceil(image[i][j].rgbtBlue
+ image[i][j + 1].rgbtBlue
+ image[i + 1][j].rgbtBlue
+ image[i + 1][j + 1].rgbtBlue) / 4);
sumGreen = round(ceil(image[i][j].rgbtGreen
+ image[i][j + 1].rgbtGreen
+ image[i + 1][j].rgbtGreen
+ image[i + 1][j + 1].rgbtGreen) / 4);
sumRed = round(ceil(image[i][j].rgbtRed
+ image[i][j + 1].rgbtRed
+ image[i + 1][j].rgbtRed
+ image[i + 1][j + 1].rgbtRed) / 4);
}
else if (j == width - 1) //top row right corner
{
sumBlue = round(ceil(image[i][j].rgbtBlue
+ image[i][j - 1].rgbtBlue
+ image[i + 1][j].rgbtBlue
+ image[i + 1][j - 1].rgbtBlue) / 4);
sumGreen = round(ceil(image[i][j].rgbtGreen
+ image[i][j - 1].rgbtGreen
+ image[i + 1][j].rgbtGreen
+ image[i + 1][j - 1].rgbtGreen) / 4);
sumRed = round(ceil(image[i][j].rgbtRed
+ image[i][j - 1].rgbtRed
+ image[i + 1][j].rgbtRed
+ image[i + 1][j - 1].rgbtRed) / 4);
}
else //top row middle pixel
{
sumBlue = round(ceil(image[i][j].rgbtBlue
+ image[i][j - 1].rgbtBlue
+ image[i][j + 1].rgbtBlue
+ image[i + 1][j].rgbtBlue
+ image[i + 1][j - 1].rgbtBlue
+ image[i + 1][j + 1].rgbtBlue) / 6);
sumGreen = round(ceil(image[i][j].rgbtGreen
+ image[i][j - 1].rgbtGreen
+ image[i][j + 1].rgbtGreen
+ image[i + 1][j].rgbtGreen
+ image[i + 1][j - 1].rgbtGreen
+ image[i + 1][j + 1].rgbtGreen) / 6);
sumRed = round(ceil(image[i][j].rgbtRed
+ image[i][j - 1].rgbtRed
+ image[i][j + 1].rgbtRed
+ image[i + 1][j].rgbtRed
+ image[i + 1][j - 1].rgbtRed
+ image[i + 1][j + 1].rgbtRed) / 6);
}
}
//Bottom row of image
else if (i == height - 1)
{
if (j == 0) //left side pixel of bottom row
{
sumBlue = round(ceil(image[i][j].rgbtBlue
+ image[i][j + 1].rgbtBlue
+ image[i - 1][j].rgbtBlue
+ image[i - 1][j + 1].rgbtBlue) / 4);
sumGreen = round(ceil(image[i][j].rgbtGreen
+ image[i][j + 1].rgbtGreen
+ image[i - 1][j].rgbtGreen
+ image[i - 1][j + 1].rgbtGreen) / 4);
sumRed = round(ceil(image[i][j].rgbtRed
+ image[i][j + 1].rgbtRed
+ image[i - 1][j].rgbtRed
+ image[i - 1][j + 1].rgbtRed) / 4);
}
else if (j == width - 1) //right side pixel of last row
{
sumBlue = round(ceil(image[i][j].rgbtBlue
+ image[i][j - 1].rgbtBlue
+ image[i - 1][j].rgbtBlue
+ image[i - 1][j - 1].rgbtBlue) / 4);
sumGreen = round(ceil(image[i][j].rgbtGreen
+ image[i][j - 1].rgbtGreen
+ image[i - 1][j].rgbtGreen
+ image[i - 1][j - 1].rgbtGreen) / 4);
sumRed = round(ceil(image[i][j].rgbtRed
+ image[i][j - 1].rgbtRed
+ image[i - 1][j].rgbtRed
+ image[i - 1][j - 1].rgbtRed) / 4);
}
else //middle pixels of last row
{
sumBlue = round(ceil(image[i][j].rgbtBlue
+ image[i][j - 1].rgbtBlue
+ image[i][j + 1].rgbtBlue
+ image[i - 1][j].rgbtBlue
+ image[i - 1][j - 1].rgbtBlue
+ image[i - 1][j + 1].rgbtBlue) / 6);
sumGreen = round(ceil(image[i][j].rgbtGreen
+ image[i][j - 1].rgbtGreen
+ image[i][j + 1].rgbtGreen
+ image[i - 1][j].rgbtGreen
+ image[i - 1][j - 1].rgbtGreen
+ image[i - 1][j + 1].rgbtGreen) / 6);
sumRed = round(ceil(image[i][j].rgbtRed
+ image[i][j - 1].rgbtRed
+ image[i][j + 1].rgbtRed
+ image[i - 1][j].rgbtRed
+ image[i - 1][j - 1].rgbtRed
+ image[i - 1][j + 1].rgbtRed) / 6);
}
}
else
{
if (j == 0) //left side of image
{
sumBlue = round(ceil(image[i][j].rgbtBlue
+ image[i - 1][j].rgbtBlue
+ image[i + 1][j].rgbtBlue
+ image[i][j + 1].rgbtBlue
+ image[i - 1][j + 1].rgbtBlue
+ image[i + 1][j + 1].rgbtBlue) / 6); //6 pixels surrounding the left side of the image
sumGreen = round(ceil(image[i][j].rgbtGreen
+ image[i - 1][j].rgbtGreen
+ image[i + 1][j].rgbtGreen
+ image[i][j + 1].rgbtGreen
+ image[i - 1][j + 1].rgbtGreen
+ image[i + 1][j + 1].rgbtGreen) / 6);
sumRed = round(ceil(image[i][j].rgbtRed
+ image[i - 1][j].rgbtRed
+ image[i + 1][j].rgbtRed
+ image[i][j + 1].rgbtRed
+ image[i - 1][j + 1].rgbtRed
+ image[i + 1][j + 1].rgbtRed) / 6);
}
//Right side of image
else if (j == width - 1)
{
sumBlue = round(ceil(image[i][j].rgbtBlue
+ image[i - 1][j].rgbtBlue
+ image[i + 1][j].rgbtBlue
+ image[i][j - 1].rgbtBlue
+ image[i - 1][j - 1].rgbtBlue
+ image[i + 1][j - 1].rgbtBlue) / 6);
sumGreen = round(ceil(image[i][j].rgbtGreen
+ image[i - 1][j].rgbtGreen
+ image[i + 1][j].rgbtGreen
+ image[i][j - 1].rgbtGreen
+ image[i - 1][j - 1].rgbtGreen
+ image[i + 1][j - 1].rgbtGreen) / 6);
sumRed = round(ceil(image[i][j].rgbtRed
+ image[i - 1][j].rgbtRed
+ image[i + 1][j].rgbtRed
+ image[i][j - 1].rgbtRed
+ image[i - 1][j - 1].rgbtRed
+ image[i + 1][j - 1].rgbtRed) / 6);
}
else //middle pixels of middle rows
{
//calculate for blue pixels
sumBlue = round(ceil(image[i - 1][j - 1].rgbtBlue
+ image[i - 1][j].rgbtBlue
+ image[i - 1][j + 1].rgbtBlue
+ image[i][j - 1].rgbtBlue
+ image[i][j].rgbtBlue
+ image[i][j + 1].rgbtBlue
+ image[i + 1][j - 1].rgbtBlue
+ image[i + 1][j].rgbtBlue
+ image[i + 1][j + 1].rgbtBlue) / 9);
//calculate for green pixels
sumGreen = round(ceil(image[i - 1][j - 1].rgbtGreen
+ image[i - 1][j].rgbtGreen
+ image[i - 1][j + 1].rgbtGreen
+ image[i][j - 1].rgbtGreen
+ image[i][j].rgbtGreen
+ image[i][j + 1].rgbtGreen
+ image[i + 1][j - 1].rgbtGreen
+ image[i + 1][j].rgbtGreen
+ image[i + 1][j + 1].rgbtGreen) / 9); // 9 pixels surrounding the middle one
//calculate for red pixels
sumRed = round(ceil(image[i - 1][j - 1].rgbtRed
+ image[i - 1][j].rgbtRed
+ image[i - 1][j + 1].rgbtRed
+ image[i][j - 1].rgbtRed
+ image[i][j].rgbtRed
+ image[i][j + 1].rgbtRed
+ image[i + 1][j - 1].rgbtRed
+ image[i + 1][j].rgbtRed
+ image[i + 1][j + 1].rgbtRed) / 9);
}
}
//assign temp values with the calculated values
temp[i][j].rgbtBlue = round((sumBlue));
temp[i][j].rgbtGreen = round((sumGreen));
temp[i][j].rgbtRed = round((sumRed));
}
}
//copies values from temporary table and assigns to original image
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
//assiging temp value to original image
image[j][i].rgbtBlue = temp[j][i].rgbtBlue;
image[j][i].rgbtGreen = temp[j][i].rgbtGreen;
image[j][i].rgbtRed = temp[j][i].rgbtRed;
}
}
}
Upvotes: 0