Fastest way to display decoded JPEG2000 in Qt?

426 views
Skip to first unread message

tlal...@gmail.com

unread,
Jun 27, 2016, 7:50:41 AM6/27/16
to OpenJPEG
Good day,

currently I am attempting to write an application that generates a preview of decoded JPEG2000 images in Qt. After decoding the image I use the following code to create a QImage:

    QImage image(width, height, QImage::Format_RGB32); // create image

    for (int x = 0; x < width; x++){
        for (int y = 0; y < height; y++){

            QRgb argb = qRgba(
                psImage->comps[0].data[x * y], //red
                psImage->comps[1].data[x * y], //green
                psImage->comps[2].data[x * y], //blue
                255);   //alpha

            image.setPixel(QPoint(x,y), argb);
        }
    }

The creation of the QImage currently takes around 200ms on my average notebook for the 1920x540 image. Also the image content is useless (see attachment).
Any tips on how to resolve these issues would be greatly appreciated!

Thanks in advance!

Aaron Boxer

unread,
Jun 27, 2016, 12:25:40 PM6/27/16
to open...@googlegroups.com
Please provide links to original compressed image, and the code you use to decompress.
Also, perhaps you will get more help on a QT forum.

--
You are subscribed to the mailing-list of the OpenJPEG project (www.openjpeg.org)
To post: email to open...@googlegroups.com
To unsubscribe: email to openjpeg+u...@googlegroups.com
For more options: visit http://groups.google.com/group/openjpeg
OpenJPEG is mainly supported by :
* UCL Image and Signal Processing Group (http://sites.uclouvain.be/ispgroup)
* IntoPIX (www.intopix.com)

Mario Emmenlauer

unread,
Jun 27, 2016, 1:05:31 PM6/27/16
to open...@googlegroups.com

Hi,

you do not mention what is the slow part. I would assume its the
image.setPixel() method that is not fast. I recll from QT3 that there
was a much faster way to access image memory with a direct memcopy-
style access. But I don't remember anything specific. If your question
is mostly related to QT, you should really ask on a QT-specific
forum.

Cheers,

Mario
> <https://lh3.googleusercontent.com/-p-Ht7Lm2ol0/V3EMFIvHwzI/AAAAAAAAACE/qiP79IrMwa4Oaibf0TZkS-e0QOAn0hk7wCLcB/s1600/decoded.jpg>
>
> --
> You are subscribed to the mailing-list of the OpenJPEG project (www.openjpeg.org)
> To post: email to open...@googlegroups.com
> To unsubscribe: email to openjpeg+u...@googlegroups.com
> For more options: visit http://groups.google.com/group/openjpeg
> OpenJPEG is mainly supported by :
> * UCL Image and Signal Processing Group (http://sites.uclouvain.be/ispgroup)
> * IntoPIX (www.intopix.com)



Viele Gruesse,

Mario Emmenlauer


--
BioDataAnalysis GmbH, Mario Emmenlauer Tel. Buero: +49-89-74677203
Balanstr. 43 mailto: memmenlauer * biodataanalysis.de
D-81669 München http://www.biodataanalysis.de/

Matthew Woehlke

unread,
Jun 27, 2016, 2:17:52 PM6/27/16
to open...@googlegroups.com
On 2016-06-27 07:23, tlal...@gmail.com wrote:
> currently I am attempting to write an application that generates a preview
> of decoded JPEG2000 images in Qt. After decoding the image I use the
> following code to create a QImage:
>
> QImage image(width, height, QImage::Format_RGB32); // create image
>
> for (int x = 0; x < width; x++){
> for (int y = 0; y < height; y++){
>
> QRgb argb = qRgba(
> psImage->comps[0].data[x * y], //red
> psImage->comps[1].data[x * y], //green
> psImage->comps[2].data[x * y], //blue
> 255); //alpha
>
> image.setPixel(QPoint(x,y), argb);
> }
> }
>
> The creation of the QImage currently takes around 200ms on my average
> notebook for the 1920x540 image. Also the image content is useless (see
> attachment).

Well... the way you are computing the pixel index looks fishy. I think
you mean something like 'y*width + x'¹. Also, using the QPoint overload
of setPixel may be less efficient than passing x and y separately.

Also, using y for the inner iteration is likely causing massive cache
inefficiency; try switching your inner and outer loops.

(¹ I often hoist the computation of the scanline offset out of the inner
loop. Even better, though, use QImage::scanLine outside the inner loop,
and in the inner loop, write to the data directly rather than using
QImage::setPixel. Don't forget the cast to QRgb* — see the Qt docs. All
of this also assumes that you switch the loops...)

Try this (not tested, may contain typos):

for (int y = 0; y < height; ++y)
{
auto const ky = y * width;
auto const l = reinterpret_cast<QRgb*>(image.scanLine(y));
for (int x = 0; x < width; ++x)
{
auto const k = ky + x;
l[x] = qRgb(psImage->comps[0].data[k],
psImage->comps[1].data[k],
psImage->comps[2].data[k]);
}
}

(qRgb(r,g,b) is equivalent to qRgba(r,g,b,255)...)

--
Matthew

tlal...@gmail.com

unread,
Jun 30, 2016, 9:13:02 AM6/30/16
to OpenJPEG
Thanks for the input! Sorry I forgot to mention details concerning main speed bumps. This is (working) code I have so far in anyone is interested in this topic.
Speed is ok for now. If anyone has ideas for improvements, they are very welcome :)

QImage JPEG2000::DataToQImage(int decod_level, opj_image_t *psImage)
{
   
    QTime myTimer;
    myTimer.start();

    int width = psImage->x1; // full width
    int height = psImage->y1; // full hight
    int w = width / pow(2, decod_level);
    int h = height / pow(2, decod_level);

    QImage image(w,h, QImage::Format_RGB32); // create image

    // check if 10bit -> 8bit adjustment is neccesary
    int adjustR, adjustG, adjustB;
    if (psImage->comps[0].prec > 8) {
        adjustR = (int)psImage->comps[0].prec - 8;
    }else{
        adjustR = 0;
    }
       
    if (psImage->comps[1].prec > 8) {
        adjustG = (int)psImage->comps[1].prec - 8;
    }else{
        adjustG = 0;
    }
       
    if (psImage->comps[2].prec > 8) {
        adjustB = (int)psImage->comps[2].prec - 8;
    }else{
        adjustB = 0;
    }
       
    int r, g, b;
    int i = 0;

    // check wheather RGB or Yuv
    if (psImage->numcomps
        && psImage->comps[0].dx == psImage->comps[1].dx
        && psImage->comps[1].dx == psImage->comps[2].dx
        && psImage->comps[0].dy == psImage->comps[1].dy
        && psImage->comps[1].dy == psImage->comps[2].dy){
        // RGB

        for (int y = 0; y < h; y++){

            QRgb* row = reinterpret_cast<QRgb*>(image.scanLine((h - y) - 1)); // get current line

            for (int x = 0; x < w; x++){

                // red
                r = psImage->comps[0].data[(h - y)*width - (width - x)];
                r = ((r >> adjustR) + ((r >> (adjustR - 1)) % 2)); // 10 bit -> 8 bit
                if (r > 255) r = 255; else if (r < 0) r = 0; // clamp

                // green
                g = psImage->comps[1].data[(h - y)*width - (width - x)];
                g = ((g >> adjustR) + ((g >> (adjustG - 1)) % 2)); // 10 bit -> 8 bit
                if (g > 255) g = 255; else if (g < 0) g = 0; // clamp

                // blue
                b = psImage->comps[2].data[(h - y)*width - (width - x)];
                b = ((b >> adjustR) + ((b >> (adjustB - 1)) % 2)); // 10 bit -> 8 bit
                if (b > 255) b = 255; else if (b < 0) b = 0; // clamp

                row[x] = qRgb(r, g, b);
                i++;
            }
        }
    }else{ // YUV
       
        int Y, u , v;
        int adjustYuv = pow(2, adjustR);

        for (int y = 0; y < h; y++){

            QRgb* row = reinterpret_cast<QRgb*>(image.scanLine((h - y) - 1)); // get current line

            for (int x = 0; x < w; x++){

                // get Yuv
                Y = psImage->comps[0].data[(h - y)*width - (width - x)];
                u = psImage->comps[1].data[((h - y)*width - (width - x)) % 2];
                v = psImage->comps[2].data[((h - y)*width - (width - x)) % 2];

                // convert to rgb
                r = (int)1.164*(Y - 16 * adjustYuv) + 1.596*(v - (128 * adjustYuv));
                g = (int)1.164*(Y - 16 * adjustYuv) - 0.813*(v - (128 * adjustYuv) - 0.391*(u - 128 * adjustYuv));
                b = (int)1.164*(Y - 16 * adjustYuv) + 2.018*(u - (128 * adjustYuv));

                // adjust red
                r = ((r >> adjustR) + ((r >> (adjustR - 1)) % 2)); // 10 bit -> 8 bit
                if (r > 255) r = 255; else if (r < 0) r = 0; // clamp

                // adjust green
                g = ((g >> adjustR) + ((g >> (adjustG - 1)) % 2)); // 10 bit -> 8 bit
                if (g > 255) g = 255; else if (g < 0) g = 0; // clamp

                // adjust blue
                b = ((b >> adjustR) + ((b >> (adjustB - 1)) % 2)); // 10 bit -> 8 bit
                if (b > 255) b = 255; else if (b < 0) b = 0; // clamp

                row[x] = qRgb(r, g, b);

                i++;
            }
        }
    }

    OPENJPEG_H::opj_image_destroy(psImage); // free allocated memory

    int nMilliseconds = myTimer.elapsed();
    qDebug() << "converting J2K to QImage took" << nMilliseconds;

    return image;
Reply all
Reply to author
Forward
0 new messages