Search code examples
c++imagebitmapbmp

I'm reading the RGB values of pixels from a BMP file and not getting the correct values


I followed the code at this link read pixel value in bmp file to be able to read the RGB values of pixels and when I have the entire image as one color and read a random pixel's values they are correct. After this I tried to make it so the function would also try and find how many unique colors there were so I added a box with a different color to the image but the function still only finds one color. I'm wondering if maybe I'm somehow not looking at all the bytes contained in the BMP but I'm not sure how that would be as I'm new to trying this stuff.

To make sure the code wasn't finding different colored pixels but failing to add them to the list of unique pixels I tried printing output when a color is found that is different from the one that is always found but no output ever came from it.

struct Color {
int R = -1;
int G = -1;
int B = -1;
};

unsigned char* readBMP(char* filename) {
int i;
FILE* f = fopen(filename, "rb");
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f);

int width = *(int*)&info[18]; //the reason *(int*) is used here because there's an integer stored at 18 in the array that indicates how wide the BMP is
int height = *(int*)&info[22]; // same reasoning for *(int*)

int size = 3 * width * height;
unsigned char* data = new unsigned char[size];
fread(data, sizeof(unsigned char), size, f);
fclose(f);

// windows has BMP saved as BGR tuples and this switches it to RGB
for(i = 0; i < size; i += 3){
    unsigned char tmp = data[i];
    data[i] = data[i+2];
    data[i+2] = tmp;
}

i = 0; // i is the x value of the pixel that is having its RGB values checked
int j = 0; // j is the y value of the pixel that is having its RGB values checked
unsigned char R = data[3 * (i * width + j)]; // value of R of the pixel at (i,j)
unsigned char G = data[3 * (i * width + j) + 1]; // value of G of the pixel at (i,j)
unsigned char B = data[3 * (i * width + j) + 2]; // value of B of the pixel at (i,j)

std::cout << "value of R is " << int(R);
std::cout << " value of G is " << int(G);
std::cout << " value of B is " << int(B);

Color num_colors[5];
int count;
int z;
int flag;
int iterator;
int sum;
for(count = 0; count < size; count += 1){
    unsigned char R = data[3 * (i * width + j)];
    unsigned char G = data[3 * (i * width + j) + 1];
    unsigned char B = data[3 * (i * width + j) + 2];
    sum = int(R) + int(G) + int(B);
    if(sum != 301) {// 301 is the sum of the RGB values of the color that the program does manage to find
        std::cout << sum;
    }
    flag = 0;
    for(z = 0; z < 5; z += 1){
        if(num_colors[z].R == R && num_colors[z].G == G && num_colors[z].B == B){
            flag = 1;
        }
    }
    if(flag == 1){
        continue;
    }
    iterator = 0;
    while(num_colors[iterator].R != -1){
        iterator += 1;
    }
    num_colors[iterator].R = R;
    num_colors[iterator].G = G;
    num_colors[iterator].B = B;
}

int number = 0;
for(int r = 0; r < 5; r += 1){
    std::cout << "\nValue of R here: " << num_colors[r].R;
    if(num_colors[r].R != -1){
        number += 1;
    }
}
std::cout << "\nNumber of colors in image: " << number;
return data;
}

https://i.sstatic.net/QTZBx.jpg This is the picture I'm using so there should be two colors found but the code only finds red pixels.


Solution

  • Your problem is that you are always checking the RGB values at (0,0)

    i = 0; // i is the x value of the pixel that is having its RGB values checked
    int j = 0; // j is the y value of the pixel that is having its RGB values checked
    ...
    for(count = 0; count < size; count += 1){
        unsigned char R = data[3 * (i * width + j)];
        unsigned char G = data[3 * (i * width + j) + 1];
        unsigned char B = data[3 * (i * width + j) + 2];
    

    i and j defines the X and Y position of the pixel you are checking, but notice that you never change those in the loop. Your loop will keep doing the same thing over and over again. What you probably want is a double loop, going through all coordinates in your image:

       for(int y=0; y<height; y++)
           for(int x=0; x<width; x++){
              unsigned char R = data[3 * (y * width + x) + 0];
              unsigned char G = data[3 * (y * width + x) + 1];
              unsigned char B = data[3 * (y * width + x) + 2];