0

I am trying to decode JPEG2000 format with OpenJPEG.
(Decoding just one raw tile buffer from a svs file.)
But I got an error on opj_read_header().
Is there something I forgot to set before calling opj_read_header()?

opj_image_t *image = NULL;
int32_t datalen = tileByteCounts[test_num];
opj_stream_t *stream = opj_stream_create(datalen, true);
struct buffer_state state =
{
    .data = buffer,
    .length = datalen,
};
opj_stream_set_user_data(stream, &state, NULL);
opj_stream_set_user_data_length(stream, datalen);
opj_stream_set_read_function(stream, read_callback);
opj_stream_set_skip_function(stream, skip_callback);
opj_stream_set_seek_function(stream, seek_callback);
opj_codec_t *codec = opj_create_decompress(OPJ_CODEC_JP2);
opj_dparameters_t parameters;
opj_set_default_decoder_parameters(&parameters);
parameters.decod_format = 1;
parameters.cod_format = 2;
parameters.DA_x0 = 0;
parameters.DA_y0 = 0;
parameters.DA_x1 = tileWidth;
parameters.DA_y1 = tileHeight;
opj_setup_decoder(codec, &parameters);
// enable error handlers
opj_set_warning_handler(codec, warning_callback, NULL);
opj_set_error_handler(codec, error_callback, NULL);

// read header
if (!opj_read_header(stream, codec, &image)) // It's calling error_callback !
{
    printf("error on reading header");
    return 1;
}
YJJ
  • 45
  • 10
  • I guess you've checked how openslide does it? https://github.com/openslide/openslide/blob/master/src/openslide-decode-jp2k.c#L219 though if you're just reading SVS, I'd be included to simply use openslide. – jcupitt Dec 18 '18 at 13:15
  • Thanks @jcupitt, You are right. now I am simply trying to use Openslide. Do you know any good references to save an image file as JPEG from a buffer which is the result of TIFFReadRawTile ? – YJJ Dec 18 '18 at 15:06
  • I would use libvips -- it has an openslide binding. I'll make an answer. – jcupitt Dec 18 '18 at 15:13
  • a reason why I am writing the code by myself is that libvips was slow for extracting JPEG2000 image from a svs file and make it as JPEG image. I am not sure why libvips was slow. is there multithread options in libvips? – YJJ Dec 18 '18 at 15:22
  • Oh, strange, it should be quick. Could you share an example that was slow? – jcupitt Dec 18 '18 at 15:23
  • Yes, libvips is threaded automatically. – jcupitt Dec 18 '18 at 15:23
  • Can I extract all tiles from the first page of a svs file and decode JPEG2000 and encode it to JPEG for saving a output file with libvips in C++ ? Once I tried it with libvips in JS, It took more than 60 secs for an image with 20000x35000 svs file. – YJJ Dec 18 '18 at 15:30
  • I had a thought, perhaps your libvips has been built without openslide support? Try entering: `vips openslideload`. You should see `load file with OpenSlide`. If not, you'll need to build libvips yourself and enable openslide, sorry. – jcupitt Dec 18 '18 at 15:51
  • Hi, @jcupitt. Could you also let me know how to convert a svs file to a tiff file? extracting all tiles from a svs file and adding tiles into a tiff file with vips library in c – YJJ Dec 27 '18 at 13:38
  • Hi, just use `something.tif` as the output filename. – jcupitt Dec 27 '18 at 16:20
  • oh, thanks :) 1. how about making a pyramidal tiff ? can I do that with libvips too? or shoud I have to use openslide? 2. can I use multi-thread for this task too? it took 59 secs for a 15000x35000 svs image. – YJJ Dec 27 '18 at 16:40
  • OK, answer updated. – jcupitt Dec 27 '18 at 20:22
  • Thanks, @jcupitt. It worked like a charm! there is no way to make a pyramidal tiff with multi-threads with vips in C ? From the doc you mentioned, There is no thread parameter unfortunately. – YJJ Dec 28 '18 at 02:40
  • It threads automatically, you don't need to do anything. By default, it'll try to fill the whole machine, but you can force single-threading if you want. If you are seeing less than 100% load it's because there isn't enough parallelism in the job. – jcupitt Dec 28 '18 at 11:25

1 Answers1

0

I would use libvips to read from SVS images. It has a good openslide import operation written by the openslide devs, and handles this kind of thing well. It's free and cross-platform. Most linuxes have it in their package manager.

At the command-line you can write:

$ vipsheader CMU-1.svs
CMU-1.svs: 46000x32914 uchar, 4 bands, rgb, openslideload
$ time vips crop CMU-1.svs x.jpg 10 10 100 100
real    0m0.058s
user    0m0.050s
sys 0m0.008s

Be aware that jp2k is rather slow to decode. To convert the entire image, I see:

$ time vips copy CMU-1.svs x.jpg --vips-progress
vips temp-5: 46000 x 32914 pixels, 8 threads, 128 x 128 tiles, 256 lines in buffer
vips temp-5: done in 14.6s          

real    0m14.720s
user    1m10.978s
sys 0m1.179s

In C++:

// compile with
//      g++ crop.cpp `pkg-config vips-cpp --cflags --libs`

#include <vips/vips8>

int
main (int argc, char **argv)
{       
        if (VIPS_INIT (argv[0]))
                vips_error_exit (NULL);

        vips::VImage image = vips::VImage::new_from_file (argv[1]);

        image.write_to_file (argv[2]);
}

There are C, Python, Ruby, JavaScript, PHP, C#, Go, Rust etc. bindings too.

You can write other formats by changing the output filename, or by setting optional arguments in the C++ code. For example, you can run that C++ program with:

$ ./a.out CMU-1.svs x.tif[compression=jpeg,tile,pyramid]

Or you could change the write_to_file to be:

        image.tiffsave (argv[2], VImage::option()
                ->set ("compression", "jpeg")
                ->set ("tile", TRUE)
                ->set ("pyramid", TRUE));

The docs have all the details.

jcupitt
  • 10,213
  • 2
  • 23
  • 39
  • your result time is interesting. Can I ask how many CPUs you have ? – YJJ Dec 18 '18 at 15:52
  • It's a four core i7, so 8 threads. I think you might not have openslide enabled in your libvips. Try `vips openslideload` at the CLI. If openslide is not enabled, libvips will try to load SVS as TIFF (since SVS files are modified TIFFs) and will not work correctly. – jcupitt Dec 18 '18 at 15:54