Example App Full Source

Here's the full source of the example Flask server app; this app is also available in the Docker image at /usr/local/share/loomai/examples/python/loomie-rest.py

# To run:
# - pip3 install flask flask-restful Pillow
# - Include {package root}/python in PYTHONPATH
# - Include {package root}/lib and {package root}/lib-ext in LD_LIBRARY_PATH
# - Set environment variable LOOMAI_LICENSE={contents of license file}
# e.g. LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/pwd/build/install/lib:/pwd/build/install/lib-ext PYTHONPATH=/pwd/build/install/python STYLE_DIR=/pwd/build/install/style/mogloomie python3 /pwd/build/install/examples/python/loomie-rest.py
#
# To get a set of stickers, along with 5 variations:
# curl http://localhost:5000/stickers/5 -F "image=@path/to/image.jpg"
#
# To get a GLTF, along with 5 variations:
# curl http://localhost:5000/gltf/5 -F "image=@path/to/image.jpg"

import PIL.Image
import flask
import flask_restful.reqparse
import io
import loomai.loomie
import numpy
import os
import werkzeug
import zipfile

# Flask-RESTful setup
app = flask.Flask(__name__)
api = flask_restful.Api(app)
create_loomie_parser = flask_restful.reqparse.RequestParser()
create_loomie_parser.add_argument('image', type=werkzeug.datastructures.FileStorage,
                                  location='files')

# Before doing anything with the Loomie API, we need to set our license token. For simplicity we look for it to be set in the environment
loomai.loomie.License.set_license(os.environ.get('LOOMAI_LICENSE'))

# Creating this pre-loads certain expensive resources in the prediction engine, and destroying it cleans those resources up. You'll generally want to create this only once and keep it around for the lifetime of the process.
factory = loomai.loomie.LoomieFactory(os.environ.get('LOOMAI_RESOURCE_ROOT'), loomai.loomie.ThreadingMode.DISPATCHED)


def make_loomie(source):
    image = PIL.Image.open(source)
    bytes = image.tobytes()
    view = loomai.loomie.InterleavedImageViewU8(image.width, image.height, 3,
                                                loomai.loomie.ByteMutableBuffer(bytes),
                                                loomai.loomie.ComponentsOrder.RGB,
                                                loomai.loomie.ImageOrientation.NORMAL)
    return factory.make_loomie(view)


def add_image_to_zip(zip_file, folder, basename, index, image):
    assert image.channel_count == 3

    # Put it in a PIL image
    pil_image = PIL.Image.frombytes("RGB", (image.width, image.height),
                                numpy.array(image.data))

    if image.order == loomai.loomie.ComponentsOrder.BGR:
        # The rendered image is actually BGR, so swizzle it
        b, g, r = pil_image.split()
        pil_image = PIL.Image.merge("RGB", (r, g, b))

    buffer = io.BytesIO()
    pil_image.save(buffer, "PNG")
    buffer.seek(0)

    zip_file.writestr(os.path.join(folder, "%s%02d.png" % (basename, index)), buffer.getvalue())


def add_gltf_to_zip(zip_file, name, loomie):
    data = numpy.array(loomie.get_gltf())
    zip_file.writestr("%s.glb" % name, data)


class stickers(flask_restful.Resource):
    def get(self, variation_count):
        args = create_loomie_parser.parse_args()
        loomie = make_loomie(args['image'])
        render_buffer = bytearray(loomie.get_images_buffer_size(loomie.sticker_image_index_end() - loomie.sticker_image_index_begin()))
        zip_buffer = io.BytesIO()
        with zipfile.ZipFile(zip_buffer, "w") as zip_file:
            images = loomie.get_images(loomie.sticker_image_index_begin(), loomie.sticker_image_index_end(), loomai.loomie.ByteMutableBuffer(render_buffer))
            for index, image in enumerate(images):
                add_image_to_zip(zip_file, "solved", "sticker", index, image)
            for i in range(0, variation_count):
                loomie.apply_random_variation()
                images = loomie.get_images(loomie.sticker_image_index_begin(), loomie.sticker_image_index_end(), loomai.loomie.ByteMutableBuffer(render_buffer))
                for index, image in enumerate(images):
                    add_image_to_zip(zip_file, "variation%02d" % i, "sticker", index, image)
        zip_buffer.seek(0)
        return flask.send_file(zip_buffer, attachment_filename='loomie.zip',
                               mimetype='application/zip')


