Libvips: problèmes de performances de l'API Web

Créé le 19 janv. 2018  ·  5Commentaires  ·  Source: libvips/libvips

Salut,

Je souhaite utiliser l'API Web pour pyvips.
Mais très mauvaise performance. Où est-ce que je fais des erreurs ?

Mon code suit ;

bonjour.py

from flask import Flask
from Image import ImageTransform
from flask import request
from flask import send_file
import io

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

@app.route("/image")
def image():
    image_value = request.args.get('image')
    i = ImageTransform(image_value)
    i.set_transform()
    a = i.image.write_to_buffer('.jpeg')
    return send_file(io.BytesIO(a), mimetype='image/jpg')

Image.py

import pyvips
import math

class ImageTransform(object):
    image = None

    def __init__(self, file_name):
        self.image = pyvips.Image.new_from_file(file_name, access='sequential')

    def set_resize_transform(self, width, height):
        im = self.image
        mem = im.write_to_buffer('.jpeg[Q=80]')
        im = pyvips.Image.thumbnail_buffer(mem, width, height=height)

        im = im.bandjoin(255)
        im = im.gravity("centre", width, height,
                            extend="background",
                            background=[244, 244, 244, 255])
        self.image = im                            
        pass
    def set_ratio_and_watermark_transform(self):
        im = self.image
        # ##### ######
        # Trigonometry: Tangent = Opposite / Adjacent
        tangent = im.height/im.width
        # convert arctangent to degrees
        angle = math.atan(tangent)*(180/math.pi);

        water_mark_x = 140
        water_mark_y = 140
        water_mark_len = 16
        # a^2 = b^2 + c^2 ; a = sqrt(b^2 + c^2)
        half_hypotenuse = math.sqrt(im.height*im.height + im.width*im.width)/2;
        font_size = int(math.hypot(im.height, im.width)/math.hypot(water_mark_x, water_mark_y)*(4 + int(water_mark_len/2)))

        text = pyvips.Image.text("text text text", font = "Futura Medium", align='centre', width = 500, dpi = (font_size*4))
        text = text.linear(0.3, 0)

        text = text.similarity(angle=angle)

        x = (im.width-text.width)/2
        y = (im.height-text.height)/2

        text = text.embed(x, y, text.width + x, text.height + y, extend="copy")

        w = im.width if text.width > im.width else text.width
        h = im.height if text.height > im.height else text.height

        im = text.ifthenelse(255, im, blend=True)      
        self.image = im

    def set_transform(self, type=int):
        self.set_ratio_and_watermark_transform()
        self.set_resize_transform(600, 450)

    def write_image(self,dest_name):
        self.image.write_to_file(dest_name)

```bash
FLASK_APP=exécution de la fiole hello.py

```bash
ab -c 10 -n 10 http://54.229.246.74/image\?image\=foto.jpeg
question

Commentaire le plus utile

Je pense que j'ajouterais le filigrane comme ceci :

# in libvips 8.6, you can get text to automatically size to fill a rectangle
text = pyvips.Image.text("text text text", 
                         font="Futura Medium", align="centre", 
                         width=300, height=300)  

# scale down brightness, then back to 8 bit ... this will avoid float arithmetic
# for the rotate/expand/ifthenelse
text = (text * 0.3).cast("uchar")

tangent = float(im.width) / im.height
angle = math.atan(tangent) * (180 / math.pi)
text = text.similarity(angle=angle)
text = text.gravity("centre", target_width, target_height)

im = text.ifthenelse(255, im, blend=True) 

C'est donc en utilisant la nouvelle fonctionnalité "taille du texte pour ajuster la boîte" dans 8.6, en utilisant x * 0.3 au lieu de linear (ils font la même chose, la surcharge de l'opérateur est juste plus facile à lire), en gardant le text en 8 bits pour éviter de flotter plus tard, et en utilisant gravity pour rendre le embed un peu plus simple.

