invalid operands to binary expression ('RGBTRIPLE' and 'int') - c

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.

Related

C issue, blur filter not working properly

Got a problem with code in C, the purpose is to blur given image working as a filter. The code reads height and width from RGBTRIPLE bmp.h file, makes a copy of each pixel in advance to compute the average in the middle pixel (when its 3x3 pixels chunk) or the boundary pixel's average (when its 2x3 chunk). I nested for-loops, 2 outer ones to copy each pixel from 'image', defined there 4 integers (3 doubles, 1 int.) to count each pixel's red, green and blue. The last int. is named counter to be my denominator in division.
The problem occurs not in syntax, but on the image. 4 down rows of pixels are like rainbow, each is different, not blurred. And the image is darkened.
When I don't use the pixels' copy it seems to work fine.
// Blur image
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++)
{
// make a copy of rgbtriple image
copy[i][j].rgbtRed = image[i][j].rgbtRed;
copy[i][j].rgbtGreen = image[i][j].rgbtGreen;
copy[i][j].rgbtBlue = image[i][j].rgbtBlue;
// i need to ensure that image's pixels wont be out of bounds of rows/columns
// it's inappropriate to have static division by 9 because sometimes there will be less pixels to divide by
double sumRed = 0;
double sumGreen = 0;
double sumBlue = 0;
int count = 0;
for (int ii = i - 1; ii <= i + 1; ii++)
{
for (int jj = j - 1; jj <= j + 1; jj++)
{
if (ii >= 0 && ii < height && jj >= 0 && jj < width)
{
sumRed += copy[ii][jj].rgbtRed;
sumGreen += copy[ii][jj].rgbtGreen;
sumBlue += copy[ii][jj].rgbtBlue;
count++;
}
}
}
if (count != 0 && count <= 9)
{
image[i][j].rgbtRed = round(sumRed / count);
image[i][j].rgbtGreen = round(sumGreen / count);
image[i][j].rgbtBlue = round(sumBlue / count);
}
}
}
return;
}
Thanks in advance!
You compute the new value of the image pixels from the data in the copy matrix, but you did not copy the whole image before hand, only pixel values up to the current pixel. Hence the results are incorrect.
You should copy the whole image in a separate loop or using memcpy.
Here is a modified version:
#include <string.h>
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width]) {
RGBTRIPLE copy[height][width];
// make a copy of rgbtriple image
#if 1 // using memcpy
memcpy(copy, image, sizeof(copy));
#else
// if you cannot use memcpy
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
copy[i][j] = image[i][j];
}
}
#endif
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Mix the color values with the adjacent pixels
// making sure the pixels are inside the image.
// It is inappropriate to always divide by 9
// because depending on the pixel position and image size
// count can be 1, 2, 3, 4, 6 or 9
double sumRed = 0;
double sumGreen = 0;
double sumBlue = 0;
int count = 0;
for (int ii = i - 1; ii <= i + 1; ii++) {
for (int jj = j - 1; jj <= j + 1; jj++) {
if (ii >= 0 && ii < height && jj >= 0 && jj < width) {
sumRed += copy[ii][jj].rgbtRed;
sumGreen += copy[ii][jj].rgbtGreen;
sumBlue += copy[ii][jj].rgbtBlue;
count++;
}
}
}
// no need to test count: there is at least one pixel
image[i][j].rgbtRed = round(sumRed / count);
image[i][j].rgbtGreen = round(sumGreen / count);
image[i][j].rgbtBlue = round(sumBlue / count);
}
}
}

Dynamically allocate 2-dimensional structure array in C