class sticker(flask_restful.Resource):
    def get(self, index, variation_count):
        args = create_loomie_parser.parse_args()
        loomie = make_loomie(args['image'])
        render_buffer = bytearray(loomie.get_image_buffer_size())
        zip_buffer = io.BytesIO()
        with zipfile.ZipFile(zip_buffer, "w") as zip_file:
            image = loomie.get_image(loomie.sticker_image_index_begin() + index, loomai.loomie.ByteMutableBuffer(render_buffer))
            add_image_to_zip(zip_file, "solved", "sticker", index, image)
            for i in range(0, variation_count):
                loomie.apply_random_variation()
                image = loomie.get_image(loomie.sticker_image_index_begin() + index, loomai.loomie.ByteMutableBuffer(render_buffer))
                add_image_to_zip(zip_file, "variation%02d" % i, "sticker", index, image)
        zip_buffer.seek(0)
        return flask.send_file(zip_buffer, attachment_filename='loomie.zip',
                               mimetype='application/zip')


class poses(flask_restful.Resource):
    def get(self, variation_count):
        args = create_loomie_parser.parse_args()
        loomie = make_loomie(args['image'])
        render_buffer = bytearray(loomie.get_images_buffer_size(loomie.pose_image_index_end() - loomie.pose_image_index_begin()))
        zip_buffer = io.BytesIO()
        with zipfile.ZipFile(zip_buffer, "w") as zip_file:
            images = loomie.get_images(loomie.pose_image_index_begin(), loomie.pose_image_index_end(), loomai.loomie.ByteMutableBuffer(render_buffer))
            for index, image in enumerate(images):
                add_image_to_zip(zip_file, "solved", "pose", index, image)
            for i in range(0, variation_count):
                loomie.apply_random_variation()
                images = loomie.get_images(loomie.pose_image_index_begin(), loomie.pose_image_index_end(), loomai.loomie.ByteMutableBuffer(render_buffer))
                for index, image in enumerate(images):
                    add_image_to_zip(zip_file, "variation%02d" % i, "pose", index, image)
        zip_buffer.seek(0)
        return flask.send_file(zip_buffer, attachment_filename='loomie.zip',
                               mimetype='application/zip')


class pose(flask_restful.Resource):
    def get(self, index, variation_count):
        args = create_loomie_parser.parse_args()
        loomie = make_loomie(args['image'])
        render_buffer = bytearray(loomie.get_image_buffer_size())
        zip_buffer = io.BytesIO()
        with zipfile.ZipFile(zip_buffer, "w") as zip_file:
            image = loomie.get_image(loomie.pose_image_index_begin() + index, loomai.loomie.ByteMutableBuffer(render_buffer))
            add_image_to_zip(zip_file, "solved", "pose", index, image)
            for i in range(0, variation_count):
                loomie.apply_random_variation()
                image = loomie.get_image(loomie.pose_image_index_begin() + index, loomai.loomie.ByteMutableBuffer(render_buffer))
                add_image_to_zip(zip_file, "variation%02d" % i, "pose", index, image)
        zip_buffer.seek(0)
        return flask.send_file(zip_buffer, attachment_filename='loomie.zip',
                               mimetype='application/zip')


class gltf(flask_restful.Resource):
    def get(self, variation_count):
        args = create_loomie_parser.parse_args()
        loomie = make_loomie(args['image'])
        zip_buffer = io.BytesIO()
        with zipfile.ZipFile(zip_buffer, "w") as zip_file:
            add_gltf_to_zip(zip_file, "solved", loomie)
            for i in range(0, variation_count):
                loomie.apply_random_variation()
                add_gltf_to_zip(zip_file, "variation%02d" % i, loomie)
        zip_buffer.seek(0)
        return flask.send_file(zip_buffer, attachment_filename='loomie.zip',
                               mimetype='application/zip')


api.add_resource(stickers, '/stickers/<int:variation_count>')
api.add_resource(sticker, '/sticker/<int:index>/<int:variation_count>')
api.add_resource(poses, '/poses/<int:variation_count>')
api.add_resource(pose, '/pose/<int:index>/<int:variation_count>')
api.add_resource(gltf, '/gltf/<int:variation_count>')

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

Last updated