c++pointersgrayscaleppm

Convert PPM Image to Greyscale C++


Trying to convert a PPM Image to greyscale by indexing the pointer containing the pixel data:

void PPMObject::greyScale()
{
    const float r = 0.299F;
    const float g = 0.587F;
    const float b = 0.114F;

    int size = this->width * this->height * 3;
    for (int i = 0; i < size; i++)
    {
        this->m_Ptr[i] = (this->m_Ptr[i] * r) + (this->m_Ptr[i] * g) + (this->m_Ptr[i] * b);
        this->m_Ptr[i+1] = (this->m_Ptr[i+1] * r) + (this->m_Ptr[i+1] * g) + (this->m_Ptr[i+1] * b);
        this->m_Ptr[i+2] = (this->m_Ptr[i+2] * r) + (this->m_Ptr[i+2] * g) + (this->m_Ptr[i+2] * b);
    }
}

Where I've read the PPM Image file using the >> overload:

istream& operator >>(istream &inputStream, PPMObject &other)
{
    inputStream >> other.magicNum >> other.width >> other.height >> other.maxColorValue;
    inputStream.get();
    size_t size = other.width * other.height * 3;
    other.m_Ptr = new char[size];
    inputStream.read(other.m_Ptr, size);
    return inputStream;
}

I write the data as follows:

ostream& operator <<(ostream &outputStream, const PPMObject &other)
{
    outputStream << other.magicNum  << " "
    << other.width          << " "
    << other.height         << " "
    << other.maxColorValue  << " "
    ;   
    outputStream.write(other.m_Ptr, other.width * other.height * 3);
    return outputStream;
}

There are no problems with reading or writing the PPM file.

The problem is simply converting the PPM Image to greyscale -- indexing is not the approach. The file is unchanged.

The question is likely: How do I get the values from the pointer to manipulate them?

E.g., Where are the pixels located in the char pointer?

Averaging the RGB component values is certainly another approach but then how do I assign the average back into the pointer?


Solution

  • Inside your greyScale() function you need to increment i by 3 each time you step through the loop, because each pixel takes up 3 bytes and you process one pixel at a time:

    for (int i = 0; i < size; i+=3)
    

    Also, the formula you are currently using will leave the values unchanged (ignoring rounding and floating point errors).

    This:

    this->m_Ptr[i] = (this->m_Ptr[i] * r) + (this->m_Ptr[i] * g) + (this->m_Ptr[i] * b);
    

    simplifies to:

     this->m_Ptr[i] = (this->m_Ptr[i] * 1.0F);
    

    The correct formula is something like this (ignoring casts and assuming the data is in RGB order):

    for (int i = 0; i < size; i+=3)
    {
        float greyscaleValue = (this->m_Ptr[i] * r) + (this->m_Ptr[i+1] * g) + (this->m_Ptr[i+2] * b);
        this->m_Ptr[i] = greyscaleValue;
        this->m_Ptr[i+1] = greyscaleValue;
        this->m_Ptr[i+2] = greyscaleValue;
    }