Need urgent help: TGA file read write and then Smoothing


  • Gesperrt

    @Th69 Hi Th69, i have updated write function now. Please check it.


  • Gesperrt

    @Schlangenmensch Hi Schlangenmensch, I need to use vector<PixelInfo> instead of vectorstd::uint8_t. I am confused with the memory alignment for 32bit here. Need your help here.


  • Gesperrt

    Hi Th69, Contortionist, Schlangenmensch

    I have rewritten entire code, please review it now. I have tested the code but it creates only partial image in tile_new.tga file.
    I am not sure what is wrong here? Please help me.

    #include <vector>
    #include <fstream>
    
    //=========================================
    // Code for loading a TGA-file 
    //=========================================
    typedef union PixelInfo
    {
        std::uint32_t Color;
        struct
        {
            std::uint8_t B, G, R, A;
        } RGBA;
    } *PPixelInfo;
    
    class Tga
    {
        private:
            std::vector<PixelInfo> Pixels;
            bool ImageCompressed;
            std::uint32_t width, height, size, BitsPerPixel;
    
        public:
            Tga(const char* FilePath);
            void writeTGA(const char* FilePath);
    };
    
    Tga::Tga(const char* FilePath)
    {
        std::fstream hFile(FilePath, std::ios::in | std::ios::binary);
        if (!hFile.is_open()){throw std::invalid_argument("File Not Found.");}
    
        std::uint8_t Header[18] = {0};
        std::vector<std::uint8_t> ImageData;
        static std::uint8_t DeCompressed[12] = {0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
        static std::uint8_t IsCompressed[12] = {0x0, 0x0, 0xA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
    
        hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header));
    
        if (!std::memcmp(DeCompressed, &Header, sizeof(DeCompressed)))
        {
            BitsPerPixel = Header[16];
            width  = Header[13] * 0xFF + Header[12];
            height = Header[15] * 0xFF + Header[14];
            size  = ((width * BitsPerPixel + 31) / 32) * 4 * height;
    
            if ((BitsPerPixel != 24) && (BitsPerPixel != 32))
            {
                hFile.close();
                throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image.");
            }
    
            ImageData.resize(size);
            ImageCompressed = false;
            hFile.read(reinterpret_cast<char*>(ImageData.data()), size);
        }
        else if (!std::memcmp(IsCompressed, &Header, sizeof(IsCompressed)))
        {
            BitsPerPixel = Header[16];
            width  = Header[13] * 0xFF + Header[12];
            height = Header[15] * 0xFF + Header[14];
            size  = ((width * BitsPerPixel + 31) / 32) * 4 * height;
    
            if ((BitsPerPixel != 24) && (BitsPerPixel != 32))
            {
                hFile.close();
                throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image.");
            }
    
            PixelInfo Pixel = {0};
            int CurrentByte = 0;
            std::size_t CurrentPixel = 0;
            ImageCompressed = true;
            std::uint8_t ChunkHeader = {0};
            int BytesPerPixel = (BitsPerPixel / 8);
            ImageData.resize(width * height * sizeof(PixelInfo));
    
            do
            {
                hFile.read(reinterpret_cast<char*>(&ChunkHeader), sizeof(ChunkHeader));
    
                if(ChunkHeader < 128)
                {
                    ++ChunkHeader;
                    for(int I = 0; I < ChunkHeader; ++I, ++CurrentPixel)
                    {
                        hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel);
    
                        ImageData[CurrentByte++] = Pixel.RGBA.B;
                        ImageData[CurrentByte++] = Pixel.RGBA.G;
                        ImageData[CurrentByte++] = Pixel.RGBA.R;
                        if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.RGBA.A;
                    }
                }
                else
                {
                    ChunkHeader -= 127;
                    hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel);
    
                    for(int I = 0; I < ChunkHeader; ++I, ++CurrentPixel)
                    {
                        ImageData[CurrentByte++] = Pixel.RGBA.B;
                        ImageData[CurrentByte++] = Pixel.RGBA.G;
                        ImageData[CurrentByte++] = Pixel.RGBA.R;
                        if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.RGBA.A;
                    }
                }
            } while(CurrentPixel < (width * height));
        }
        else
        {
            hFile.close();
            throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit TGA File.");
        }
    
        hFile.close();
        std::uint8_t* BuffP = ImageData.data();
        Pixels.resize(width * height);
    
        //Flip Pixels and store them in my vector
    
        for (std::size_t I = 0; I < height; ++I)
        {
            for (std::size_t J = 0; J < width; ++J)
            {
                Pixels[(height - 1 - I) * width + J].RGBA.B = *(BuffP++);
                Pixels[(height - 1 - I) * width + J].RGBA.G = *(BuffP++);
                Pixels[(height - 1 - I) * width + J].RGBA.R = *(BuffP++);
                Pixels[(height - 1 - I) * width + J].RGBA.A = (BitsPerPixel > 24 ? *(BuffP++) : 0xFF);
            }
            if(BitsPerPixel == 24)
                BuffP += (-width * 3) & 3;
        }
    }
    
    void Tga::writeTGA(const char* FilePath)
    {
        std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
        if (!hFile.is_open()) {throw std::invalid_argument("Cannot open file for writing.");}
    
        std::vector<std::uint8_t> ImageData(size);
        std::uint8_t* BuffPos = ImageData.data();
    
    
        //Flip it back to how it was when we loaded it.. 
        for (std::size_t I = 0; I < height; ++I)
        {
            for (std::size_t J = 0; J < width; ++J)
            {                                                                   //Flip The ScanLines/Rows back to normal.
                *(BuffP++) = Pixels[(height - 1 - I) * width + J].RGBA.B;
                *(BuffP++) = Pixels[(height - 1 - I) * width + J].RGBA.G;
                *(BuffP++) = Pixels[(height - 1 - I) * width + J].RGBA.R;
    
                if (BitsPerPixel > 24)
                    *(BuffP++) = Pixels[(height - 1 - I) * width + J].RGBA.A;
            }
            if(BitsPerPixel == 24)
                BuffP += (-width * 3) & 3;
        }
    
        static std::uint8_t DeCompressed[12] = {0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
        static std::uint8_t IsCompressed[12] = {0x0, 0x0, 0xA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
    
        if (!ImageCompressed)
        {
            hFile.write(reinterpret_cast<char*>(&DeCompressed), sizeof(DeCompressed));
            hFile.put(width & 0xFF);
            hFile.put((width & 0xFF) / 0xFF);
            hFile.put(height & 0xFF);
            hFile.put((height & 0xFF) / 0xFF);
            hFile.put(BitsPerPixel);
            hFile.put(0x0);
            hFile.write(reinterpret_cast<char*>(ImageData.data()), ImageData.size());
            hFile.close();
        }
        else
        {
            hFile.write(reinterpret_cast<char*>(&IsCompressed), sizeof(IsCompressed));
            hFile.put(width & 0xFF);
            hFile.put((width & 0xFF) / 0xFF);
            hFile.put(height & 0xFF);
            hFile.put((height & 0xFF) / 0xFF);
            hFile.put(BitsPerPixel);
            hFile.put(0x0);
        }
        hFile.close();
    }
    
    
    
    //=========================================
    // main
    //=========================================
    int main(int argc, char** argv) {
    	
    	Tga oTga("tile.tga");
            oTga.writeTGA("tile_new.tga");
    	return 0;
    }
    
    
    


  • @tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:

    @hustbaer With those code changes, I don't see weird glitchy patterns on the TGA image file anymore, rather I can see overlapping of two images and doesnot retain the actual color of the original image.

    That's strange. Header[13] * 256 + Header[12] and (Header[13] << 8) + Header[12] should be equivalent.

    Any way to attach images here?

    Unfortunately, no. But it would indeed be good to have the images you are using (both, the original and the one that your program creates). Maybe you can find some free image/file hosting service and post a link here?


    Aside from that: you are trying to solve 6 different things here:

    • Reading uncompressed 24 bit images
    • Reading uncompressed 32 bit images
    • Reading compressed 24 bit images
    • Reading compressed 32 bit images
    • Writing uncompressed 24 bit images
    • Writing uncompressed 32 bit images

    This is a bit much all at once, and clearly it's too much for you. Also I'm quite sure you're also not testing all of those 6 things but only two, and those only in combination instead of one at a time.

    What makes matters worse is that for 24 bit, there's an additional complication with images that have a width which is not divisible by 4.

    So...

    I would suggest you start with ONE of those things, e.g. reading uncompressed 24 bit images. Write the code for just that, and test it using two different test images: one that has a width which is divisible by 4 and one that has a width which is NOT divisible by 4. Prepare two small test images in some paint program with known values. E.g. pick 9 different colors and then make small test images that use those colors, one color for each of the 4 corners, one for each of the 4 sides and the last one for the middle section. Choose the colors so all the color components are different.

    Then let your program read the test images and print them to screen ala

    (R,G,B)(R,G,B)(R,G,B)(R,G,B)(R,G,B)
    (R,G,B)(R,G,B)(R,G,B)(R,G,B)(R,G,B)
    (R,G,B)(R,G,B)(R,G,B)(R,G,B)(R,G,B)
    (R,G,B)(R,G,B)(R,G,B)(R,G,B)(R,G,B)
    (R,G,B)(R,G,B)(R,G,B)(R,G,B)(R,G,B)
    

    Use fixed width format for R, G and B so it's easier to check. And then check the output of the program to what it should be. If it is, then you know that part is working and you can start implementing the next part. E.g. writing uncompressed 24 bit images. Or reading compressed 24 bit images - the order is up to you.

    Once you have all that implemented & checked using your test images, you can be reasonable sure that your code works. Then you can start modifying the image.


  • Gesperrt

    @hustbaer Hi hustbaer, I would focus on Uncompressed Targa image format first. Then would want to apply smoothing technique. Blur filter needs to be applied to the images. Any idea on this?



  • I give up.
    Good luck with this.



  • @tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:

    Blur filter needs to be applied to the images. Any idea on this?

    OpenCV is OpenSource, there are some common blur filters, so you can take a look there ....
    If you know which concrete blur filter you wonna apply (gaussian .... etc ) then the Internet also can tell you the mathematics behind. You only have to search for .... (think not every member here is intrested in basic computer vision / image manipulation algorithms, so the most ones would use a lib for it)

    The question is, why do YOU have to do this job, with this requirements (not using 3d party libs) ? There is a lot of mathematics and algorithms involved, and its looks like you have not that much experience to read specifications in the internet and apply this to working code ...

    So is it for learning or should it realy become productive code ?


  • Gesperrt

    @RHBaum Its for learning purpose. I cant use any 3rd party libraries here. Need to use std libraries only



  • @tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:

    I cant use any 3rd party libraries here.

    Could I ask Why?
    Thats not really common in programming area, and it makes your "job" not easy.
    In a real bussines environment it would not workable, at least not with this non trivial requirements.

    But yes, maybe its doable, but it would even a challange for an experienced developer. So it would take a lot of time ....



  • @RHBaum
    Implementing a blur filter is pretty easy. Implementing one that creates good looking results is a little harder, but still not hard. I didn't look, but I'm sure there's plenty of material online about calculating the coefficients. Also for a blur filter, you can use almost any coefficients and it will look OK.

    What's really hard though, is implementing a blur filter that's efficient. As in not 10x or even 100x slower compared to a really fast implementation.

    And the part about reading & writing TGA images should also not be a challenge for an experienced programmer. TGA is really simple compared to almost all other formats. (BMP is simple too, but only if you restrict it to a narrow subset of all possible BMP sub-formats.)

    Could I ask Why?

    Since he was asked repeatedly, and doesn't really want to answer, I'm pretty sure it's homework or something similar.


  • Gesperrt

    @hustbaer This is not a homework. im just trying out various image formats and manipulating them and apply algorithm to make them more efficient and optimize it as needed.



  • @tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:

    @hustbaer This is not a homework. im just trying out various image formats and manipulating them and apply algorithm to make them more efficient and optimize it as needed.

    Are you serious? Do you think you can do it better than those people who create dedicated libraries?
    You are struggling with reading/writing TGA images and I doubt you´ll produce anything as good as freely available libraries.


  • Gesperrt

    @DocShoe I am able to read and write TGA images using std c++ libraries now.



  • @tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:

    @hustbaer This is not a homework. im just trying out various image formats and manipulating them and apply algorithm to make them more efficient and optimize it as needed.

    No, you're not, because you obviously have no idea what you're doing. Maybe that's what you want to do, or think you're doing. But no, you're certainly not optimizing anything or making anything more efficient.


Anmelden zum Antworten