Tous les 5 commentaires

Bonjour @volkan ,

Je réorganiserais votre pipeline en quelque chose comme :

  1. Utilisez thumbnail pour ouvrir l'image et réduire la taille en une seule opération
  2. Ajouter la superposition de filigrane
  3. Enfin, utilisez gravity pour ajouter l'arrière-plan

Je vais te faire un exemple.

Voici un programme de test qui exécute votre code et un éventuel nouveau pipeline. J'ai changé la ligne tangente dans votre version en :

        tangent = float(im.width) / im.height

Mais sinon inchangé.

import time
import sys
import math
import pyvips

from Image import ImageTransform

start = time.time()
i = ImageTransform(sys.argv[1])
i.set_transform()
i.write_image(sys.argv[2])
end = time.time()
print "ImageTransform() took ", end - start

start = time.time()

target_width = 600
target_height = 450         

# efficiently load and downsize in one operation
im = pyvips.Image.thumbnail(sys.argv[1], target_width, height=target_height)

# watermark
tangent = float(im.width) / im.height
angle = math.atan(tangent) * (180 / math.pi)
water_mark_x = 140
water_mark_y = 140
water_mark_len = 16
half_hypotenuse = math.sqrt(im.height*im.height + im.width*im.width)/2;
font_size = int(math.hypot(im.height, im.width)/math.hypot(water_mark_x, water_mark_y)*(4 + int(water_mark_len/2)))
text = pyvips.Image.text("text text text", font = "Futura Medium", align='centre', width = 500, dpi = (font_size*4))
text = text.linear(0.3, 0)
text = text.similarity(angle=angle)
x = (im.width - text.width) / 2
y = (im.height - text.height) / 2
text = text.embed(x, y, text.width + x, text.height + y, extend="copy")
w = im.width if text.width > im.width else text.width
h = im.height if text.height > im.height else text.height
im = text.ifthenelse(255, im, blend=True)  

# add alpha and margins
im = im.bandjoin(255)
im = im.gravity("centre", target_width, target_height,
                    extend="background",
                    background=[244, 244, 244, 255])

im.write_to_file(sys.argv[2])

end = time.time()

print "after revision, took ", end - start

Sur cet ordinateur portable avec une image 6k x 4k, je vois :

$ python volkan.py ~/pics/theo.jpg x.jpg
ImageTransform() took  0.490525960922
after revision, took  0.0774891376495

Vous pourriez rendre votre code de filigrane un peu plus simple, je vais essayer.

Je pense que j'ajouterais le filigrane comme ceci :

# in libvips 8.6, you can get text to automatically size to fill a rectangle
text = pyvips.Image.text("text text text", 
                         font="Futura Medium", align="centre", 
                         width=300, height=300)  

# scale down brightness, then back to 8 bit ... this will avoid float arithmetic
# for the rotate/expand/ifthenelse
text = (text * 0.3).cast("uchar")

tangent = float(im.width) / im.height
angle = math.atan(tangent) * (180 / math.pi)
text = text.similarity(angle=angle)
text = text.gravity("centre", target_width, target_height)

im = text.ifthenelse(255, im, blend=True) 

C'est donc en utilisant la nouvelle fonctionnalité "taille du texte pour ajuster la boîte" dans 8.6, en utilisant x * 0.3 au lieu de linear (ils font la même chose, la surcharge de l'opérateur est juste plus facile à lire), en gardant le text en 8 bits pour éviter de flotter plus tard, et en utilisant gravity pour rendre le embed un peu plus simple.

@jcupitt vos exemples sont très utiles. Merci.

D'accord, je vais fermer !

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

harukizaemon picture harukizaemon  ·  4Commentaires

huskier picture huskier  ·  4Commentaires

felixbuenemann picture felixbuenemann  ·  4Commentaires

solisoft picture solisoft  ·  3Commentaires

AKlein920 picture AKlein920  ·  3Commentaires