Search code examples
c++image-processingrgbppmraw-file

Seperate 4 channels (R,G,G,B) of .raw image file and save them as valid image in c++


I have to take a .raw12 file, separate the 4 channels (R, G, G, B) and save them as valid images (8-bits in memory) without using any external library (.ppm) in C++.

You can read about raw12 here and ppm file format here.

I have written the code but it is giving me this output.

Click Here

I have tried a lot of things but it is always giving me output similar to the one above. I think there is a problem in datatype conversion but I am not sure.

I am trying to debug it from 2 days, still no luck.

Here is this code.

#include <fstream>
#include <iostream>
using namespace std;


const int BUFFERSIZE = 4096;


int main () 
{

    ifstream infile;

    infile.open("portrait.raw12", ios::binary | ios::in);

    ofstream outfile;

    outfile.open("Redtwo.ppm", ios::binary);

    //outfile.write("P6 ", 3);
    //outfile.write("1536 2048 ", 8);
    //outfile.write("2048 ", 4);
    //outfile.write("255 ", 4);


    //outfile << "P6\n" << 1536 << "\n" << 2048 << "\n255\n";
    outfile << "P6"     << "\n"
        << 1536  << " "
        << 2048  << "\n"
        << 255   << "\n"
       ;
    uint8_t * bufferRow = new uint8_t[BUFFERSIZE];

    if(!infile)
    {
        cout<<"Failed to open"<<endl;
    }
    int size=1536*2048*3;
    char * RedChannel=new char[size];
    int GreenChannel_1,GreenChannel_2,BlueChannel;
    int rowNum=0;
    int i=0;
    int j=0;
    int pixel=1;
    while(rowNum<3072)
    {
        infile.read(reinterpret_cast<char*>(bufferRow), BUFFERSIZE);
        if(rowNum%2==0)
        {
            while(i<BUFFERSIZE)
            {
                RedChannel[j]=(uint8_t)bufferRow[i];
                GreenChannel_1=((uint8_t)(bufferRow[i+1] & 0x0F) << 4) | ((uint8_t)(bufferRow[i+2] >> 4) & 0x0F);
                i+=3;
                //Collect s;
                //s.r=(char)RedChannel[j];
                //s.g=(char)0;
                //s.b=(char)0;
                //unsigned char c = (unsigned char)(255.0f * (float)RedChannel[j] + 0.5f); 
                //outfile.write((char*) &c, 3);
                //outfile.write((char*) 255, sizeof(c));
                //outfile.write(reinterpret_cast<char*>(&RedChannel), 4);
                if(pixel<=3 && rowNum<5)
                {
                    cout<<"RedChannel: "<<RedChannel[j]<<endl;
                    if(pixel!=3)
                        cout<<"GreenChannel 1: "<<GreenChannel_1<<endl;
                }
                pixel++;
                j++;

            }
            RedChannel[j]='\n';
            j++;

        }
        else
        {
            while(i<BUFFERSIZE)
            {
                GreenChannel_2=(uint8_t)bufferRow[i];
                BlueChannel=((uint8_t)(bufferRow[i+1] & 0x0F) << 4) | ((uint8_t)(bufferRow[i+2] >> 4) & 0x0F);
                i+=3;
                if(pixel<=3 && rowNum<5)
                {
                    cout<<"GreenChannel 2: "<<GreenChannel_2<<endl;
                    if(pixel!=3)
                        cout<<"BlueChannel: "<<BlueChannel<<endl;
                }
                pixel++;
            }
        }
        rowNum++;
        i=0;
        pixel=1;
        if(rowNum<5)
            cout<<" "<<endl;
    }
    infile.close();
    outfile.write(RedChannel, size);
    outfile.close();
}

Github Link To The Code


Solution

  • I have simplified your code quite a lot and made it output just one single channel, since your question says you should generate one image per channel.

    Now you have something working, you can add back in the other parts - it's easier to start with something that works! I won't do all your challenge for you... that would be no fun and leave you without any sense of achievement. You can do the rest - good luck!

    #include <fstream>
    #include <iostream>
    using namespace std;
    
    // Enough for one line of the input image
    const int BUFFERSIZE = 4096 * 3;
    
    int main(){
    
        ifstream infile;
        ofstream outfile;
    
        infile.open("portrait.raw12", ios::binary | ios::in);
        outfile.open("result.pgm", ios::binary);
    
        // Write single channel PGM file
        outfile << "P5\n2048 1536\n255\n";
    
        unsigned char * bufferRow = new unsigned char[BUFFERSIZE];
    
        if(!infile)
        {
            cout<<"Failed to open"<<endl;
        }
        int size=2048*1536;
        unsigned char * RedChannel=new unsigned char[size];
        unsigned char * Redp = RedChannel;
    
        for(int rowNum=0;rowNum<1536;rowNum++){
            // Read an entire row
            infile.read(reinterpret_cast<char*>(bufferRow), BUFFERSIZE);
            if(rowNum%2==0){
                for(int i=0;i<BUFFERSIZE;i+=3){
                    *Redp++=bufferRow[i];
                }
            }
        }
        infile.close();
        outfile.write(reinterpret_cast<char*>(RedChannel), size);
        outfile.close();
    }
    

    enter image description here