[PYTHON] A script that makes it easy to create rich menus with the LINE Messaging API

Overview

If you set the rich menu from the Messaging API, you can set it quite flexibly, and you can set up to 20 buttons. However, it is ridiculously troublesome to create Json to set it, so I wrote a script that can be set easily.

sample.png

For example, if you have an image like this If you set eight buttons to each circle, it would be too tedious to find out the coordinates, height, and width.

step 1

First, create an original image with a size of 2500x1686 for the rich menu. Just like the image this time, it's fine if it's just a simple figure, but since it can't recognize complicated figures such as photos and characters, it's a good idea to create individual images that emphasize only the part you want to use as a button.

Let's call the image where the button part is easy to understand `` `sample.png```

Step 2

Feed the script.

$ python menu_gen.py sample.png

The script looks like this.

menu_gen.py


import cv2
import json
import collections as cl
import codecs
import sys

def main():

  args = sys.argv

  file_name = args[1]

  img_color = cv2.imread(file_name) #Import original image
  img_gray = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE) #Image loading in grayscale
  ret, img_binary = cv2.threshold(img_gray, 250, 255, cv2.THRESH_BINARY_INV) #Binarize grayscale images
  contours, hierarchy = cv2.findContours(img_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #Contour extraction
  #cv2.drawContours(img_color, contours, -1, (0,0,255), 2) #Draw red on the contour
  print(len(contours),"I found one") #Number of contours

  rich_menu_json = cl.OrderedDict()
  rich_menu_json["size"] = {"width": 2500, "height": 1686}
  rich_menu_json["selected"] = "true"
  rich_menu_json["name"] = file_name
  rich_menu_json["chatBarText"] = 'menu'
  rich_menu_json["areas"] = []

  for i, c in enumerate(contours):
    x,y,w,h = cv2.boundingRect(c) #Rectangle judgment
    # print("["+str(i)+"]",x,y,w,h)

    img_color = cv2.rectangle(img_color, (x,y), (x+w, y+h), (255,0,0), 3)
    img_color = cv2.putText(img_color, "b_"+str(i), (x+int(w/3),y+int(h/2)), cv2.FONT_HERSHEY_SIMPLEX, 4, (255,255,255), 2, cv2.LINE_AA)

    tmp = cl.OrderedDict()
    tmp["bounds"] = {
      "x": x,
      "y": y,
      "width": w,
      "height": h
    }
    tmp["action"] = {
      "type": "postback",
      "label": "b_"+str(i),
      "data": "{  }",
      "displayText": str(i)
    }
    rich_menu_json["areas"].append(tmp)



  fw = codecs.open(file_name.split('.')[0]+"_created_.json", 'w', "utf-8")
  json.dump(rich_menu_json, fw, indent=4, ensure_ascii=False)

  print('''
Create a rich menu with the following contents

  curl -v -X POST https://api.line.me/v2/bot/richmenu \\
  -H 'Authorization: Bearer {Access token}' \\
  -H 'Content-Type: application/json' \\
  -d \\
  '
Insert the edited Json here
  '

  ''')

  cv2.imwrite(file_name.split('.')[0]+"_created_.jpg ", img_color)
  cv2.imshow("window", img_color)
  cv2.waitKey()
  cv2.destroyAllWindows()

if __name__ == '__main__':
  main()

Then, an image with a label for each button like `` `b_1``` is generated like this.

sample_created_.jpg

At the same time, `` `sample_created.json``` is created from the coordinates, height, and width information.

It looks like the following

{
    "size": {
        "width": 2500,
        "height": 1686
    },
    "selected": "true",
    "name": "sample.png ",
    "chatBarText": "menu",
    "areas": [
        {
            "bounds": {
                "x": 91,
                "y": 1131,
                "width": 407,
                "height": 407
            },
            "action": {
                "type": "postback",
                "label": "b_0",
                "data": "{  }",
                "displayText": "0"
            }
        },
        {
            "bounds": {
                "x": 2002,
                "y": 1130,
                "width": 407,
                "height": 407
            },
            "action": {
                "type": "postback",
                "label": "b_1",
                "data": "{  }",
                "displayText": "1"
            }
        },
        {
            "bounds": {
                "x": 1047,
                "y": 1130,
                "width": 406,
                "height": 407
            },
            "action": {
                "type": "postback",
                "label": "b_2",
                "data": "{  }",
                "displayText": "2"
            }
        },
        {
            "bounds": {
                "x": 1534,
                "y": 640,
                "width": 407,
                "height": 407
            },
            "action": {
                "type": "postback",
                "label": "b_3",
                "data": "{  }",
                "displayText": "3"
            }
        },
        {
            "bounds": {
                "x": 559,
                "y": 639,
                "width": 407,
                "height": 407
            },
            "action": {
                "type": "postback",
                "label": "b_4",
                "data": "{  }",
                "displayText": "4"
            }
        },
        {
            "bounds": {
                "x": 1047,
                "y": 149,
                "width": 406,
                "height": 407
            },
            "action": {
                "type": "postback",
                "label": "b_5",
                "data": "{  }",
                "displayText": "5"
            }
        },
        {
            "bounds": {
                "x": 91,
                "y": 149,
                "width": 407,
                "height": 407
            },
            "action": {
                "type": "postback",
                "label": "b_6",
                "data": "{  }",
                "displayText": "6"
            }
        },
        {
            "bounds": {
                "x": 2002,
                "y": 148,
                "width": 407,
                "height": 407
            },
            "action": {
                "type": "postback",
                "label": "b_7",
                "data": "{  }",
                "displayText": "7"
            }
        }
    ]
}

For the time being, it is in postback format, but it seems that you can save time by filling in the contents while comparing the contents around here with the image.

It's a rough explanation, but if it helps someone.

Recommended Posts

A script that makes it easy to create rich menus with the LINE Messaging API
[LINE Messaging API] Create a BOT that connects with someone with Python
[LINE Messaging API] Create a rich menu in Python
A story that makes it easy to estimate the living area using Elasticsearch and Python
[Python] I wrote a test of "Streamlit" that makes it easy to create visualization applications.
Create a REST API to operate dynamodb with the Django REST Framework
Create a web page that runs a model that increases the resolution of the image using gradio, which makes it easy to create a web screen
I tried to make a site that makes it easy to see the update information of Azure
[LINE Messaging API] I want to send a message from the program to everyone's LINE
Let's create it by applying Protocol Buffer to the API with Serverless Framework.
I want to create an API that returns a model with a recursive relationship in the Django REST Framework
How to create a submenu with the [Blender] plugin
Create a tweet heatmap with the Google Maps API
[LINE Messaging API] Create parrot return BOT with Python
A simple system that automatically shoots with object detection and sends it to LINE
Try to create a waveform (audio spectrum) that moves according to the sound with python
I made a tool that makes it a little easier to create and install a public key.
Generate a password that is easy to remember with apg
Let's create a script that registers with Ideone.com in Python.
Probably the easiest way to create a pdf with Python3
Creating a Python script that supports the e-Stat API (ver.2)
Steps to create a Job that pulls a Docker image and tests it with Github Actions
Throw appointments to others with the LINE WORKS calendar API
A story that makes it easier to see Model debugging in the Django + SQLAlchemy environment
Tornado-Let's create a Web API that easily returns JSON with JSON
Create a deploy script with fabric and cuisine and reuse it
Create a web API that can deliver images with Django
[Python] Create a program to delete line breaks in the clipboard + Register as a shortcut with windows
Create an alias for Route53 to CloudFront with the AWS API
How easy is it to synthesize a drug on the market?
I created a Python library to call the LINE WORKS API
Create a shell script to run the python file multiple times
Create REST API that returns the current time with Python3 + Falcon
Write a script to calculate the distance with Elasticsearch 5 system painless
A script that returns 0, 1 attached to the first Python prime number
Create a poster with matplotlib to visualize multiplication tables that remember multiplication
How to send a request to the DMM (FANZA) API with python
Try to create a Qiita article with REST API [Environmental preparation]
How to create a serverless machine learning API with AWS Lambda
[Python] Create a script that uses FeedParser and LINE Notify to notify LINE of the latest information on the new coronavirus of the Ministry of Health, Labor and Welfare.
I made a POST script to create an issue on Github and register it in the Project
A story that visualizes the present of Qiita with Qiita API + Elasticsearch + Kibana
How to make an artificial intelligence LINE bot with Flask + LINE Messaging API
I tried to make "Sakurai-san" a LINE BOT with API Gateway + Lambda
How to create a wrapper that preserves the signature of the function to wrap
It seems that cancelall childorders can be used to cancel all parent orders (special orders) with the bitflyer API
Story of making a virtual planetarium [Until a beginner makes a model with a script and manages to put it together]
A class that hits the DMM API
Create a star system with Blender 2.80 script
Prepare a development environment that is portable and easy to duplicate without polluting the environment with Python embeddable (Windows)
Script to create a Mac dictionary file
Create a simple app that incorporates the Fetch API of Ajax requests in Flask and explain it quickly
When I tried to create a virtual environment with Python, it didn't work
Zip-compress any file with the [shell] command to create a file and delete the original file.
Create an app that works well with people's reports using the COTOHA API
LINE Bot sent me the scraping results of IT trend information [LINE Messaging API]
I wrote a script to revive the gulp watch that will die soon
[Free] Hit the Clash Royale API from lambda and send it to LINE
Convert the cURL API to a Python script (using IBM Cloud object storage)
Python script that makes UTF-8 files with all BOMs under the folder without BOMs
Create a filter to get an Access Token in the Graph API (Flask)