Image to QImage ?

I saw in an earlier thread the discussion about the layer density calculation via the TilingProcessor. I implemented it and made a nice GUI around it. However, as already indicated, the resulting RBA::Image can be placed into a LayoutView, but not conveniently saved. I managed to slap something together with LayoutView.save_image(), but I also spent a whole day trying to convert the RBA::Image content into something that RBA::QImage could take, but to no avail. I can access each pixel via RBA::Image.get_pixel(), but I struggled with the data/buffer/bytearray arrangement of QImage. Does anyone know how to do this correctly ? I would like to set grayscale pixels of QImage directly. The hope is that i also figure out how to export/save that QImage object correctly later. :smile:

Thank you !

Thomas.

Comments

  • Hi Thomas,

    Image was designed for reading images from PNG, but not to write them. It carries more information than a plain image, e.g. the data mapping (e.g. heat map), the transformation, z order etc.

    Actually, iterating the pixels and writing into a QImage is currently the only way to translate back to PNG. In this case you have to decide how to translate values into RGB triples.

    I'm fairly sure that for density maps there are scientific formats which allow encapsulating the extended information. But my experience here is limited. If you have a proposal for a format commonly used for the purpose of representing 2d float data, I'm open to supporting reading/writing.

    For example, there is a format developped by the NASA in the 70s for representing 1d, 2d or 3d data called FITS (https://fits.gsfc.nasa.gov/fits_primer.html). Apparently it's capable of holding 32bit floats and different channels. It has a flexible header structure I could use to store the transformation information. And it can be read by gimp and many other tools. But as I said, my experience is limited. Any comments are welcome.

    Regards,

    Matthias

  • Hi Matthias,
    I actually believe that your tiling processor suggestion does a good enough job. From the other thread:

     tp.queue("_tile && (var d = to_f(input.area(_tile.bbox)) / to_f(_tile.bbox.area);_output(res, (1-d)))")
    

    Where it hangs up for me is the hinted "iterating the pixels and writing into a QImage". I cannot get that to work. Can you give me a sample code ? I read in some ruby forums that you need a bytearray, a buffer, and the right way of accessing it.
    I don't think you need special formats for the maps. What you created (an array of values 0..1) fits perfectly.

    Thanks.

    Thomas.

  • Well, you can't fit values of 0..1 into a PNG file. It only takes 8 bit ARGB and you somehow need to convert the values. So you'll essentially loose precision along with the metadata which give you the coordinate information for example.

    That's why I was bringing up the topic of scientific formats which are made for representing measurement values.

    For the plain Image to QImage conversion this is some sample code:

    import pya
    import math
    
    def to_qimage(img):
      h = img.height()
      w = img.width()
      qimg = pya.QImage.new(w, h, pya.QImage.Format_ARGB32)
      for y in range(0, h):
        for x in range(0, w):
          # turn a value of 0..1 into a ARGB32 pixel value of 0xffvvvvvv (vv = 0x00..0xff)
          v_8bit = int(math.floor(img.get_pixel(x, y) * 255.0 + 0.5))
          argb32 = v_8bit * 0x10101 + 0xff000000
          qimg.setPixel(x, h - 1 - y, argb32)
      return qimg
    
    img = pya.Image(600, 400, [])
    for x in range(0, 255):
      img.set_pixel(x, x, x / 255.0)
    
    qimg = to_qimage(img)
    
    qimg.save("/home/matthias/x.png")
    
Sign In or Register to comment.