I am trying to write a function that applies a sepia filter to the images,
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for(int i=0; i<height; i++)
{
for(int j=0; j<width; j++)
{
int r = image[i][j].rgbtRed;
int g = image[i][j].rgbtGreen;
int b = image[i][j].rgbtBlue;
image[i][j].rgbtRed = round((0.393 * r) + (0.769 * g) + (0.189 * b));
image[i][j].rgbtGreen = round((0.349 * r) + (0.686 * g) + (0.168 * b));
image[i][j].rgbtBlue = round((0.272 * r) + (0.534 * g) + (0.131 * b));
if(image[i][j].rgbtRed > 255)
{
image[i][j].rgbtRed = 255;
}
if(image[i][j].rgbtGreen > 255)
{
image[i][j].rgbtGreen = 255;
}
if(image[i][j].rgbtBlue > 255)
{
image[i][j].rgbtBlue = 255;
}
}
}
}
when I used this code, it does not raise any error, but the if conditions do not work at all, and the resulting image has many creepy pixels.
but when I used intermediate variables like this code below:
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for(int i=0; i<height; i++)
{
for(int j=0; j<width; j++)
{
int r = image[i][j].rgbtRed;
int g = image[i][j].rgbtGreen;
int b = image[i][j].rgbtBlue;
int sr = round((0.393 * r) + (0.769 * g) + (0.189 * b));
int sg = round((0.349 * r) + (0.686 * g) + (0.168 * b));
int sb = round((0.272 * r) + (0.534 * g) + (0.131 * b));
if(sr > 255)
{
sr = 255;
}
if(sg > 255)
{
sg = 255;
}
if(sb > 255)
{
sb = 255;
}
image[i][j].rgbtRed = sr;
image[i][j].rgbtGreen = sg;
image[i][j].rgbtBlue = sb;
}
}
}
the if statements worked perfectly.
my question is what is wrong in the first code that makes the if statements don't work?
image[i][j].rgbtRed > 255 is never true as .rgbtRed is 8-bit. Use an int to save the sum.
The structure members are eight-bit unsigned integers. When you assign to them, values over 255 are lost. (They are wrapped modulo 256.)
When you assign to the intermediate int variables, they retain the full values.
Related
In my open source project ( https://github.com/mmj-the-fighter/GraphicsLabFramework ) i am trying to add a image smoothening box filter for NxN kernel size. I have already implemented the algorithm for 3x3 kernel size. As you can see from the source code below I am not processing the image for edges. Using this logic, for a 5x5 kernel size I have to skip two rows or columns from top, right, bottom and left of the image. So the edges will not be blurred. Is there any other solution.
Here is the code:
/*applying a box filter of size 3x3*/
void blur_image(unsigned char *img, int width, int height)
{
int n = width * height;
int i, j;
int r, g, b;
int x, y;
float v = 1.0 / 9.0;
float kernel[3][3] =
{
{ v, v, v },
{ v, v, v },
{ v, v, v }
};
unsigned char* resimage = (unsigned char *)malloc(width * height * 4 * sizeof(unsigned char));
memcpy(resimage, img, width*height * 4);
for (x = 1; x < width - 1; ++x) {
for (y = 1; y < height - 1; ++y) {
float bs = 0.0;
float gs = 0.0;
float rs = 0.0;
for (i = -1; i <= 1; ++i) {
for (j = -1; j <= 1; ++j){
float weight = (float)kernel[i + 1][j + 1];
unsigned char* buffer = img + width * 4 * (y + j) + (x + i) * 4;
bs += weight * *buffer;
gs += weight * *(buffer + 1);
rs += weight * *(buffer + 2);
}
}
unsigned char* outbuffer = resimage + width * 4 * y + x * 4;
*outbuffer = bs;
*(outbuffer + 1) = gs;
*(outbuffer + 2) = rs;
*(outbuffer + 3) = 255;
}
}
memcpy(img, resimage, width*height * 4);
free(resimage);
}
I use the following structures to load in memory a bmp image:
// header
typedef struct {
uint16_t type; // Magic identifier
uint32_t size; // File size in bytes
uint16_t reserved1; // Not used
uint16_t reserved2; // Not used
uint32_t offset;
uint32_t header_size; // Header size in bytes
uint32_t width; // Width of the image
uint32_t height; // Height of image
uint16_t planes; // Number of color planes
uint16_t bits; // Bits per pixel
uint32_t compression;// Compression type
uint32_t imagesize; // image size in bytes
uint32_t xresol; // pixels per meter
uint32_t yresol; // pixels per meter
uint32_t ncolours; // nr of colours
uint32_t importantcolours; // important colours
} BMP_Header;
// image details
typedef struct {
BMP_Header header;
uint64_t data_size;
uint64_t width;
uint64_t height;
uint8_t *data;// allocate memory based on width and height
} BMP_Image;
Then I want to apply a gaussian filter over it.
The functions associated is the following:
double gaussianModel(double x, double y, double variance) {
return 1 / (2 * 3.14159 * pow(variance, 2)) * exp(-(x * x + y * y) / (2 * variance * variance));
}
double *generate_weights(int radius, double variance, int bits_nr) {
double *weights = (double*)malloc(sizeof(double) * radius * radius * bits_nr);
double sum = 0;
for (int i = 0; i < radius; i++) {
for (int j = 0; j < radius * bits_nr; j++) {
weights[i * radius * bits_nr + j] = gaussianModel(i - radius / 2, j - radius / 2, variance);
sum += weights[i * radius + j];
}
}
// normalize
for (int i = 0; i < radius * radius; i++)
weights[i] /= sum;
return weights;
}
double getWeightedColorValue(double *w, int len, unsigned int index, unsigned int bits_nr) {
double sum = 0;
for (int i = index; i < len; i+= bits_nr)
sum += w[i];
return sum;
}
BMP_Image* BMP_blur_collapsed(BMP_Image *img, unsigned int bits_nr, unsigned int radius, unsigned int th_number, FILE* f) {
BMP_Image *bluredImg = malloc(sizeof(BMP_Image));
bluredImg->header = img->header;
bluredImg->data_size = (img->header.size - sizeof(BMP_Header)) * bits_nr;
bluredImg->width = img->header.width;
bluredImg->height = img->header.height;
bluredImg->data = malloc(sizeof(uint8_t) * bluredImg->data_size);
for(uint64_t i = 0; i < bluredImg->data_size; ++i)
bluredImg->data[i] = img->data[i];
double variance = 1.94;
double* weights = generate_weights(radius, variance, bits_nr);
uint64_t i, j;
double start, end;
start = omp_get_wtime();
#pragma omp parallel for private(i, j) collapse(2) schedule(static) num_threads(th_number)
for (i = 0; i < img->height - radius; i++) {
for (j = 0; j < img->width * bits_nr - radius - bits_nr * 2; j+= bits_nr ) {
uint64_t ofs = i * img->width * bits_nr + j;
double *distributedColorRed = (double*)malloc(sizeof(double) * radius * radius * bits_nr);
double *distributedColorGreen = (double*)malloc(sizeof(double) * radius * radius * bits_nr);
double *distributedColorBlue = (double*)malloc(sizeof(double) * radius * radius * bits_nr);
for (int wx = 0; wx < radius; wx++) {
for (int wy = 0; wy < radius * bits_nr; wy += bits_nr) {
uint64_t wofs = wx * img->width * bits_nr + wy;
// double currWeight = weights[wx * radius + wy];
distributedColorRed[wofs] = weights[wx * radius + wy] * img->data[ofs];
distributedColorGreen[wofs + 1] = weights[wx * radius + wy + 1] * img->data[ofs + 1];
distributedColorBlue[wofs + 2] = weights[wx * radius + wy + 2] * img->data[ofs + 2];
}
}
bluredImg->data[ofs] = getWeightedColorValue(distributedColorRed, radius * radius * bits_nr, 0, bits_nr);
bluredImg->data[ofs + 1] = getWeightedColorValue(distributedColorGreen, radius * radius * bits_nr, 1, bits_nr);
bluredImg->data[ofs + 2] = getWeightedColorValue(distributedColorBlue, radius * radius * bits_nr, 2, bits_nr);
free(distributedColorRed);
free(distributedColorBlue);
free(distributedColorGreen);
}
}
end = omp_get_wtime();
fprintf(f, "blur collapsed %f \n", end - start);
free(weights);
return bluredImg;
}
Assuming that img is a BMP_Image object, then img->data has stored all the pixels inside it:
img->data[i] is Red
img->data[i + 1] is Green
img->data[i + 2] is Blue
But the output is not the expected one after I use this function.
Your image convolution with filtering coefficients looks weird.
One is because you use the variable bits_nr
in the calculation which makes the indexing complicated.
It will be more comprehensible to handle the color components r, g, and
b separately.
The variable name variance is not appropriate because variance = sigma ** 2.
You don't need to apply the multiplication with 1/sqrt(2*PI)/sigma
in gaussianModel() because it is cancelled in the normalization.
Here is an example of fully compilable code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#define SIGMA 1.94
#define RADIUS 5
#define INFILE "0Jayx.bmp"
#define OUTFILE "blurred.bmp"
// header
typedef struct __attribute__((__packed__)) {
uint16_t type; // Magic identifier
uint32_t size; // File size in bytes
uint16_t reserved1; // Not used
uint16_t reserved2; // Not used
uint32_t offset;
uint32_t header_size; // Header size in bytes
uint32_t width; // Width of the image
uint32_t height; // Height of image
uint16_t planes; // Number of color planes
uint16_t bits; // Bits per pixel
uint32_t compression;// Compression type
uint32_t imagesize; // image size in bytes
uint32_t xresol; // pixels per meter
uint32_t yresol; // pixels per meter
uint32_t ncolours; // nr of colours
uint32_t importantcolours; // important colours
} BMP_Header;
// image details
typedef struct {
BMP_Header header;
uint64_t width;
uint64_t height;
uint8_t *b;
uint8_t *g;
uint8_t *r;
} BMP_Image;
double gaussianModel(double x, double y, double sigma) {
return 1. / exp(-(x * x + y * y) / (2 * sigma * sigma));
}
double *generate_coeff(int radius, double sigma) {
double *coeff = malloc(sizeof(double) * radius * radius);
double sum = 0;
for (int i = 0; i < radius; i++) {
for (int j = 0; j < radius; j++) {
coeff[i * radius + j] = gaussianModel(i - radius / 2, j - radius / 2, sigma);
sum += coeff[i * radius + j];
}
}
// normalize
for (int i = 0; i < radius * radius; i++)
coeff[i] /= sum;
return coeff;
}
BMP_Image *BMP_blur_collapsed(BMP_Image *img, int radius, double sigma) {
BMP_Image *bimg = malloc(sizeof(BMP_Image));
bimg->header = img->header;
bimg->width = img->header.width;
bimg->height = img->header.height;
bimg->b = malloc(bimg->width * bimg->height);
bimg->g = malloc(bimg->width * bimg->height);
bimg->r = malloc(bimg->width * bimg->height);
int b, g, r;
double *coeff = generate_coeff(radius, sigma);
int i, j, m, n;
for (i = 0; i < img->height - radius; i++) {
for (j = 0; j < img->width - radius; j++) {
b = g = r = 0;
for (m = 0; m < radius; m++) {
for (n = 0; n < radius; n++) {
b += coeff[m * radius + n] * img->b[(i + m) * img->width + (j + n)];
g += coeff[m * radius + n] * img->g[(i + m) * img->width + (j + n)];
r += coeff[m * radius + n] * img->r[(i + m) * img->width + (j + n)];
}
}
bimg->b[i * bimg->width + j] = b;
bimg->g[i * bimg->width + j] = g;
bimg->r[i * bimg->width + j] = r;
}
}
free(coeff);
return bimg;
}
void free_img(BMP_Image *img)
{
free(img->b);
free(img->g);
free(img->r);
free(img);
}
BMP_Image *read_bmp_file(char *filename)
{
FILE *fp;
int i, j, bytesperline;
BMP_Image *img;
img = malloc(sizeof(BMP_Image));
if (NULL == (fp = fopen(filename, "r"))) {
perror(filename);
exit(1);
}
fread(&img->header, sizeof(char), sizeof(BMP_Header), fp);
img->width = img->header.width;
img->height = img->header.height;
bytesperline = ((img->width * 3 + 3) / 4) * 4; // word alignment
img->b = malloc(img->width * img->height);
img->g = malloc(img->width * img->height);
img->r = malloc(img->width * img->height);
for (i = 0; i < img->height; i++) {
for (j = 0; j < img->width; j++) {
img->b[i * img->width + j] = getc(fp);
img->g[i * img->width + j] = getc(fp);
img->r[i * img->width + j] = getc(fp);
}
for (j = img->width * 3; j < bytesperline; j++) {
getc(fp);
}
}
return img;
}
void write_bmp_file(BMP_Image *img, char *filename)
{
FILE *fp;
int i, j, bytesperline;
if (NULL == (fp = fopen(filename, "w"))) {
perror(filename);
exit(1);
}
bytesperline = ((img->width * 3 + 3) / 4) * 4; // word alignment
fwrite(&img->header, sizeof(char), sizeof(BMP_Header), fp);
for (i = 0; i < img->height; i++) {
for (j = 0; j < img->width; j++) {
putc(img->b[i * img->width + j], fp);
putc(img->g[i * img->width + j], fp);
putc(img->r[i * img->width + j], fp);
}
for (j = img->width * 3; j < bytesperline; j++) {
putc(0, fp);
}
}
}
int main()
{
BMP_Image *img = read_bmp_file(INFILE);
BMP_Image *bimg = BMP_blur_collapsed(img, RADIUS, SIGMA);
write_bmp_file(bimg, OUTFILE);
free_img(img);
free_img(bimg);
return 0;
}
The produced image with radius=5, sigma=1.94:
[Edit]
To modify the code to support 32bit bmp file:
remove the bytesperline relevant codes.
append uint8_t *a; to the struct BMP_Image.
find the b, g, r pixel processing codes and append the a processing
thereafter (just by changing the variable name).
If you are familiar with the patch command, below is the patch file
which can be applied with:
patch -u < gauss.diff
to convert my previous source code to the 32bit version.
(You will need to modify the filenames in the 1st and the 2nd line
according to the source filename you work with.)
gauss.diff:
-- gauss.c.O 2021-12-09 08:57:36.504685533 +0900
+++ gauss.c 2021-12-09 09:49:57.342895501 +0900
## -36,6 +36,7 ##
uint8_t *b;
uint8_t *g;
uint8_t *r;
+ uint8_t *a;
} BMP_Image;
double gaussianModel(double x, double y, double sigma) {
## -67,25 +68,28 ##
bimg->b = malloc(bimg->width * bimg->height);
bimg->g = malloc(bimg->width * bimg->height);
bimg->r = malloc(bimg->width * bimg->height);
+ bimg->a = malloc(bimg->width * bimg->height);
- int b, g, r;
+ int b, g, r, a;
double *coeff = generate_coeff(radius, sigma);
int i, j, m, n;
for (i = 0; i < img->height - radius; i++) {
for (j = 0; j < img->width - radius; j++) {
- b = g = r = 0;
+ b = g = r = a = 0;
for (m = 0; m < radius; m++) {
for (n = 0; n < radius; n++) {
b += coeff[m * radius + n] * img->b[(i + m) * img->width + (j + n)];
g += coeff[m * radius + n] * img->g[(i + m) * img->width + (j + n)];
r += coeff[m * radius + n] * img->r[(i + m) * img->width + (j + n)];
+ a += coeff[m * radius + n] * img->r[(i + m) * img->width + (j + n)];
}
}
bimg->b[i * bimg->width + j] = b;
bimg->g[i * bimg->width + j] = g;
bimg->r[i * bimg->width + j] = r;
+ bimg->a[i * bimg->width + j] = a;
}
}
free(coeff);
## -98,13 +102,15 ##
free(img->b);
free(img->g);
free(img->r);
+ free(img->a);
free(img);
}
BMP_Image *read_bmp_file(char *filename)
{
FILE *fp;
- int i, j, bytesperline;
+// int i, j, bytesperline;
+ int i, j;
BMP_Image *img;
img = malloc(sizeof(BMP_Image));
## -117,21 +123,25 ##
img->width = img->header.width;
img->height = img->header.height;
- bytesperline = ((img->width * 3 + 3) / 4) * 4; // word alignment
+// bytesperline = ((img->width * 3 + 3) / 4) * 4; // word alignment
img->b = malloc(img->width * img->height);
img->g = malloc(img->width * img->height);
img->r = malloc(img->width * img->height);
+ img->a = malloc(img->width * img->height);
for (i = 0; i < img->height; i++) {
for (j = 0; j < img->width; j++) {
img->b[i * img->width + j] = getc(fp);
img->g[i * img->width + j] = getc(fp);
img->r[i * img->width + j] = getc(fp);
+ img->a[i * img->width + j] = getc(fp);
}
+/*
for (j = img->width * 3; j < bytesperline; j++) {
getc(fp);
}
+*/
}
return img;
}
## -139,13 +149,14 ##
void write_bmp_file(BMP_Image *img, char *filename)
{
FILE *fp;
- int i, j, bytesperline;
+// int i, j, bytesperline;
+ int i, j;
if (NULL == (fp = fopen(filename, "w"))) {
perror(filename);
exit(1);
}
- bytesperline = ((img->width * 3 + 3) / 4) * 4; // word alignment
+// bytesperline = ((img->width * 3 + 3) / 4) * 4; // word alignment
fwrite(&img->header, sizeof(char), sizeof(BMP_Header), fp);
for (i = 0; i < img->height; i++) {
## -153,10 +164,13 ##
putc(img->b[i * img->width + j], fp);
putc(img->g[i * img->width + j], fp);
putc(img->r[i * img->width + j], fp);
+ putc(img->a[i * img->width + j], fp);
}
+/*
for (j = img->width * 3; j < bytesperline; j++) {
putc(0, fp);
}
+*/
}
}
I wrote code for the sepia function of the filter pset. The code compiles without any errors but the output image is not entirely sepia. However, after I wrote the code in different way it works fine. Can someone explain why this happens?
First code:
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
RGBTRIPLE pixel={0,0,0};
RGBTRIPLE pix = image[i][j];
pixel.rgbtBlue = round(0.272 * pix.rgbtRed + 0.534 * pix.rgbtGreen + 0.131 * pix.rgbtBlue);
pixel.rgbtGreen = round(0.349 * pix.rgbtRed + 0.686 * pix.rgbtGreen + 0.168 * pix.rgbtBlue);
pixel.rgbtRed = round(0.393 * pix.rgbtRed + 0.769 * pix.rgbtGreen + 0.189 * pix.rgbtBlue);
if(pixel.rgbtBlue > 255)
{
pixel.rgbtBlue = 255;
}
if(pixel.rgbtGreen > 255)
{
pixel.rgbtGreen = 255;
}
if(pixel.rgbtRed > 255)
{
pixel.rgbtRed = 255;
}
image[i][j] = pixel;
}
}
return;
}
first code output image:
Second Code:
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int red = image[i][j].rgbtRed;
int green = image[i][j].rgbtGreen;
int blue = image[i][j].rgbtBlue;
//calculate sepia values
int sepiaRed = round(.393 * red + .769 * green + .189 * blue);
if(sepiaRed > 255)
{
sepiaRed = 255;
}
int sepiaGreen = round(.349 * red + .686 * green + .168 * blue);
if(sepiaGreen > 255)
{
sepiaGreen = 255;
}
int sepiaBlue = round(.272 * red + .534 * green + .131 * blue);
if(sepiaBlue > 255)
{
sepiaBlue = 255;
}
image[i][j].rgbtRed = sepiaRed;
image[i][j].rgbtGreen = sepiaGreen;
image[i][j].rgbtBlue = sepiaBlue;
}
}
return;
}
Second code output:
The difference between the two versions is that the type in which you compute the new pixel value
In the first version the type is whatever the constituent members of RGBTRIPLE are - which I assume is an unsigned 8-bit integer.
pixel.rgbtBlue = round(0.272 * pix.rgbtRed + 0.534 * pix.rgbtGreen + 0.131 * pix.rgbtBlue);
In this line (and the equivalents for green and red pixels),
the value can exceeded 255 which then gets truncated by assignment to an 8-bit unsigned int on assignment to pixel.rgbtBlue.
The following clamp to saturation:
if(pixel.rgbtBlue > 255)
{
pixel.rgbtBlue = 255;
}
Will always excute false, as pixel.rgbtBlue cannot hold a value bigger than 255.
In the second version of the code, an int is used, which is larger, and in which truncation does not occur, allowing the clamp-to-255 to work correct.
As people above already comment, the first one has a truncated value in the if conditions, as the avarage operation is resulting in a number bigger than 255... That's why the filter does not work properly.
I would consider as well less "if/else" on the second one, using perhaps a "Ternary Operator", for a cleaner code:
image[i][j].rgbtGreen = (sepiaGreen > 255) ? 255 : sepiaGreen;
image[i][j].rgbtRed = (sepiaRed > 255) ? 255 : sepiaRed;
image[i][j].rgbtBlue = (sepiaBlue > 255) ? 255 : sepiaBlue;
I am doing cs50 pset4 sepia filter. The tests results from check50 show that the last two tests fail, but all the other tests are okay. I can't figure out what is the problem, because the expected output and my actual output are the same.
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float orginalRed = image[i][j].rgbtRed;
float originalGreen = image[i][j].rgbtGreen;
float originalBlue = image[i][j].rgbtBlue;
float spRed = round(.393 * orginalRed + .769 * originalGreen + .189 * originalBlue);
float spGreen = round(.349 * orginalRed + .686 * originalGreen + .168 * originalBlue);
float spBlue = round(.272 * orginalRed + .534 * originalGreen + .131 * originalBlue);
if (spRed > 255.0)
{
spRed = 225;
}
if (spBlue > 255.0)
{
spBlue = 255;
}
if (spGreen > 255.0)
{
spGreen = 255;
}
image[i][j].rgbtRed = spRed;
image[i][j].rgbtGreen = spGreen;
image[i][j].rgbtBlue = spBlue;
}
}
}
The one thing sticking out is that you set red to 225 if it exceeds 255. That looks wrong.
Anyway, simplify:
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
RGBTRIPLE x = image[i][j];
#define X(r, g, b) fmin(255, round(r * x.rgbtRed + g * x.rgbtGreen + b * x.rgbtBlue))
image[i][j].rgbtRed = X(.393, .769, .189);
image[i][j].rgbtGreen = X(.349, .686, .168);
image[i][j].rgbtBlue = X(.272, .534, .131);
#undef X
}
}
}
If you look closely at the results from the 2 check50 tests that were wrong, line 7-9 of the expected output is:
255 251 195
255 255 214
255 255 232
Then lines 7-9 of the actual output are:
225 251 195
225 255 214
225 255 232
The red values of the actual output should have been rounded to 255 instead of 225. The bug is at line 17, where you say:
spRed = 225; instead of spRed = 255;
I also replaced the if statements with a ternary operator and replaced the use of variables orginalRed, orginalBlue, and orginalGreen with the actual pixel values, for better run time and simplicity.
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int x = 0; x < width; x++)
{
float spRed = round(.393 * image[i][x].rgbtRed + .769 * image[i][x].rgbtGreen + .189 * image[i][x].rgbtBlue);
float spGreen = round(.349 * image[i][x].rgbtRed + .686 * image[i][x].rgbtGreen + .168 * image[i][x].rgbtBlue);
float spBlue = round(.272 * image[i][x].rgbtRed + .534 * image[i][x].rgbtGreen + .131 * image[i][x].rgbtBlue);
image[i][x].rgbtRed = (spRed < 255) ? spRed : 255;
image[i][x].rgbtBlue = (spBlue < 255) ? spBlue : 255;
image[i][x].rgbtGreen = (spGreen < 255) ? spGreen : 255;
}
}
return;
}
The arrays could be the problem also you just return maybe it waits you to return 0 extra. But usually main problem in c I think arrays.
Have you use allocate memorty for this array : image[i][j]
Hi to everyone who did CS50,
Currently, I am doing pset4 filter, reflect and struggling with the code I wrote. It compiles fine, but the output picture looks like the one that I attached. Has any a clue for me how I could fix this? (If possible without the solution; a hint is totally fine :))
#include "helpers.h"
#include <stdio.h>
#include <math.h>
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < (height - 1); i++)
{
for (int j = 0; j < (width - 1); j++)
{
//get the average
float average = 0;
average = (image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3;
//set color channels with the average value
image[i][j].rgbtRed = round(average);
image[i][j].rgbtGreen = round(average);
image[i][j].rgbtBlue = round(average);
}
}
return;
}
// Convert image to sepia
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < (height - 1); i++)
{
for (int j = 0; j < (width - 1); j++)
{
//calculate the new values
float red = 0;
float green = 0;
float blue = 0;
red = .393 * image[i][j].rgbtRed + .769 * image[i][j].rgbtGreen + .189 * image[i][j].rgbtBlue;
if (round(red) > 255)
{
image[i][j].rgbtRed = 255;
}
else if (round(red <= 255))
{
image[i][j].rgbtRed = red;
}
green = .349 * image[i][j].rgbtRed + .686 * image[i][j].rgbtGreen + .168 * image[i][j].rgbtBlue;
if (round(green) > 255)
{
image[i][j].rgbtGreen = 255;
}
else if (round(green) <= 255)
{
image[i][j].rgbtGreen = green;
}
blue = .272 * image[i][j].rgbtRed + .534 * image[i][j].rgbtGreen + .131 * image[i][j].rgbtBlue;
if (round(blue) > 255)
{
image[i][j].rgbtBlue = 255;
}
else if (round(blue) <= 255)
{
image[i][j].rgbtBlue = blue;
}
}
}
return;
}
// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < (height - 1); i++)
{
//RGBTRIPLE
int a[width - 1 /2];
int b[width - 1 /2];
int c[width - 1 /2];
for (int j = 0; j < ((width/2) - 1); j++)
{
a[j] = image[i][(width - 1) - j].rgbtRed;
b[j] = image[i][(width - 1) - j].rgbtGreen;
c[j] = image[i][(width - 1) - j].rgbtBlue;
}
// GERADE / UNGERADE ZAHLEN VERARBEITEN
for (int n = 0; (n + (width - 1) /2) < (width - 1); n++)
{
image[i][((width - 1)/2) - n].rgbtRed = image[i][((width - 1)/2) - n].rgbtRed;
image[i][((width - 1)/2) - n].rgbtGreen = image[i][((width - 1)/2) - n].rgbtGreen;
image[i][((width - 1)/2) - n].rgbtBlue = image[i][((width - 1)/2) - n].rgbtBlue;
}
for (int m = 0; m < ((width/2) - 1); m++)
{
image[i][m].rgbtRed = a[m];
image[i][m].rgbtRed = b[m];
image[i][m].rgbtRed = c[m];
}
}
return;
}
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
return;
}
Input:
./filter -r stadium.bmp outfile.bmp
(stadium.bmp is just a file that I choose. You can choose any file as the input)
Output: compiles successfully, please see attached pictureenter image description here
Your code is too complicated. You do not need to divide image into RGB values. You need to swap the image values from left to right or vice versa to achieve reflection.
For this you may need to create a temporary data structure which is the same as "image".
RGBTRIPLE temp[width];
With temp, you need to store values from image, and swap them. Following is a design pattern which you can use.
//Pseudo code
1. //Loop though the row of an image (start from row = 0). We need to iterate every row.
2. // Loop through the height of an image to save current row in an image to the temp.
3. // Swap the values in image by using the temp.
If you want to filter this one dimensional image below.
val1, val2, valn, val3, val4
After reflection filter, it will be like this.
val4, val3, valn, val2, val1