Rendering list of card images taking too long

Hi all,

I am creating an app that takes user-based parameters as text input, and all the images that match the user-based parameters are shown as dbc.Cards.

This is what my callback looks like:

This is the HTML component:
image

Rendering images in such a fashion takes a very long to render. For example, 100 cards take about 18 secs to show up on the screen :frowning:

Can anyone help me with this one?

Hi @ankita-unsw welocme to the forums.

What is the shape of this array?

Thank you @AIMPED.

The size of the images are (640, 640, 3). They are RGB images

So we are talking about roughly 9.5MB x 100 images?

You might try reducing the resolution before putting the images into the dbc.Card()

More like 2MB x 100 images.

I tried reducing the resolution, but it still doesn’t reduce the time images take to show up.
I believe the issue is how I render the cards list returned by the callback.

image

How did you change the resolution? Even without creating the thumbnails wit PIL (commented line) this seems to be faster than 18 seconds:

from dash import Dash, Input, Output, html
import dash_bootstrap_components as dbc
import numpy as np
from PIL import Image


app = Dash(__name__)

app.layout = html.Div(
    [
        html.Button('click', id='btn'),
        html.Div(
            id='out',
            children=[]
        )
    ]
)


@app.callback(
    Output('out', 'children'),
    Input('btn', 'n_clicks'),
    prevent_initial_call=True
)
def update_styles(_):
    cards = []
    for idx in range(0, 100):
        arr = np.stack(
            [np.ones(shape=(640, 640)) * np.random.randint(0, 255) for _ in range(3)]
            , axis=-1
        )
        pil_img = Image.fromarray(
            arr.astype(np.uint8),
            mode="RGB"
        )
        #pil_img.thumbnail(size=(60, 60))
        cards.append(generate_thumbnail(pil_img))
    return cards


def generate_thumbnail(img):
    return dbc.Card(
        [
            dbc.CardImg(
                src=img,
                top=True,
                style={'width': '200px'}
            ),
            dbc.CardFooter(html.H4('Just a text'))
        ],
    )


if __name__ == '__main__':
    app.run_server(debug=True)

Thanks, @AIMPED. The example you mentioned runs and renders at lightning speed!

Here is the difference I see:

Your example:

My example:
This is about 100 images that I am trying to render.

Also to adjust the image resolution here is what I added:

def generate_thumbnail(img):
    return dbc.Card(
        [
            dbc.CardImg(
                src=img,
                top=True,
                style={'width': '200px', 'image-resolution': '45dpi'}
            ),
            dbc.CardFooter(html.H4('Just a text'))
        ],
    )

Hi @ankita-unsw my conclusion would be, that the way you extract your arrays is the bottleneck. Maybe the get_img_idx_range(), maybe image_batch (where do you use img_select?), maybe image_tiles_select

It’ll be difficult to help you any further.

Hi @AIMPED,

I just wanted to mention that I solved this issue and it turns out the code was working just fine. It was the images that were a bottleneck. The images read were of size 3000 x 3000 and then downsized to 200 x 200 on the dash side while rendering.

To solve this, I created image thumbnails that were smaller in size than 3000 x 3000 and also used multi-threading as these were stored on AWS S3.

Thanks for your help :smiley:

1 Like