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.

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.
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```
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.

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.