Kssonety
Kssonety

Reputation: 43

Make image from uint8 RGB pixel data

I am trying to make a library related to RGB pixel data, but cannot seem to save the image data correctly.

Image

That is my output image. This is my code:

pixelmanager.py

from PIL import Image
import numpy as np

class MakeImgFromPixelRGB:
    def createIMG(PixelArray: list, ImgName: str, SaveImgAsFile: bool):
        # Convert the pixels into an array using numpy
        array = np.array(PixelArray, dtype=np.uint8)
        if SaveImgAsFile == True:
            new_image = Image.fromarray(array)
            new_image.save(ImgName)
class getPixelsFromIMG:
    def __init__(self, ImagePath):
        im = Image.open(ImagePath, 'r')
        width, height = im.size
        pixel_values = list(im.getdata())
        self.output = pixel_values

test.py

import pixelmanager

a = pixelmanager.getPixelsFromIMG(ImagePath="download.jpg")

pixelmanager.MakeImgFromPixelRGB.createIMG(a.output, "output.png", True)

with open("output.txt", "w") as f:
    for s in a.output:
        f.write(str(s) + "," + "\n")

I have tried to de-scale the image in paint.net and also tried to mess with the uint size.

Upvotes: 2

Views: 98

Answers (2)

Kssonety
Kssonety

Reputation: 43

Mark Setchell was ALMOST correct. His code did help me get an image, but it was repeated 4 times in one.

Mark's line of code had a switchup (with h as height and w as width):

array = np.array(PixelArray, dtype=np.uint8).reshape(h,w,3)

This is my line of code:

array = np.array(PixelArray, dtype=np.uint8).reshape(w, h, 3)

Upvotes: 1

Mark Setchell
Mark Setchell

Reputation: 207798

Treating images as Python lists of pixels is not generally the best idea, because it is slow and error-prone. In general, you want to use PIL's functions which are coded in C and deal with PIL Image types, or Numpy or OpenCV which are highly vectorised/optimised and deal with Numpy arrays.

Anyway, if you really, really want to deal with lists (which you don't), you need to remember that when you call Image.getdata() against a JPEG you will get a flat list of RGB tuples. So, if your image is 640x480 pixels, and you do this:

im = Image.open('image.jpg')
px = list(im.getdata())

you will get a list with 307,200 entries, each one an RGB tuple. BUT your list no longer knows the height and width of the image. So, when you subsequently do:

array = np.array(PixelArray, dtype=np.uint8)

your array is now shaped (307200,3) instead of (480,640,3) - sooooo, you get a long line of pixels in your output image.

If you are insistent on using lists, you will need to retain the height and with of the original image, so you can do:

array = np.array(PixelArray, dtype=np.uint8).reshape(h,w,3)

Note that you should also remember the image's mode, i.e. whether it was RGB or RGBA, or P, or PA, or L, or LA, or HSV etc. And note that will also make your tuples of length 1, 2, 3 or 4 instead of always assuming 3. Later on, you will also realise you may have to deal with 16/32/64 bits/sample images so you will need to remember that too, in addition to the above.

Upvotes: 4

Related Questions