views:

41

answers:

2

I'm new to C++ and getting a bit frustrated with it. Below, in pixelsVector, I am storing each pixel RGB float-value in Pixel and want to dump all the values to a byte array with pixelsArray so I can output to an image file. HEIGHT and WIDTH refer to the image dimensions. The code below works fine, but I need to specify the sizes of pixelsArray at run-time, because it may not always be a 500x500 image.

// WIDTH and HEIGHT specified at run-time
vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));

...

unsigned char pixelsArray[500][500][3];

for (int i = 0; i < 500; i++)
{
    for (int j = 0; j < 500; j++)
    {
        // Returns RGB components
        vector<float> pixelColors = pixelArray[i][j].getColor();

        for (int k = 0; k < 3; k++)
        {
            pixels[i][j][k] = pixelColors.at(k);
        }
    }
}

// write to image file
fwrite(pixelsArray, 1, 500*500*3, file);

If I put HEIGHT and WIDTH instead of 500 and 500 above, I get an error since they are not constant values. Now using a 3D vector does seem to work, but fwrite won't take a vector for its first argument. I tried using a triple-pointer array but it doesn't seem to work at all - maybe I was using it wrong. Here it is using a 3D vector for pixelsArray:

vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));

...

vector< vector< vector<unsigned char> > > pixelsArray;

for (int i = 0; i < HEIGHT; i++)
{
    pixels.push_back(vector< vector<unsigned char> >());

    for (int j = 0; j < WIDTH; j++)
    {
        pixels[i].push_back(vector<unsigned char>());

        vector<float> pixelColors;
        pixelColors = pixelArray[i][j].getColor();

        for (int k = 0; k < 3; k++)
        {
            pixels[i][j][k] = pixelColors.at(k);
        }
    }
}

// Error
fwrite(pixelsArray, 1, 500*500*3, file);

Suggestions?

+1  A: 

You could use Boost.MultiArray insead of vectors of vectors, which lets you access he underlying memory with the .data() method.

It looks like you are trying to manipulate images, so you might want to consider using Boost.Gil.

xDD
Is the boost library built-in c++?
Steve
@John: No, but it's about as cross-platform as a library can get.
Steve M
+1  A: 

From the last code snippet:

vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));

Using uppercase names for variables you risk name collisions with macros. In C++ all uppercase names are conventionally reserved for macros.

...

vector< vector< vector<unsigned char> > > pixelsArray;

Presumably this vector is the same as is called pixels below?

If so, then the standard advice is that it helps to post real code.

Anyway, in order to output those bytes in one efficient operation you need the bytes to be contiguously stored in memory. So a vector of vectors of vectors is out. Use a single vector (C++ guarantees contiguous storage for the buffer of a std::vector).

for (int i = 0; i < HEIGHT; i++)
{
    pixels.push_back(vector< vector<unsigned char> >());

    for (int j = 0; j < WIDTH; j++)
    {
        pixels[i].push_back(vector<unsigned char>());

At this point you have an inner vector but it's empty, size 0.

        vector<float> pixelColors;
        pixelColors = pixelArray[i][j].getColor();

Presumably pixelArray is an instance of a class you have defined?

        for (int k = 0; k < 3; k++)
        {
            pixels[i][j][k] = pixelColors.at(k);
        }

Here you're trying to assign to non-existent elements of the empty innermost vector. You can either size it properly in advance, or use the push_back method for each value.

In addition, are you sure that the float values are integers in range 0 through 255 (or more generally, 0 through UCHAR_MAX) and not, say, in the range 0 through 1?

Perhaps you need to scale those values.

    }
}

// Error
fwrite(pixelsArray, 1, 500*500*3, file);

If pixelsArray had been a (non-empty) vector of bytes, then you could use &pixelsArray[0] to obtain a pointer to the first byte.

Now, I know, the above only dissects some of what's wrong, and doesn't tell you directly what's right. :-)

But some more information would be needed to give example code for doing this, like (1) what are your float values, and (2) what do you want in your file?

Anyway, hope this helps,

– Alf

Alf P. Steinbach