2

I have a numpy array representing a jpg, not as file. Therefore I have to directly process the array. I want to save these data into a file so that I can watch it with a usual jpg viewer. Usually I can do that with

pl = pylab.imshow(ds.pixel_array, cmap=pylab.cm.bone)

but the image information is coded in jpg2000, therefore this approach failed. I tried therefore pgmagick:

tmp = pgmagick.Image(ds.pixel_array)
logging.info("Info I")
pl = pgmagick.Blob()
tmp.write(pl, 'GRAY')

but unfortunately this fails, too, with the error that the numpy-array can not be converted into a pgmagick-image. Is there another way to convert the jpg2000-coded information into PIL-able information?

Update:
Running the following line

jpg_bytes = ds.pixel_array.astype('uint8').tostring()

leads to the following error:

Data type not understood by NumPy: format='uint12', PixelRepresentation=0, BitsAllocated=12

Edit: The complete function:

def convert(self, inputpic, outputpic = "", force = False):
        if not inputpic or not os.path.isfile(inputpic):
            logging.critical("No valid input filename entered, or input file not found. Input filename was " + inputpic)
            return INT_ERROR
        else:
            input_clean = self.cleanEnding(inputpic)
            if not outputpic:
                outputpic = input_clean + ".jpg"
            print "Output pic is " + outputpic
            if os.path.isfile(outputpic + ".jpg") and force is False:
                logging.critical("Output file is already there, don't want to overwrite it! Output filename was " + outputpic)
            else:
                if outputpic[:-4] is not ".jpg":
                    outputpic = outputpic + ".jpg"
                try:
                    ds = dicom.read_file(inputpic, force=True)
                except InvalidDicomError:
                    logging.critical("File " + inputpic + " is not a dicom file!")
                    return INT_ERROR
                #try:
                #    pl = pylab.imshow(ds.pixel_array, cmap=pylab.cm.bone)
                #except:
                try:
                    logging.info("Decoding starts now")
                    jpg_bytes = "".join(chr(x) for x in ds.pixel_array)
                    logging.info("Test I")
                    jpg_bytes = ds.pixel_array.astype('uint8').tostring()
                    logging.warning("Trying to decode it with pgmagick")
                    im = pgmagick.Image.open(io.BytesIO(jpg_bytes))
                    logging.info("Decoding successfull")
                    #logging.info("Info I")
                    #pl = pgmagick.Blob()
                    #tmp.write(pl, 'GRAY')
                except Exception as e:
                    logging.critical("Critical error happened during imshow() with file " + inputpic + " with the following error: " + str(e))
                    return INT_ERROR
                if not os.path.isfile("tmp.png"):
                    pylab.savefig("tmp.png")
                else:
                    logging.critical("tmp.png is already in this folder, maybe a failed cleanup? Stopping!")
                    return INT_ERROR
                im = Image.open("tmp.png")
                bg = Image.new("RGB", im.size, (255,255,255))
                bg.paste(im, (0,0), im)
                bg.save(outputpic[:-4], quality=95)
                os.remove("tmp.png")
        return INT_SUCCESS

with inputpic as a dicom file. The error in the logging file turns up after the first logging.info (logging.info("Decoding starts now")), therefore I assume that the error is thrown from the second line, after the third line is not in the log file anymore.

3
  • I'm not sure I understand. Can you just write it as a binary file without involving PIL? Have you tried the io from scikit image? Commented Mar 2, 2015 at 21:44
  • Note that you can't use is to compare strings, so if outputpic[:-4] is not ".jpg" will not do what you expect. Use == / !=: if outputpic[:-4] != ".jpg". Commented Mar 2, 2015 at 22:57
  • Also, if you use logging.exception instead of logging.critical you'll get a stack trace along with the error. Commented Mar 2, 2015 at 22:57

1 Answer 1

2

Assuming the pixel_array is an array of bytes which represent the JPEG-encoded image (the first four bytes - the magic number - will be FF D8 FF E0 if this is the case).

You can convert the numpy array to a byte string using:

jpg_bytes = ds.pixel_array.astype('uint8').tostring()

And you can load a byte string using:

import io
from pgmagick import Image

im = Image.open(io.BytesIO(jpg_bytes))

Edit: I missed the "jpg2000" bits, so:

  • pgmagick can load jpg2000 files and the code above will work without issue.
  • The magic number of jpg2000 files is 0000 000C 6A50 2020 0D0A 870A.
Sign up to request clarification or add additional context in comments.

10 Comments

I have the data as a numpy array, not as a file, as stated in my question. Furthermore I have the problem that PIL is not able to handle jpg2000-compressed data, as also stated in the question, therefore rendering it useless for me.
See the second code block for an example of converting the numpy array to a byte string. pgmagick — which you're already using — supports jpg2000 so the example should work. If it doesn't, it likely means your installation of pgmagick was built without jpg2000 support.
Even the first line is not working, the error is shown in the opening post.
That's not an error I've seen specifically, so I'm not 100% sure the "right" way to address it, but the quick and dirty fix would be: jpg_bytes = "".join(chr(x) for x in ds.pixel_array)
Same as which? The "data type cannot be understood"? Can you copy+paste the exact code you're using and the exact error? (the quick fix I posted doesn't use any numpy methods so it's unlikely to cause a numpy error)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.