QImage reduce color to nearest indexed palette



  • can someone provide some example code on how to convert an image to raw data and display it?
    I have googled around for tutorials but I can't find one.

    tiletable.h

    #ifndef TILETABLE_H
    #define TILETABLE_H
    
    #include <QImage>
    
    class TileTable
    {
        public:
            TileTable();
           ~TileTable();
    
            unsigned char tiles[65536];
            unsigned char pal[256];
            QColor        cset[16];
    
    
            unsigned char load_image(QImage *image);
    
    };
    
    #endif // TILETABLE_H
    
    

    tiletable.cpp

    #include "tiletable.h"
    
    TileTable:: TileTable()
    {
    
    }
    
    TileTable::~TileTable()
    {
    
    }
    
    
    unsigned char TileTable::load_image(QImage *file)
    {
        QImage image = QImage.load(file);
        image.convertToFormat(QImage::Format_RGB444);
    
        uchar bits = image.bits();
        //I'm not sure what to do here.
    }
    

  • Moderators

    @Shadowblitz16 What do you mean by "raw data"? Do you mean RAW as in a digital camera? What do you expect to get?



  • @Shadowblitz16 mmh, do you want it in a QByteArray?

    You could do something like this than:

    QImage img;
    QByteArray bArray;
    QBuffer buffer(&bArray);
    buffer.open(QIODevice::WriteOnly);
    img.save(&buffer, "format");
    


  • Hello jsulm and j.Hilk

    I mean like loading the image and finding the closest colors in the current color set , and converting them into a array of 4 bit indexed pixel data.

    so there would be 65536 tiles and each tile would hold a 256 sized array of unsigned chars representing the color of the current palette and color set.

    https://en.wikipedia.org/wiki/Indexed_color


  • Qt Champions 2016

    I had made a toy project a few months back that does that. I could upload the source for you somewhere if you're interested. It uses a median cut to get the palette and then "reconstructs" the image by replacing each color with its closest counterpart from the palette. It should be somewhat trivial to adapt it to your needs.

    Edit:
    Source code available here.



  • thankyou so much kshegunov I will take a look at this.
    however I see that you use the boost library and I seem to not have it.
    can you explain where to get it?


  • Moderators

    @Shadowblitz16 For which platform, OS and compiler?


  • Qt Champions 2016

    @Shadowblitz16 said in Convert Image to Array based pixel data?:

    however I see that you use the boost library and I seem to not have it.
    can you explain where to get it?

    http://www.boost.org/

    Note that I use only the statistics framework (header-only) so you don't need to compile anything before hand. You just need to point your project file to the boost directory (through the INCLUDEPATH variable). Also, since I only use the min, max and mean accumulator extractors from that library you can simply provide your own implementations and not care about including boost at all.



  • Thankyou kshegunov I will do that



  • @kshegunov I'm not sure if this does what I want.

    I'm trying to make my game draw things from pixel data not convert them back into indexed images.

    this way I can store the tiledata directly into a json file representing the tiles and there index
    here is an example json explaining what format I want my tiles in

    {
    	"TILES": [
    		[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    		[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    	  	...all the way to 65535...
    		[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    	]
    }
    

    EDIT: here is what I got for a loading function so far

    QImage TileTable::load_image(QString file, int tilewidth, int tileheight)
    {
        QImage image(file);
        image.convertToFormat(QImage::Format_RGB444);
    
        char data[65536]; // need a 2d array here later
        int  len = (image.width / tilewidth) * (image.height / tileheight);
    
        for(int i=0; i<len; i++)
        {
            int x = i % tile_width;
            int y = i / tile_height;
            QImage subImage = image.copy(x,y,tilw_width, tile_height);
            
            //Todo convert subImage to to array of palette indexes
            
            data[i] = subImage; //temparary I want to eventully store a array of indexed pixels here
        }
    }
    

    I just need a way of converting the image


  • Qt Champions 2016

    Well, I have provided sample code for the conversion. If you don't want to save the data back to an image, you need to modify the code and save the index in an array, but I don't really see a big difference so should be easy to adapt.
    Instead of setPixelColor used here you just save the index of the palette color in your array, should be as simple as this.



  • @kshegunov I see you didn't use the QImage.bits() method like i did can you explain why?


  • Qt Champions 2016

    QImage::bits returns internal data, thus it requires me to know what is the image's format and data padding (if any). Using the pixel modification API does not, on the other hand. Moreover, as this all boils down to interpolation in RGB space, having a color value represented in other color spaces isn't as useful, because the "finding closest" approximation requires a bit more work. For example if I used CMYK I'd have to use 4D color space, if I were to work in HSV I'd have to calculate distances in cylindrical coordinate system, which while possible makes it more complicated for no good reason.



  • thankyou kshegunov however when I add an image and try to reduce its color by lowering the color count it doesn't do anything can you explain why?


  • Qt Champions 2016

    You mean for my toy application?
    The color count should be a power of two, so 16, 32, 64, 128 are valid, but not say 3, 9, 11.



  • oh I see why its called color reduction now...
    it doesn't index the image it just reduces the color..


  • Qt Champions 2016

    @Shadowblitz16 said in QImage reduce color to nearest indexed palette:

    it doesn't index the image it just reduces the color..

    I don't follow, what's the difference?
    An index-colored image is a table of colors (again 8, 16, 32 etc. in number) and instead of assigning RGB values directly to the pixels you assign them indices from that table. My toy app does the table, but instead of saving the table and using index-colored format it just uses the colors directly, but it's basically the same principle. If you open the image histogram you'll see only that number of colors that would otherwise be in the color table.



  • but it should round the colors to the nearest color on the palette if the palette size isn't big enough to hold all the colors.


  • Qt Champions 2016

    It does - here



  • hmm its not doing it for me.. for example I gave it an image and specified a palette size of 4.
    after it was done processing it just recolored parts of the image..

    EDIT: now it doesn't look like its doing anything.

    EDIT2: ok so when I open the file browser to load an image, all my images are listed as paint.net images when they are not.
    I think its getting the file extension confused with the default program that opens the file.


  • Qt Champions 2016

    @Shadowblitz16 said in QImage reduce color to nearest indexed palette:

    hmm its not doing it for me.. for example I gave it an image and specified a palette size of 4.
    after it was done processing it just recolored parts of the image..

    What do you suppose an index based image is to look like?
    Open any image, put it in photoshop, gimp or w/e make it index-based with a palette size of 4 and observe what happens.


  • Qt Champions 2016

    Hi
    Unless you use Dithering, a palette of 4 color will destroy most images :)
    ![alt text](0_1493897430493_upload-216d44af-ee00-457b-b63b-636f672371d1 image url)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.