I have been trying to create an edges filter as per CS50 problem set 4. I have seen several solutions, however I would like to know if my approach can work. I'm trying to expand the input image by a black border of one pixel width. For this I want to expand my two-dimensional RGBTRIPLE structure by one pixel on either side. I am setting all values of RGB to 0 (aka black) in the first line and then copy the original image into the temporary structure, substituting all except the border values with the respective colours.
I am defining a variable-length two-dimensional structure RGBTRIPLE which contains three values of the datatype BYTE:
RGBTRIPLE temp[height+2][width+2] = {};
I'm getting the error message that because of the variable length it may not have been initialized, which I understand. I have seen several solutions using pointers and malloc, which I hopefully implemented correctly in the first line. I have been trying to connect the RGBTRIPLE to the pointer as per the following two lines:
RGBTRIPLE *ptr = (RGBTRIPLE *)malloc((height+2)*(width+2)*sizeof(RGBTRIPLE));
RGBTRIPLE temp[height+2][width+2] = &ptr;
temp[height+2][width+2] = {0};
Setting all the values to zero here does also not work, but that's another issue.
I want to use the original RGBTRIPLE in a for-loop and I cannot get this to work. All examples I have seen use the pointers afterwards to add any information. Is there any way to define the RGBTRIPLE using malloc so that I can afterwards use it in code as a "normal" element of the structure as seen with temp[][]:
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
temp[i+1][j+1] = image[i][j];
}
}
for(int i = 1; i <= height; i++)
{
for(int j = 1; j <= width; j++)
{
int counter = 0;
float gxr, gxb, gxg, gyr, gyb, gyg = 0;
//right pixel
gxb += (2*temp[i][j+1].rgbtBlue);
gxg += (2*temp[i][j+1].rgbtGreen);
gxr += (2*temp[i][j+1].rgbtRed);
etc. for all surrounding pixels.
Any help is appreciated.
You might initialize as in the following sample code.
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char BYTE;
typedef struct tagRGBTRIPLE
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} RGBTRIPLE;
int main()
{
int height = 400;
int width = 600;
RGBTRIPLE img[height][width];
RGBTRIPLE temp[height+2][width+2];
for (int i = 0; i < height; i++) /* Build a sample image file */
{
for (int j = 0; j < width; j++)
{
img[i][j].rgbtRed = 68;
img[i][j].rgbtGreen = 188;
img[i][j].rgbtBlue = 32;
}
}
for (int i = 0; i < (height + 2); i++) /* Initialize the temporary RGBTRIPLE structure*/
for (int j = 0; j < (width + 2); j++)
{
temp[i][j].rgbtRed = 0;
temp[i][j].rgbtGreen = 0;
temp[i][j].rgbtBlue = 0;
}
for(int i = 0; i < height; i++) /* Imported code from the issue */
{
for(int j = 0; j < width; j++)
{
temp[i+1][j+1] = img[i][j];
}
}
for(int i = 0; i <= (height + 2); i++) /* Right and left edges*/
{
float gxr = 0, gxb = 0, gxg = 0;
temp[i][0].rgbtRed = gxr;
temp[i][0].rgbtGreen = gxg;
temp[i][0].rgbtBlue = gxb;
temp[i][width + 1].rgbtRed = gxr;
temp[i][width + 1].rgbtGreen = gxg;
temp[i][width + 1].rgbtBlue = gxb;
}
for(int i = 0; i <= (width + 2); i++) /* Top and bottom edges */
{
float gyr = 0, gyb = 0, gyg = 0;
temp[0][i].rgbtRed = gyr;
temp[0][i].rgbtGreen = gyg;
temp[0][i].rgbtBlue = gyb;
temp[height + 1][i].rgbtRed = gyr;
temp[height + 1][i].rgbtGreen = gyg;
temp[height + 1][i].rgbtBlue = gyb;
}
/* See what we have at a pixel point */
printf("Top edge RGBTRIPLE %d, %d, %d \n", temp[0][144].rgbtRed, temp[0][144].rgbtGreen, temp[0][144].rgbtBlue);
printf("Left edge RGBTRIPLE %d, %d, %d \n", temp[144][0].rgbtRed, temp[144][0].rgbtGreen, temp[144][0].rgbtBlue);
printf("RGBTRIPLE within image %d, %d, %d \n", temp[144][144].rgbtRed, temp[144][144].rgbtGreen, temp[144][144].rgbtBlue);
return 0;
}
C does not really provide a simple way to initialize tuples so you probably would need "for" loops to do this. Experiment with this scenario and see if it applies to the spirit of your project.
Some issues:
Use mem...() where possible.
To zero byte fill an entire variable length array:
// RGBTRIPLE temp[height+2][width+2] = {};
RGBTRIPLE temp[height+2][width+2];
memset(temp, 0, sizeof temp);
I am setting all values of RGB to 0 (aka black) in the first line and then copy the original image into the temporary structure, substituting all except the border values with the respective colours.
Alternative:
// Given image[][] is a 2D array
for(int i = 0; i < height; i++) {
memcpy(temp[i+1], image[i], sizeof image[i]);
}
Initialize properly
float gxr, gxb, gxg, gyr, gyb, gyg = 0; only initializes gyg.
float gxr = 0;
float gxb = 0;
...
float gyg = 0;
Advanced: int math vs. size_t math
int*int*size_t may overflow int*int where size_t*int*int does not.
Cast not needed in C.
Size to the referenced object, not the type.
// RGBTRIPLE *ptr = (RGBTRIPLE *)malloc((height+2)*(width+2)*sizeof(RGBTRIPLE));
RGBTRIPLE *ptr = malloc(sizeof ptr[0] * (height+2) * (width+2));

Best way to get neighboring pixels on image

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.

error: 8.13802e+06 is outside the range of representable values of type 'unsigned char'

close to the finish I've encountered a problem I can't solve. Maybe one of you can:
The compiling of the following code works fine but when I fire the program I get this error message:
helpers.c:228:42: runtime error: 8.13802e+06 is outside the range of representable values of type 'unsigned char'
The code is a function to blur an image blockwise, but the very first pixel [0][0] does not get a correct average value and I don't know why I get that error message instead.
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
int i;
int j;
int m;
int n;
int averageRed;
int averageBlue;
int averageGreen;
RGBTRIPLE average[height][width];
// For each row of the image...
for (i = 0; i < height; i++)
{
//...take each pixel.
for (j = 0; j < width; j++)
//If current height equals 0 AND current width equals 0..
if (i == 0 && j == 0)
{
//..take 2 rows of the picture..
for (m = i; m <= i + 1; m++)
{
//..and take 2 pixels of each row.
for (n = j; n <= j + 1; n++)
{
//Sum up the rgb-values for each of the 2 pixel of the 2 rows.
averageRed = averageRed + image[m][n].rgbtRed;
averageGreen = averageGreen + image[m][n].rgbtGreen;
-> The error line averageBlue = averageBlue + image[m][n].rgbtBlue;
}
}
//Save the average of the values in a separate array after the 2x2 pixel-block
average[i][j].rgbtRed = round((float)averageRed / 4);
average[i][j].rgbtGreen = round((float)averageGreen / 4);
average[i][j].rgbtBlue = round((float)averageBlue / 4);
//Set average-variables to 0
averageRed = 0;
averageGreen = 0;
averageBlue = 0;
}
//From each row of the image...
for (i = 0; i < height; i++)
{
//...take each pixel..
for (j = 0; j < width; j++)
{
//...and update the original value with the temporary stored value.
image[i][j].rgbtRed = average[i][j].rgbtRed;
image[i][j].rgbtGreen = average[i][j].rgbtGreen;
image[i][j].rgbtBlue = average[i][j].rgbtBlue;
}
}
}
Thanks in advance for any hint!
Another facepalm-answer :-)..
The solution was quite simple. It was just the missing initialization of the averageRed/Green/Blue-variables.
Didn't get it because the error message pointed only to the averageBlue.
Thanks to M Oehm again :-)

