1

I am running the following simple line in a short script without any issues:

Python 3.5.2;
PIL 1.1.7;
OpenCV 2.4.9.1;
Matplotlib 3.0.1;

...
# for example:
img = plt.imread(i1)
...

However, if the size of a loaded .JP2 > ~500 MB, Python3 throws the following error when attempting to load an image:

"Segmentation Fault (core dumped)"

It should not be a RAM issue, as only ~40% of the available RAM is being used when the error occurs + the error remains the same when RAM is removed or added to the computer. The error also remains the same when using other ways to load the image, e.g. with PIL.

Is there a way to avoid this error or to work around it? Thanks a lot!

valethmps
  • 11
  • 2
  • Do you mean the JP2 file is over 500MB on disk? Or it expands into more than 500MB in memory when loaded? How did you create the JP2 or can you provide a link to where it came from? What are the dimensions in pixels wide by pixels tall of the JP2 file? What OS are you using? – Mark Setchell Jun 20 '19 at 08:14
  • hi mark, yes, the .JP2s are >500 MB on disk. I did not create the .JP2 files, those are large images (~20000 pix wide, ~60000 pix tall, I;16, JPEG2000) that I have downloaded e.g. from here: https://hirise-pds.lpl.arizona.edu/download/PDS/EXTRAS/RDR/PSP/ORB_007200_007299/PSP_007219_1720/PSP_007219_1720_RED.NOMAP.JP2 the width of the images is always equal (more or less), but the length will vary (determining the size of the file on disk). My OS is an Ubuntu 16.04. Thanks! – valethmps Jun 20 '19 at 08:29
  • The image you linked is 20k x 80k, which is 1.6 gigapixels of 2 bytes each, so 3.2GB in memory at least. So, all libraries and your OS better be 64-bit? – Mark Setchell Jun 20 '19 at 08:44
  • If you give some more information about how you plan to process the image, I may have some suggestions, but as a first attempt, I would suggest you consider replacing the `segmentation-fault` tag with `vips` as that seems the most likely solution at the moment. – Mark Setchell Jun 20 '19 at 08:48
  • great, added a 'vips' tag! I am usually performing minor operations like tiling the image or converting from 16bit to 8bit... could I do something like that with e.g. pyvips? – valethmps Jun 20 '19 at 08:58
  • pyvips uses imagemagick to open JP2 images, unfortunately, so it needs huge amounts of memory. However as long as you have loads of ram, it should work. – jcupitt Jun 20 '19 at 16:29
  • so, I've got 64 GB of RAM, and I receive the error as described above... using e.g. matplotlib or OpenCV... – valethmps Jun 20 '19 at 16:53
  • can you recommend any other library to load these large .JP2 images? – valethmps Jun 20 '19 at 16:55
  • Wow that's a lot. Yes, pyvips should work, but it will load the whole image to memory, and IM needs a lot of memory, depending on the version. – jcupitt Jun 20 '19 at 19:49
  • I have no issue opening `PSP_007219_1720_RED.NOMAP.JP2` on Windows with Pillow 6 (or Matplotlib, which uses Pillow under the hood). Make sure Pillow was compiled with JPEG2000 support and set `Image.MAX_IMAGE_PIXELS` large enough. 3 GB is not really that large that it would necessitate out of core processing... – cgohlke Jun 21 '19 at 03:04
  • thanks @cgohlke, let me double-check! – valethmps Jun 21 '19 at 23:08
  • @jcupitt: so, Image.MAX_IMAGE_PIXELS = None or random big number is implemented and seems to be alright, but how could i verify that JPEG2000 support has been compiled for pillow? thanks! – valethmps Jun 27 '19 at 14:46
  • Sorry, you'd need to ask a Pillow export, I'm the pyvips person. – jcupitt Jun 27 '19 at 17:34

1 Answers1

0

Not really a solution, more of an idea that may work or help other folks think up similar or further developments...

If you want to do several operations or crops on each monster JP2 image, it may be worth paying the price up-front, just once to convert to a format that ImageMagick can subsequently handle more easily. So, your image is 20048x80000 of 2-byte shorts, so you can expand it out to a 16-bit PGM file like this:

convert monster.jp2 -depth 16 image.pgm

and that takes around 3 minutes. However, if you now want to extract part of the image some way down its height, you can now extract from the PGM:

convert image.pgm -crop 400x400+0+6000 tile.tif

in 18 seconds, instead of from the monster JP2:

convert monster.jp2 -crop 400x400+0+6000 tile.tif

which takes 153 seconds.


Note that the PGM will take lots of disk space.... I guess you could try the same thing with a TIFF which can hold 16-bit data too and could maybe be LZW compressed. I guess you could also use libvips to extract tiles even faster from the PGM file.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • I was about to suggest this too, heh. If you write a tiled TIFF, libvips can read it very quickly, eg. `convert PSP_007219_1720_RED.NOMAP.JP2 -define tiff:tile-geometry=128x128 -compress jpeg x.tif` takes 25m on this laptop and needs 6.5gb of ram. – jcupitt Jun 21 '19 at 02:07
  • @jcupitt John, what would be the equivalent `vips` to extract a 400x400+0+6000 chunk from the tiled TIFF please? Also, does your `-compress JPEG` carry forward/preserve the 10-bittedness of the original image? Thank you. – Mark Setchell Jun 21 '19 at 06:56
  • Hey Mark, you can just use `crop`. I was hoping the 10 bits was unimportant, but if it is, yes, I guess you'd need to use 16-bit LZW. @cgohlke above says pillow can be built with jp2 support (I had no idea!) so perhaps that's the best route. – jcupitt Jun 21 '19 at 10:52
  • @jcupitt, great ideas guys, let me see if I can make them work on my machine! – valethmps Jun 21 '19 at 23:07