skip to Main Content

My telegram bot is designed to do image classification so I need to first read in the image from the user, for example, by using cv2.imread(telegram_image.jpeg, 1) before doing any processing and running my model on it. Is there a way to do this without having to download the image file from the telegram bot?

This is the code I have so far:

bot = telegram.Bot(token=TOKEN)
@app.route('/{}'.format(TOKEN), methods=['POST'])
def start():
    # retrieve the message in JSON and then transform it to Telegram object
    update = telegram.Update.de_json(request.get_json(force=True), bot)
    chat_id = update.message.chat.id
    msg_id = update.message.message_id
    imageId = update.message.photo[len(update.message.photo)-1].file_id

I am trying to deploy on Heroku (using Flask), but was having issues previously trying to download the files using update.message.photo[-1].get_file().download(). The code ran without errors but I couldn’t find the image file anywhere.

Sorry I am quite new to this, would really appreciate any help or suggestions, thank you!

2

Answers


  1. I suggest using python-telegram-bot for this, if you aren’t already. The wiki is great, and avoids the use of Flask.

    You can avoid saving the file to disk, and store it in memory using BytesIO. A function to handle a message might look like this:

    from io import BytesIO
    
    def photo(update: Update, context: CallbackContext):
        file = context.bot.get_file(update.message.photo[-1].file_id)
        f =  BytesIO(file.download_as_bytearray())
    
        # f is now a file object you can do something with
    
        result = somefunction(f)
    
        response = 'I procsseed that and the result was %s' % (result,)
    
        context.bot.send_message(chat_id=update.message.chat_id, text=response)
    

    Then add the handler to the dispatcher. Notice by using Filters.photo only messages which are photos will reach this handler:

    photo_handler = MessageHandler(Filters.photo, photo)
    dispatcher.add_handler(photo_handler)
    

    This supports the latest version (v12) of the API.

    You may also wish to have a look at a script I put together: tg_client.py. This is part of a larger repo which does image processing via the Yolov3 library. It also implements support for locking bot communication down to your own telegram user ID (see my wiki page for more info).

    You could probably modify this for your own needs by swapping the upload function out for something that calls your own processing script.


    EDIT: I think I partially misread your question, so I’ll answer this part:

    by using cv2.imread(telegram_image.jpeg, 1) before doing any processing and running my model on it. Is there a way to do this without having to download the image file from the telegram bot?

    I’ve handled this in my code with thanks to this answer which suggests the use of cv2.imdecode in place of cv2.imread.

    So somefunction above, could handle this like:

    def somefunction(input_stream):
        image = cv2.imdecode(numpy.fromstring(input_stream, numpy.uint8), 1)
    
        # image is now what cv2.imread('filename.jpg',1) would have returned.
    
        # rest of your code.
    
        return 'the result of the processing'
    

    This avoids writing the file to disk, as it’s all handled in memory.

    Login or Signup to reply.
  2. This helped me:

    def get_image(update, context):
        from io import BytesIO
        photo = update.message.photo[-1].get_file()
        # photo.download('img.jpg')
        # img = cv2.imread('img.jpg')
        img = cv2.imdecode(np.fromstring(BytesIO(photo.download_as_bytearray()).getvalue(), np.uint8), 1)
        ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search