Loomie™ 3D Avatar Platform
  • Welcome
  • REST API Tutorials
    • API Credentials
    • Create Avatar & Render
    • Create Avatar & Render (fast)
    • Create Avatar & Download GLTF
    • Create Stickers & Animations
  • Voice2Animation SDK Tutorials
    • Unity Tutorial
    • Loom.ai Facial Rig Specification
  • Loomie SDK Tutorials
    • Deploying the Docker Image
    • Example App Walkthrough
      • Example App Full Source
  • REST API
    • Authentication
      • Authorization Code Flow
      • Authorization Code Flow with PKCE
      • Client Credentials Flow
      • Implicit Flow
      • Refresh Token Flow
      • Resource Owner Flow
    • Authorization
    • Avatars
      • List
      • Create
      • Resolve Status
      • Delete
      • Attachments
        • List
        • Resolve
      • Renderings
        • List
        • Create
        • Resolve
        • Resolve Status
    • Schema
      • Animation
      • Attachment Type
      • Dimensions
      • Quota
      • Scope
      • Status
      • Sticker
Powered by GitBook
On this page

Was this helpful?

  1. Loomie SDK Tutorials
  2. Example App Walkthrough

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)
PreviousExample App WalkthroughNextAuthentication

Last updated 5 years ago

Was this helpful?