cs50 pset4 filter swapping structs

I'm facing some difficulties while doing the reflect portion of filter. Essentially the struct is
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
and I have been attempting to reflect the image by implementing this function.
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
if (width % 2 == 0)
{
for (int j = 0; j < width/2; j++)
{
RGBTRIPLE temp = image[i][j];
image[i][j] = image[i][width - j];
image[i][width - j] = temp;
}
}
else if (width % 3 == 0)
{
for (int j = 0; j < (width - 1)/2; j++)
{
RGBTRIPLE temp = image[i][j];
image[i][j] = image[i][width - j];
image[i][width - j] = temp;
}
}
}
return;
}
The code compiles fine but the end product is the same as the input image. Tried to run debug50 and i figured that my problem lies with the way i swap the RGBTRIPLE values. Any help would be good. Thanks!
What you need to do is to reverse the array.
Why? because you are reflecting image horizontally so you want the left side of the image to become the right side of the image.
Imagine you have this array and you want to reverse it:
int count = 5;
int numbers[count] = {0, 1, 2, 3, 4};
// middle here should be 2.5 but it will be 2 because we cast it to int
int middle = count / 2;
// Reverse array
for (int i = 0; i < middle; i++)
{
// when i is 0, numbers[i] is 0, numbers[count - 1 - i] is 4
temp = numbers[i];
numbers[i] = numbers[count - i - 1];
numbers[count - i - 1] = temp;
}
You should do the same in your function:
// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
// The middle index
int middle = width / 2;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < middle; j++)
{
// Swap the left side element with right side element
RGBTRIPLE temp = image[i][j];
image[i][j] = image[i][width - j - 1];
image[i][width - j - 1] = temp;
}
}
return;
}

Resources