I'm working on a image filter. On the blur filter i need to get data of the neighbor pixels of one pixel to update it's RGB values. To do so I'm using something like:
RGBTRIPLE *neighbors;
int array_size;
if (i == 0 && j == 0) {
array_size = 4;
neighbors = malloc(array_size * sizeof(RGBTRIPLE));
neighbors[0] = image[i][j];
neighbors[1] = image[i][j + 1];
neighbors[2] = image[i + 1][j];
neighbors[3] = image[i][j + 1];
} else if (i == height - 1 && j == 0) {
array_size = 4;
neighbors = malloc(array_size * sizeof(RGBTRIPLE));
neighbors[0] = image[i + 1][j];
neighbors[1] = image[i + 1][j + 1];
neighbors[2] = image[i][j];
neighbors[3] = image[i][j + 1];
}
And having an if statement for each case (top left, top right, bottom left, bottom right, up, left, bottom, right and no corner). But this makes the code extremely big and inefficient. Is there a better way to do so?
The RGBTRIPLE is a pixel struct defined as:
typedef uint8_t BYTE;
typedef struct {
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
If the order of data doesn't matter, you can use loops to count and collect in-range pixels.
RGBTRIPLE *neighbors;
int array_size = 0;
/* count in-range pixels */
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
if (0 <= i + k && i + k < height && 0 <= j + l && j + l < width) {
array_size++;
}
}
}
/* allocate the array */
neighbors = malloc(array_size * sizeof(RGBTRIPLE));
if (neighbors == NULL) {
/* handle error */
}
/* collect pixel values */
int cnt = 0;
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
if (0 <= i + k && i + k < height && 0 <= j + l && j + l < width) {
neighbors[cnt++] = image[i + k][j + l];
}
}
}
And having an if statement for each case (top left, top right, bottom left, bottom right, up, left, bottom, right and no corner). But this makes the code extremely big and inefficient. Is there a better way to do so?
A common technique is to have extra room at the sides so that you can access a default value (to avoid the branches) or a tombstone value of some sort (to simplify the code).
As for slow, you would need to profile to see whether that is true or not. Most branches will be correctly predicted most of the time if the image is big enough.
If it is true that the branches are really slowing you down, then you will have to make the code more complex, e.g. splitting the processing into border/no border cases as #IanAbbott suggests.
Related
I spent several day trying to figure out what's wrong with this function. It actually compile fine but it blurs the image in the wrong way. I believe maybe my numbers or formulas are wrong but after checking it again and again for several hours I cannot figure out what s wrong.
The exercise wants you to blur an image using a 3*3 blur box so adding up the RGB values of the blur box and dividing them by the valid blur box pixels (the ones in side the image boundaries).Then assigning the 'blurred' values to the image.
In my blurred image the blur does not allow to distinguish any figure in the picture. I checked other blur function answers and tried to make and re-make the code from scratch with different variations but nothing seems to work. The code below it seems to me it s the closer to the right solution.
Any help would be very much appreciate.
Sorry for any mistake in my english
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{ // create image copy for holding modifies RGB values
RGBTRIPLE copy[height][width];
for(int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
copy[i][j] = image[i][j];
}
}
// setting variable for holding sum of blur box RGB values
float blurred = 0.0;
float blurgreen = 0.0;
float blurblue = 0.0;
// setting counter for valid blur box pixels
float validpixels = 0.0;
// looping through image rows
for( int i = 0; i < height; i++)
{ // looping through image columns
for(int j = 0; j < width; j++)
{ // looping through blur box rows
for(int r = -1; r < 2; r++)
{ //looping through blur box columns
for(int c = -1; c < 2; c++)
{ // counting only valid blur-box pixels(inside image boundaries)
if(i + c >= 0 && j + r >= 0 && i + c < height && j + r < width)
{ // storing total of blur box RGB values
blurred += copy[i + c][j + r].rgbtRed;
blurgreen += copy[i + c][j + r].rgbtGreen;
blurblue += copy[i + c][j + r].rgbtBlue;
// counting valid pixels total
validpixels ++;
}
}
}
// calculate RGB blurred values and assigning them to image copy
copy[i][j].rgbtRed = round(blurred / validpixels);
copy[i][j].rgbtGreen = round(blurgreen / validpixels);
copy[i][j].rgbtBlue = round(blurblue / validpixels);
}
}
//giving blur values back to image
for(int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j].rgbtRed = copy[i][j].rgbtRed;
image[i][j].rgbtGreen = copy[i][j].rgbtGreen;
image[i][j].rgbtBlue = copy[i][j].rgbtBlue;
}
}
return;
}
You have 2 main issues:
You must re-initialize your blur* variables and also the counter for each pixel. Otherwise you keep summing up more and more pixels. That will basically create an average of the whole image when you get to the end.
You are storing blurred values in the same array where you read the values to blur. That spills the whole purpose of making a copy at all.
Not an issue but could be improved:
Do not use float in your programs. Unless you have some very strict limitations in memory or computing power, you should always use double for floating point numbers.
Counters are best defined as integers, not floating point numbers.
Pointed out by Chux: As your destination is an integer value, you could replace round by lround. Or use integer arithmetics all the way as shown in Chux's answer.
The fixes are marked in the code using //####
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{ // create image copy for holding modifies RGB values
RGBTRIPLE copy[height][width];
for(int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
copy[i][j] = image[i][j];
}
}
// looping through image rows
for( int i = 0; i < height; i++)
{ // looping through image columns
for(int j = 0; j < width; j++)
{ // looping through blur box rows
// setting variable for holding sum of blur box RGB values
//#### Initialize your blurring variables for each pixel you are visiting.
//#### Always use double instead of float except you have specific requirements.
double blurred = 0.0;
double blurgreen = 0.0;
double blurblue = 0.0;
// setting counter for valid blur box pixels
//#### Also re-initialize counter for each pixel
//#### Counters are normally integers, no floating point numbers
size_t validpixels = 0;
for(int r = -1; r < 2; r++)
{ //looping through blur box columns
for(int c = -1; c < 2; c++)
{ // counting only valid blur-box pixels(inside image boundaries)
if(i + c >= 0 && j + r >= 0 && i + c < height && j + r < width)
{ // storing total of blur box RGB values
blurred += copy[i + c][j + r].rgbtRed;
blurgreen += copy[i + c][j + r].rgbtGreen;
blurblue += copy[i + c][j + r].rgbtBlue;
// counting valid pixels total
validpixels ++;
}
}
}
// calculate RGB blurred values and assigning them to image copy
//#### No! Don't store in the copy again. This will disturb
//#### calculation of the other pixels.
image[i][j].rgbtRed = lround(blurred / validpixels);
image[i][j].rgbtGreen = lround(blurgreen / validpixels);
image[i][j].rgbtBlue = lround(blurblue / validpixels);
}
}
//giving blur values back to image
//#### No! Copying again is not required. Results were stored there already
return;
}
Any help would be very much appreciate.
Not a fix to a problem, but a simplification.
//for(int i = 0; i < height; i++) {
// for (int j = 0; j < width; j++) {
// copy[i][j] = image[i][j];
// }
//}
memcpy(copy, image, sizeof copy);
Likewise with final copy back to image. Yet since copy is not needed, just drop this step.
// memcpy(image, copy, sizeof copy);
Do not use sizeof image as that is not the size of the image.
Rather than float math, stay with integer math.
// float blurred = 0.0;
unsigned blurred = 0;
// float validpixels = 0.0;
unsigned validpixels = 0;
...
// Leave as is.
blurred += copy[i + c][j + r].rgbtRed;
...
// copy[i][j].rgbtRed = round(blurred / validpixels);
// Put result in `image[]`
image[i][j].rgbtRed = (blurred + validpixels/2) / validpixels;
Rather than test r in the deepest loop:
{ //looping through blur box columns
for(int c = -1; c < 2; c++)
{ // counting only valid blur-box pixels(inside image boundaries)
if(i + c >= 0 && j + r >= 0 && i + c < height && j + r < width)
{ // storing total of blur box RGB values
blurred += copy[i + c][j + r].rgbtRed;
blurgreen += copy[i + c][j + r].rgbtGreen;
blurblue += copy[i + c][j + r].rgbtBlue;
// counting valid pixels total
validpixels ++;
}
}
}
Move the test and reset the validpixels
unsigned blurred = 0;
unsigned blurgreen = 0;
unsigned blurblue = 0;
unsigned validpixels = 0;
for(int r = -1; r < 2; r++) {
// Add
if(!(j + r >= 0 && j + r < width)) continue;
for(int c = -1; c < 2; c++) {
// if(i + c >= 0 && j + r >= 0 && i + c < height && j + r < width)
if(i + c >= 0 && i + c < height) {
blurred += copy[i + c][j + r].rgbtRed;
blurgreen += copy[i + c][j + r].rgbtGreen;
blurblue += copy[i + c][j + r].rgbtBlue;
validpixels ++;
}
}
}
Advanced
Division can be expensive in time. As the vast majority of divisions is by 9, consider:
image[i][j].rgbtRed = validpixels == 9 ?
(blurred + 9/2) / 9 :
(blurred + validpixels/2) / validpixels;
With optimizations turned on, the compiler is certain to create faster code with a fixed divisor of 9, even with the validpixels == 9 overheard.
I am receiving a Segmentation fault (core dumped) error when trying to blur an image, but I cannot find out why. To achieve a blur, I loop through each element in the 2x2 image array. I then check each of the 9x9 squares around & including it - if they exist, their RGB values are added to a sum (sumRed, sumGreen, sumBlue) for each color. I also increment a counter called numPixel each time this is successful so I can average the RGB values at the end.
There are other parts of the code, but I am certain that this blur() function is causing the segfault. This is because when I comment out the body of the function, the segfault goes away.
However, within the function I do not see what is triggering the segfault. I don't think I'm going out of bound in an array, which has been the cause of most of my segfaults in the past. From commenting out certain portions of the code, I also gathered that memcpy() is not the cause of the error (or at least not the only cause).
There's also a custom header file, which includes definitions for BYTE and RGBTRIPLE:
typedef uint8_t BYTE;
...
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
The actual code is:
// TODO: Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE new_image[height][width];
BYTE sumRed, sumGreen, sumBlue;
BYTE numPixels;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; w++)
{
sumRed = sumGreen = sumBlue = 0;
numPixels = 0;
// Check from 1 higher to 1 lower
for (int h = i - 1; h <= i + 1; h++)
{
// Check from 1 left to 1 right
for (int w = j - 1; w <= j + 1; j++)
{
// If neither index is out of bound, add neighboring RGB values
if (0 <= h < height && 0 <= w < width)
{
sumRed += image[h][w].rgbtRed;
sumGreen += image[h][w].rgbtGreen;
sumBlue += image[h][w].rgbtBlue;
numPixels++;
}
}
}
new_image[i][j].rgbtRed = (BYTE) sumRed / numPixels;
new_image[i][j].rgbtGreen = (BYTE) sumGreen / numPixels;
new_image[i][j].rgbtBlue = (BYTE) sumBlue / numPixels;
}
}
memcpy(&image[0][0], &new_image[0][0], sizeof(image[0][0]) * height * width);
return;
}
Be sure of your logic, not relying on braces to save the day. Use simple short names in "local context". "Ease of reading" trumps being "Overly explicit."
for (int h = 0; h < height; h++)
for (int w = 0; w < width; w++) {
// bigger accumulators, short names, declared & init'd locally
uint16_t sumR = 0;
uint16_t sumG = 0;
uint16_t sumB = 0;
int nPix = 0;
for (int hO = -1; hO <= 1; hO++) // height offset range
for (int wO = -1; wO <= 1; wO++) { // width offset range
int indH = h + hO; // Simple!
int indW = w + wO;
if (0 <= indH && indH < height && 0 <= indW && indW < width) {
RGBTRIPLE *p = &image[ indH ][ indW ]; // short alias
sumR += p->rgbtRed;
sumG += p->rgbtGreen;
sumB += p->rgbtBlue;
nPix++;
}
}
new_image[i][j].rgbtRed = (BYTE)( sumR / nPix );
new_image[i][j].rgbtGreen = (BYTE)( sumG / nPix );
new_image[i][j].rgbtBlue = (BYTE)( sumB / nPix );
}
/* memcpy....*/
I'm still uneasy with possible confusion between "Height/width" and "vertical/Horizontal".
Here's an alternative for the two inner loops. Don't bother to set-up the width if the height is out-of-frame...
// From -1 offset, examine >>3<< pixels: -1, 0, 1...
for( int ih = h-1, limH = ih+3; ih < limH; ih++ ) { // height range
if( ih < 0 || height <= ih ) continue;
for( int iw = w-1, limW = iw+3; iw < limW; iw++) { // width range
if( iw < 0 || width <= iw ) continue;
RGBTRIPLE *p = &image[ ih ][ iw ]; // short alias
sumR += p->rgbtRed;
sumG += p->rgbtGreen;
sumB += p->rgbtBlue;
nPix++;
}
}
I got this error when I tried to look particular value exist or not. I used a custom data type called RGBTRIPLE that cs50 provides me. If the value is not exist in the memory I will get 'segmentation fault' because I need to find out top left, top middle, top right, value that I have its previous value and next value, bottom left, bottom middle, bottom right value. So for that I used a function called isNull. It will check whether the value exists in the memory or not. If it is not null It will return 1, otherwise 0.
Here is my code
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// entering the array of the image
for (int i = 0; i < height; i++)
{
// entering the array of the row
for (int j = 0; j < width; j++)
{
/* blur: the element we select we need to get the value
of its neighbour value and adding this all including it
then get the avg value of pixel that need to set
*/
int element = 0;
int blueSum = 0;
int greenSum = 0;
int redSum = 0;
RGBTRIPLE pixels[] = {
image[i][j], image[i][j - 1], image[i][j + 1],
image[i - 1][j - 1], image[i - 1][j], image[i - 1][i + 1],
image[i + 1][j - 1], image[i + 1][j], image[i + 1][j + 1]
};
for (int k = 0; k < 9; k++)
{
if (isNull(pixels[k]) == 1)
{
element++;
blueSum += pixels[k].rgbtBlue;
greenSum += pixels[k].rgbtGreen;
redSum += pixels[k].rgbtRed;
}
}
image[i][j].rgbtBlue = round(blueSum / element);
image[i][j].rgbtGreen = round(greenSum / element);
image[i][j].rgbtRed = round(redSum / element);
}
}
return;
}
// check whether it is null or not
int isNull(RGBTRIPLE pixel)
{
if (pixel != 0)
{
return 1;
}
return 0;
}
Error I got:
$ make filter
helpers.c:142:15: error: invalid operands to binary expression ('RGBTRIPLE' and 'int')
if (pixel != 0)
~~~~~ ^ ~
1 error generated.
make: *** [Makefile:2: filter] Error 1
the type RGBTRIPLE is defined in bmp.h as:
/**
* RGBTRIPLE
*
* This structure describes a color consisting of relative intensities of
* red, green, and blue.
*
* Adapted from http://msdn.microsoft.com/en-us/library/aa922590.aspx.
*/
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
It is a structure: you cannot compare structures with the == operator, you must compare members individually.
The problem is: what do you mean by check whether it is null or not?
If you mean "is the pixel black?", you should test if all 3 components are 0:
// check whether it is black or not
int isBlack(RGBTRIPLE pixel) {
return ((pixel.rgbtBlue | pixel.rgbtGreen | pixel.rgbtRed) == 0);
}
You get a segmentation fault because you read pixels beyond the boundaries of the matrix image:
the 6th initializer image[i - 1][i + 1] has a typo
you must make special cases for the image boundaries (i == 0, j == 0, i == height - 1 and j == width - 1).
Here is a simple fix:
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a < b ? b : a; }
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// entering the array of the image
for (int i = 0; i < height; i++) {
// entering the array of the row
for (int j = 0; j < width; j++) {
/* blur: compute the new color by averaging the components
of all pixels in a 3x3 area around the pixel.
assume that pixel colors continue beyond the image
borders.
*/
unsigned blueSum = 0;
unsigned greenSum = 0;
unsigned redSum = 0;
int i1 = max(0, i - 1);
int i2 = min(height - 1, i + 1);
int j1 = max(0, j - 1);
int j2 = min(width - 1, j + 1);
RGBTRIPLE pixels[] = {
image[i][j1], image[i][j], image[i][j2],
image[i1][j1], image[i1][j], image[i1][j2],
image[i2][j1], image[i2][j], image[i2][j2]
};
for (int k = 0; k < 9; k++) {
blueSum += pixels[k].rgbtBlue;
greenSum += pixels[k].rgbtGreen;
redSum += pixels[k].rgbtRed;
}
image[i][j].rgbtBlue = round(blueSum / 9);
image[i][j].rgbtGreen = round(greenSum / 9);
image[i][j].rgbtRed = round(redSum / 9);
}
}
}
Note however that the above function cannot work as coded because it overwrites the pixel values that will be used for the next column and for the next row. To perform this transformation in place, you can use a 3 line buffer to keep the previous values.
Here is a modified version:
typedef unsigned char BYTE;
typedef struct {
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} RGBTRIPLE;
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE row[3][width + 2];
// populate the initial the row cache
row[1][0] = row[2][0] = image[0][0];
row[1][width + 1] = row[2][width + 1] = image[0][width - 1];
for (int j = 0; j < width; j++) {
row[1][j + 1] = row[2][j + 1] = image[0][j];
}
// entering the array of the image
for (int i = 0; i < height; i++) {
// update the row cache
for (int j = 0; j < width + 2; j++) {
row[0][j] = row[1][j];
row[1][j] = row[2][j];
}
if (i < height - 2) {
row[2][0] = image[i + 1][0];
row[2][width + 1] = image[i + 1][width - 1];
for (int j = 0; j < width; j++)
row[2][j + 1] = image[i + 1][j + 1];
}
// update the image row
for (int j = 0; j < width; j++) {
/* blur: compute the new color by averaging the components
of all pixel values in a 3x3 area around the pixel.
Assume that pixel colors are extended beyond the image
borders.
*/
unsigned blueSum = 0;
unsigned greenSum = 0;
unsigned redSum = 0;
for (int ii = 0; ii < 3; ii++) {
for (int jj = j; jj < j + 3; jj++) {
blueSum += row[ii][jj].rgbtBlue;
greenSum += row[ii][jj].rgbtGreen;
redSum += row[ii][jj].rgbtRed;
}
}
image[i][j].rgbtBlue = (BYTE)((blueSum + 4) / 9);
image[i][j].rgbtGreen = (BYTE)((greenSum + 4) / 9);
image[i][j].rgbtRed = (BYTE)((redSum + 4) / 9);
}
}
}
You cannot compare scalar types with a struct or an array. That is what the error message is telling you.
What condition should be true to make a struct of multiple unrelated bytes to compare with a numerical value?
That's not how it works. You can only compare the fields separately or compare whole struct with another variable of same struct type.
Besides that, you have a few misconceptions in your code.
If the value is not exist in the memory I will get 'segmentation fault'
You got a segmentation fault because the memory you want to read is not your memory. You have no access privileges to read or write.
It will check whether the value exists in the memory or not.
If you provide some value to a function, it will always "exist in memory". You have provided a value in the calling function. How would it not exist?
You cannot detect if the memory location where you copied it from was valid by just looking at the copied value.
Your underlying problem is that you do not verify that you are withing bounds of your array before reading the values.
You must compare row and column index with the limits and only access the array element if you are not out of bounds.
You need to rework your approach to collect pixels to blur.
Hey, so I been stuck on the cs50 pst4 for a while now, specifically on blur.
The goal is to create a filter which blurs the image by changing each pixel to the average of the ones surrounding it.
What I did first is create a copy of the image so that I wouldn't use the changed pixels when calculating the average.
To calculate the sides and the corners i made the colors of pixels outside of the picture to 0. Then I could blindly add it and divide by however many pixels are there for ex. corners have 4 pixels surrounding it so i divide by 4, edges by 6 etc.
To get the positions I looped around image[i][j] from [i - 1][j - 1] to [i + 1][j + 1]
However it seems that the right and bottom right side aren't being calculated correctly.
#include "helpers.h"
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE copy[height][width];
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
for(int n = 0; n < 9; n++)
{
copy[i][j].rgbtRed = image[i][j].rgbtRed;
copy[i][j].rgbtGreen = image[i][j].rgbtGreen;
copy[i][j].rgbtBlue = image[i][j].rgbtBlue;
}
}
}
int rgbtRed, rgbtGreen, rgbtBlue;
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
bool corner = false;
rgbtRed = rgbtGreen = rgbtBlue = 0;
for(int n = i - 1; n <= i + 1; n++)
{
for (int k = j - 1; k <= j + 1; k++)
{
if(n < 0 || n > height || k < 0 || k > width)
{
copy[n][k].rgbtRed = copy[n][k].rgbtGreen = copy[n][k].rgbtBlue = 0;
}
rgbtRed += copy[n][k].rgbtRed;
rgbtGreen += copy[n][k].rgbtGreen;
rgbtBlue += copy[n][k].rgbtBlue;
}
}
if ((i == 0 && (j == 0 || j == width)) || (i == height && (j == 0 || j == width)))
{
image[i][j].rgbtRed = (rgbtRed / 4);
image[i][j].rgbtGreen = (rgbtGreen / 4);
image[i][j].rgbtBlue = (rgbtBlue / 4);
corner = true;
}
else if (!corner && (i == 0 || i == height || j == 0 || j == width))
{
image[i][j].rgbtRed = (rgbtRed / 6);
image[i][j].rgbtGreen = (rgbtGreen / 6);
image[i][j].rgbtBlue = (rgbtBlue / 6);
}
else
{
image[i][j].rgbtRed = (rgbtRed / 9);
image[i][j].rgbtGreen = (rgbtGreen / 9);
image[i][j].rgbtBlue = (rgbtBlue / 9);
}
}
}
Thankful for anyhelp provided
From the question it is not clear how the right and bottom right side aren't being calculated correctly. I run the your code and the output is decent from my point of view. Though it gives some runtime error.
Here are some suggestions.
if (n < 0 || n > height || k < 0 || k > width)
{
copy[n][k].rgbtRed = copy[n][k].rgbtGreen = copy[n][k].rgbtBlue = 0;
}
rgbtRed += copy[n][k].rgbtRed;
rgbtGreen += copy[n][k].rgbtGreen;
rgbtBlue += copy[n][k].rgbtBlue;
I think you are trying to setup a special handling for the boundary case. For the upper limit, isn't it should be n >= height, since it is zero-based index? Moreover, you don't have to explicitly set the pixel to black. Just ignore it and don't add them to the average value is fine. But you didn't stop there and followed by rgbtRed += copy[n][k].rgbtRed. n could be -1 or > height, it could hit array index out of bound.
Also, you setup a if statement with 3 conditions for edge, corner, and inbound case. You don't need that. You only need to know how many pixel are inbound. Take that number as the divisor for the average formula. Below is my example.
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE copy[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
for (int n = 0; n < 9; n++)
{
copy[i][j].rgbtRed = image[i][j].rgbtRed;
copy[i][j].rgbtGreen = image[i][j].rgbtGreen;
copy[i][j].rgbtBlue = image[i][j].rgbtBlue;
}
}
}
int rgbtRed, rgbtGreen, rgbtBlue;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
rgbtRed = rgbtGreen = rgbtBlue = 0;
// number of pixel is within boundary
int inbound = 0;
for (int n = i - 1; n <= i + 1; n++)
{
for (int k = j - 1; k <= j + 1; k++)
{
if (n >= 0 && n < height && k >= 0 && k < width)
{
rgbtRed += copy[n][k].rgbtRed;
rgbtGreen += copy[n][k].rgbtGreen;
rgbtBlue += copy[n][k].rgbtBlue;
inbound++;
}
}
}
image[i][j].rgbtRed = (rgbtRed / inbound);
image[i][j].rgbtGreen = (rgbtGreen / inbound);
image[i][j].rgbtBlue = (rgbtBlue / inbound);
}
}
}
$ ./filter -b ./images/courtyard.bmp outfile.bmp
Result
I am working on the CS50 filter challenge and specifically the blur challenge.
It compiles nicely, but when I create the image the image is turned 90 degrees and at the bottom of the image is an image error.
Do you know what the problem is?
This is my code:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
float sum_blue;
float sum_green;
float sum_red;
float counter;
RGBTRIPLE temp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
sum_blue = 0;
sum_green = 0;
sum_red = 0;
counter = 0;
for (int h= -1; h < 2; h++)
{
if (j + h < 0 || j + h > width - 1)
{
continue;
}
for (int v = -1; v < 2; v++)
{
if (i + v < 0 || i + v > height - 1)
{
continue;
}
sum_red += image[j + h][i + v].rgbtRed;
sum_blue += image[j + h][i + v].rgbtBlue;
sum_green += image[j + h][i + v].rgbtGreen;
counter++;
}
}
//summarize all values and save the pixels in a temporary image to transfer it later
temp[i][j].rgbtRed = round(sum_red / counter);
temp[i][j].rgbtBlue = round(sum_blue / counter);
temp[i][j].rgbtGreen = round(sum_green / counter);
}
}
// transfer temporary to real image
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j].rgbtRed = temp[i][j].rgbtRed;
image[i][j].rgbtBlue = temp[i][j].rgbtBlue;
image[i][j].rgbtGreen = temp[i][j].rgbtGreen;
}
}
}
You appear to have swapped width and height here:
sum_red += image[j + h][i + v].rgbtRed;
sum_blue += image[j + h][i + v].rgbtBlue;
sum_green += image[j + h][i + v].rgbtGreen;
I would expect:
sum_red += image[i + v][j + h].rgbtRed;
sum_blue += image[i + v][j + h].rgbtBlue;
sum_green += image[i + v][j + h].rgbtGreen;
since the image array is [height][width] and i is the vertical iterator and j the horizontal. Possibly only i and j are swapped, and i + h and j + v are intended.
Possibly the variables are swapped elsewhere in the algorithm. Better variable naming might help - so the names indicate what they represent. Even x and y would be clearer since that is a convention for cartesian coordinates - though a comment indicating top-left origin and y increasing down might be advisable.
By getting the indexes in the wrong order you have rotated and mirrored it and processed data from the wrong part of the image or not in the image at all.