Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image Conversion being too slow #1

Open
bugbrekr opened this issue Aug 28, 2021 · 4 comments
Open

Image Conversion being too slow #1

bugbrekr opened this issue Aug 28, 2021 · 4 comments

Comments

@bugbrekr
Copy link

Hey, I really love this tool.
Its able to accurately convert images to terminal codes.
But I have one issue - the conversion process is too slow....

Here is an example:
ORIGINAL - 500x500_random.png
image

Command: climage.convert("500x500_random.png", is_unicode=True, width=100)

OUTPUT -
image

And this conversion took about 0.51 seconds.

My original idea was to try to make a real-time video-transmission tool using only the terminal.
But the output video cannot be like 2 FPS....

So is there any way to optimize the conversion process without losing a lot of quality?

@pnappa
Copy link
Owner

pnappa commented Sep 12, 2021

Thanks for the feedback!

I took a look at this, and it looks like most expensive part occurs for non-truecolor colour schemes.

TL;DR: Use is_truecolor=True, is_256colour=False, if your terminal supports it.

Some cProfile stats, sorted by the total time spent in each line, for the input:

convert('image.png', is_unicode=True, width=100)
         2722518 function calls (2539177 primitive calls) in 0.762 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
181030/4540    0.210    0.000    0.627    0.000 kdtree.py:431(_search_node)
   362670    0.120    0.000    0.199    0.000 kdtree.py:382(axis_dist)
   120890    0.061    0.000    0.260    0.000 kdtree.py:396(<listcomp>)
   120890    0.058    0.000    0.336    0.000 kdtree.py:390(dist)
   540962    0.049    0.000    0.049    0.000 climage.py:15(__getitem__)
   362670    0.046    0.000    0.046    0.000 {built-in method math.pow}
   120890    0.027    0.000    0.363    0.000 kdtree.py:418(<lambda>)
   120890    0.019    0.000    0.019    0.000 {built-in method builtins.sum}
   181030    0.017    0.000    0.017    0.000 kdtree.py:172(__nonzero__)
201152/198397    0.011    0.000    0.012    0.000 {built-in method builtins.len}

Now, it's much different for this:

convert('image.png', is_unicode=True, width=100, is_truecolor=True, is_256color=False)

Note, yeah, I notice that it's kinda annoying to enable truecolour, using default values gets in the way here.

Log:

         235341 function calls (230805 primitive calls) in 0.118 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   482/80    0.007    0.000    0.019    0.000 sre_parse.py:493(_parse)
       93    0.006    0.000    0.006    0.000 {built-in method marshal.loads}
        1    0.004    0.004    0.020    0.020 climage.py:123(_toAnsi)
     5272    0.004    0.000    0.004    0.000 {method 'format' of 'str' objects}
    10000    0.004    0.000    0.009    0.000 Image.py:1423(getpixel)
  373/368    0.003    0.000    0.023    0.000 {built-in method builtins.__build_class__}
    13452    0.003    0.000    0.003    0.000 sre_parse.py:233(__next)
    10003    0.003    0.000    0.004    0.000 Image.py:814(load)
   829/76    0.003    0.000    0.007    0.000 sre_compile.py:71(_compile)
        3    0.002    0.001    0.002    0.001 {method 'decode' of 'ImagingDecoder' objects}

I benchmarked a bunch of different invocations, too:

duration = timeit.timeit(lambda: convert('image.png', is_unicode=True, width=2, is_truecolor=True, is_256color=False), number=1000)
print(f"Width=2 (unicode, truecolor) took {duration}")
duration = timeit.timeit(lambda: convert('image.png', is_unicode=True, width=100, is_truecolor=True, is_256color=False), number=1000)
print(f"Width=100 (unicode, truecolor) took {duration}")
duration = timeit.timeit(lambda: convert('image.png', is_unicode=True, width=2, is_truecolor=False, is_256color=True), number=1000)
print(f"Width=2 (unicode, 256color) took {duration}")
duration = timeit.timeit(lambda: convert('image.png', is_unicode=True, width=100, is_truecolor=False, is_256color=True), number=1000)
print(f"Width=100 (unicode, 256color) took {duration}")
duration = timeit.timeit(lambda: convert('image.png', is_unicode=False, width=2, is_truecolor=True, is_256color=False), number=1000)
print(f"Width=2 (truecolor) took {duration}")
duration = timeit.timeit(lambda: convert('image.png', is_unicode=False, width=100, is_truecolor=True, is_256color=False), number=1000)
print(f"Width=100 (truecolor) took {duration}")
duration = timeit.timeit(lambda: convert('image.png', is_unicode=False, width=2, is_truecolor=False, is_256color=True), number=1000)
print(f"Width=2 (256color) took {duration}")
duration = timeit.timeit(lambda: convert('image.png', is_unicode=False, width=100, is_truecolor=False, is_256color=True), number=1000)
print(f"Width=100 (256color) took {duration}")

Prints (this is the time each function call takes, in milliseconds):

Width=2 (unicode, truecolor) took 3.259595004012226
Width=100 (unicode, truecolor) took 13.441674665999017
Width=2 (unicode, 256color) took 3.350438164998195
Width=100 (unicode, 256color) took 314.9447129469918
Width=2 (truecolor) took 3.495372111996403
Width=100 (truecolor) took 6.761303802995826
Width=2 (256color) took 3.4730656869942322
Width=100 (256color) took 140.41951910499483

Which is confirming that the part that's mapping colours from the image to terminal colours is a bit slow. I might try and re-implement it in C++, or investigate different data-structures, because Python's just kinda slow at it. :/

@bugbrekr
Copy link
Author

bugbrekr commented Sep 12, 2021

Thanks, adding is_truecolor=True, is_256color=False did increase the performance :-)
I see that the colour mapping functions take the most time for computing. I hope re-implementing this in C++ optimizes and improves it.

@bugbrekr bugbrekr closed this as completed Dec 2, 2021
@pnappa
Copy link
Owner

pnappa commented Dec 4, 2021

Haha, don't worry about closing the issue, I'm still looking to fix the performance issues for 256 bit colour, just haven't had the time quite yet :)

Thanks again for pointing it out!

@pnappa pnappa reopened this Dec 4, 2021
@bugbrekr
Copy link
Author

bugbrekr commented Dec 5, 2021

Okay, sorry. That's cool then.

Thanks 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants