東京藝術大学の学祭でプリントシール機を出店した話

# はじめに
２０２３年９月１日～３日に開催された東京藝術大学の学祭（通称：藝祭）にて出店した __アスキーアートになるプリ機__ についての技術をまとめた記事となっています。

<img width="500" alt="IMG_5082.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/fb9d8298-56c1-cc36-1ce1-3bff44d4b15b.jpeg">


:::note info
注意
 __今回の企画は私一人で行ったわけではありません。__ あくまで担当範囲内での技術共有、来年度に向けたフィードバックを目的に記事にしています。
今回の企画に携わっていただいたみんなには感謝してもしきれません。ありがとうございました！！！これからもよろしくお願いします！
:::

# 目次
[東京藝術大学テクノロジー研究会とは](#東京藝術大学テクノロジー研究会とは)
[自己紹介](#自己紹介)
[今回の企画概要](#今回の企画概要)
[システム概要](#システム概要)
[当日の様子](#当日の様子)
[実際のコード](#実際のコード)
[さいごに](#さいごに)

# 東京藝術大学テクノロジー研究会とは
東京藝術大学の公式サークルです。実態はDiscordサーバーになっていて、学外の生徒や社会人などいろいろな方がいます。
活動は不定期、CG・プログラミングなどを使って創作をすることを目的で活動しています。
𝕏（Twitter）：https://twitter.com/geidai_techno

# 自己紹介
プリ機の撮影・ラクガキブースの各システムを開発した __[塩田航佑](https://twitter.com/koushioda)__ と申します。

理数科の中高一貫校に通っていました。中高時代、情報工学部という部活でC++を使って競技プログラミングをしたり、高校ではPythonを用いた機械学習について研究したりしていました。また、映画製作に魅了され中学三年生から自主制作で映画を作ったりしています。
そんなこんなで、メディアアート・映像表現を探求できる東京藝術大学先端芸術表現科に在籍しているという感じです。
<INS>※撮影したデータの共有システム、ダウンロード用のWEBサイト開発は尾上（@YumNumm ）くん／ラクガキペンのシステム開発は内田さんが担当しています</INS>

＜尾上君の記事＞

https://qiita.com/YumNumm/items/bb170f594cfb90202084

# 今回の企画概要
５月中旬に差し掛かったある日、「BUG」をテーマにアートマーケットで何かを出店しようという話がサークル内で提案されました。そこで、「アスキーアート」「グリッチノイズ」などについてのリサーチが始まり、最終的にはそれらを体験として楽しんでもらえる「プリントシール機」を出店することにまとまりました。

今回の企画、最大の特徴は「盛る」ではなく「バグ」というコンセプトの元、顔などの情報が文字へと変換され、視認性が低くなることです。従来のプリ機とは違い、匿名性を少し内包するような不思議なプリにできたらと考えました。なぜなら、私自身が自分の写真を誰かと共有することに抵抗感があったからです。私を含め、今までのプリ機に抵抗感があった層にも新たな体験を生み出せないかと思い、進めていったのが今回の企画になります。

 __【企画書の一部】__
<img width="500" alt="F5fINvPaYAAKuap.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/34be7e0a-4ccb-b601-edda-be922f950e28.jpeg">

# システム概要
|||
|:---|:---|
|言語|Python|
|主要ライブラリ|cv2 / numpy / PIL / rembg / tkinter / pygame|
|PC|Mac（撮影ブース） / Windows（ラクガキブース）|
|周辺機器|Logicool C920（WEBカメラ） / BenQ PD2700Q（２７インチモニタ）|

##### ■全体の流れ
１：物販ブースでチケット購入
<img width="500" alt="UUID説明.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/66312624-a70e-3657-43bc-d181473cecd5.png">

２：撮影ブースへ移動
　　▶先ほどのQRコードをカメラにかざす

３：撮影開始
　　▶写真を三枚撮影する
 __【モックGUI】__
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/6452fbf0-e9d2-d973-77b0-7c183e5ade9b.png">

４：ラクガキブースへ移動
　　▶QRコードをカメラにかざす

５：ラクガキスタート
 __【８月下旬GUI】__
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/ce9be6d4-9922-c9e5-f264-e12e08daf643.png">

|撮影された写真|アスキーアート化された写真|
|:---|:---|
|![comp_L_1_temp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/54d046f6-665e-344e-2b79-fc3825acde4f.png)|![AA_L_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/7eec0c5d-8cc1-6ffd-a5ea-ec22de5dd040.png)|
|![comp_L_2_temp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/d794fd23-83f8-174a-5b58-08eddfde04c9.png)|![AA_L_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551871/75e4bc8f-53c8-c075-84c3-77b9a641a2f1.png)|

※撮影された写真にはモザイクが入っています；；

６：体験終了
　　▶チケットのQRコードをスマホで読み込むとダウンロードサイトへ飛ぶ


##### ■撮影ブース
|||
|:---|:---|
|画像処理|cv2/numpy/PIL|
|クロマキー処理|rembg|
|GUI処理|tkinter / pygame|

 __＜画像処理＞__
撮影した写真をアスキーアート化する処理です。
具体的にはキャプチャ画像をグレースケール化して、２５６階調をそれぞれ文字に割り当てるという感じです。

https://qiita.com/Pavaux/items/450ac6823e86b092cfbb

__＜クロマキー処理＞__
Rembgという優秀なライブラリがあったのでこちらを完全に使用しました。

https://dev.classmethod.jp/articles/python-rembg/

__＜GUI処理＞__
ユーザーが操作することはなかったのですが画面変遷と音声ガイドが必要だったのでtkinterとpygameを使用しました。

##### ■ラクガキブース
|||
|:---|:---|
|画像処理|cv2/numpy/PIL|
|GUI処理|tkinter / pygame|

__＜画像処理＞__
ペンでなぞった部分が写真になる処理を加えたり、半透明合成、スタンプの合成などを行っています。
※最終章にあるコードを読んでいただければわかるのですが、cv2とPILがごちゃごちゃで処理することになってしまって最高に重いです。反省です。

__＜GUI処理＞__
ペンやスタンプの選択画面の処理、音声ガイドの処理です。
※こちらもマルチスレッド処理の実装が間に合わなかった点、rootでのマウス検知の限界があり操作感が最悪なので反省です。

##### ■まとめ
今回、初めてGUIを伴ったシステムの開発をしたため調べながらの二か月間だったのですが、「処理が重すぎる」という課題に尽きる気がします。まずはマルチスレッドでの処理は必須でした。また、なぞったところが写真になったりAAになったりするというリアルタイム処理が必須となる今回のシステムは初めてやるにはハードルが高すぎたかもしれません。もっと時間をかけて、よりよい処理を考えていきたいというのが今後の展望になります。

# 当日の様子
たくさんの方に体験していただきありがとうございました。
以下、当日のみなさんの反応と発生した問題についてまとめました。

### 当日の皆さんの反応
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">アスキーアートと融合しちゃう変わったプリクラ機で遊んできた🙌<br><br>藝祭の中での出し物なんだけど、上野公園の中に突如プリクラ機が現れてめちゃ目立ってましたww<br><br>らくがきコーナーではアスキーアート化した写真の一部を元に戻せるようになってて、不思議な感じのプリになりました💓💫 <a href="https://twitter.com/hashtag/%E8%97%9D%E7%A5%AD?src=hash&amp;ref_src=twsrc%5Etfw">#藝祭</a> <a href="https://twitter.com/hashtag/%E8%97%9D%E7%A5%AD2023?src=hash&amp;ref_src=twsrc%5Etfw">#藝祭2023</a> <a href="https://t.co/rW1PkRtnIw">pic.twitter.com/rW1PkRtnIw</a></p>&mdash; なかじ @8/13~Vフレット正式版リリース🎉 (@nkjzm) <a href="https://twitter.com/nkjzm/status/1698315934962962738?ref_src=twsrc%5Etfw">September 3, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E8%97%9D%E7%A5%AD2023?src=hash&amp;ref_src=twsrc%5Etfw">#藝祭2023</a> が終わりました。<br>色々と大変だったけれど、無事に終わってよかった！<br>ご来場、作品をご購入いただいた皆様ありがとうございました😊<br>沢山の方とお話しできて楽しかったです♪<br><br>…ちなみに、今日は研究室メンバーとプリクラを撮ったり、ファミレスで打ち上げしたりして楽しみました🌸 <a href="https://t.co/uM18O506Z2">pic.twitter.com/uM18O506Z2</a></p>&mdash; shino osawa (@hananoutena04) <a href="https://twitter.com/hananoutena04/status/1698311096757879218?ref_src=twsrc%5Etfw">September 3, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E8%97%9D%E7%A5%AD2023?src=hash&amp;ref_src=twsrc%5Etfw">#藝祭2023</a> <a href="https://twitter.com/geisai_koushiki?ref_src=twsrc%5Etfw">@geisai_koushiki</a> <br><br>東京藝大のテクノロジー研究会による「アスキーアートになるプリクラ機」<a href="https://twitter.com/geidai_techno?ref_src=twsrc%5Etfw">@geidai_techno</a> <br><br>研究室メンバーと体験した！<br><br>今日も私は19時まで国際交流棟3階で展示してるよ！来てね〜！ <a href="https://t.co/m5wNYE8u57">pic.twitter.com/m5wNYE8u57</a></p>&mdash; 佐藤はなえ Hanae Sato (@eanahotas) <a href="https://twitter.com/eanahotas/status/1698141607730790870?ref_src=twsrc%5Etfw">September 3, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">藝祭なう。まずは顧問してるテクノロジー研究会のプリクラ見にきた。<br>自作ゲーム機売ってたので買った。 <a href="https://t.co/yHVKIjbpqu">pic.twitter.com/yHVKIjbpqu</a></p>&mdash; 八谷和彦 (@hachiya) <a href="https://twitter.com/hachiya/status/1698219152283181205?ref_src=twsrc%5Etfw">September 3, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### 当日発生した問題

<dl>
  <dt>１：使用電力が多すぎた</dt>
  <dd>屋外での設営だったため、発電機を用いた。事前に計算していたものの、気温などの影響もあり１５：００頃に一度発電機がダウン。安定的な電力供給はなかなか難しい。</dd>
<dd><INS>解決策：昼に一度メンタンスを兼ねてガソリン補給などの時間を設けるようにした。</INS></dd>
  <dt>２：インターネット回線がダウン</dt>
  <dd>画像の共有をテザリングで行っていた。初日はdocomoの５Gギガホプレミアムを使用して行っていたが、まさかのお昼でダウン。問い合わせたところ契約書のなかに<INS>「機械的な発信などにより、1度の音声発信またはデータ通信接続において長時間の通話継続または大量のデータ通信があった場合や、一定時間内に連続で音声発信またはデータ通信接続をした場合など、当社設備に影響をおよぼすと当社が判断した場合は、その音声通話を切断またはそのデータ通信の速度を制限することがあります。」</INS>という記載がありこれに該当した模様。絶対にパソコン同士のデータ共有はLANで有線接続するほうがよかったと反省。しかし、クラウドに画像を挙げる部分には必ずネット回線が必要なため今後も代替案を考える必要がある。</dd>
<dd><INS>解決策：USBを使ってパワー運用。データは当日の２２時にアップするという対応にさせていただき、パソコンとプリンター間の共有は私がUSBを使って行った。（体験までに想定の１０倍以上の時間を必要としてしまいご迷惑をおかけしました。すみません。）</INS></dd>
  <dt>３：設営作業が大変すぎた</dt>
  <dd>公園を使用させていただいている立場だったため毎回設営と解体をやらなくてはいけなかった。その都合もあり次の日に改善したいと思ってもそんな余裕はなく新パッチを適応するための調整などが十分にできなかった。</dd>
<dd><INS>解決策：家で似た環境を構築して家で修正➡当日試すみたいなことをやってみた。（結果は失敗）</INS></dd>
</dl>


# 実際のコード

:::note alert
注意
・一部（画像共有部分の関数など）掲載していないコードがあります
・使用した素材については配布しません
・バグがあります
　当日は再ビルドして解決していましたが、現在も改善中のコードになります
:::

＜ディレクトリ構造＞

```
■ラクガキブース
C:\USERS\USERNAME\デスクトップ\SHOOTING_PURI
│  AAmozi.txt
│  AA_S_1.png
│  AA_S_2.png
│  AA_S_3.png
│  BG.png
│  BG1.png
│  BG2.png
│  BG3.png
│  camera_count0.png
│  camera_count1.png
│  camera_count2.png
│  camera_count3.png
│  camera_loading.png
│  comp_S_1.png
│  comp_S_2.png
│  comp_S_3.png
│  count1.png
│  count2.png
│  count3.png
│  guide.png
│  main.py
│  mask.png
│  notice.png
│  puriGUI_ver1.0.py
│  result_1.png
│  result_2.png
│  result_3.png
│  samplepose1.png
│  samplepose2.png
│  samplepose3.png
│  scene1.png
│  scene3.png
│  UUID.csv
└─shot_picture
    └─customer1
    └─customer2
    └─customer3
    └─customer4
    	.
    	.
    	.
```

```
■ラクガキブース
C:\USERS\USERNAME\デスクトップ\RAKUGAK_PURI
│  AA_L_1.png
│  AA_L_2.png
│  AA_L_3.png
│  bg_1.png
│  bg_1_a.png
│  bg_1_b.png
│  bg_1_c.png
│  bg_2.png
│  bg_3.png
│  bg_4.png
│  brush_widgh1.png
│  brush_widgh1_off.png
│  brush_widgh2.png
│  brush_widgh2_off.png
│  brush_widgh3.png
│  brush_widgh3_off.png
│  brush_widgh4.png
│  brush_widgh4_off.png
│  comp_L_1_temp.png
│  comp_L_2_temp.png
│  comp_L_3_temp.png
│  DL_explanation.wav
│  drawGUI_ver1.0.py
│  icon1.png
│  icon1_off.png
│  icon2.png
│  icon2_off.png
│  icon3.png
│  icon3_off.png
│  icon4.png
│  icon4_off.png
│  icon_stamp1.png
│  icon_stamp1_off.png
│  icon_stamp2.png
│  icon_stamp2_off.png
│  icon_stamp3.png
│  icon_stamp3_off.png
│  icon_stamp4.png
│  icon_stamp4_off.png
│  pen_bg.png
│  printing_explanation.wav
│  QRcodeRead.wav
│  qrread.png
│  rest1.wav
│  rest10.wav
│  rest2.wav
│  rest3.wav
│  rest5.wav
│  result_L_1.png
│  result_L_2.png
│  result_L_3.png
│  scene3_1.png
│  scene3_2.png
│  select_explanation.wav
│  stamp1.png
│  stamp2.png
│  stamp3.png
│  stamp4.png
│  stamp_bg.png
│  start_call.wav
│  time_explanation.wav
│  UUID.csv
```

### 撮影ブース
<details><summary>ソースコード</summary>

使用したライブラリ一覧
```python:puriGUI_ver2.1
import tkinter as tk
import tkinter.ttk as ttk
import cv2
import numpy as np
import tkinter.filedialog
import PIL.ImageTk
import PIL.Image
import os
import pygame
import requests

from PIL import Image, ImageDraw, ImageFont, ImageOps
from rembg import remove  # クロマキーライブラリ
```

***

「world_timer」関数で時間制御。しかし、これが最悪でafterで1秒ループしても少しずれるため力技で処理。撮影するタイミング・音声ガイド・ロードタイミングがずれて大変だった。

また、ロードできなかった場合にもう一度読み込むという処理を入れていないので読めなかったらErrorを吐く。これも最大の反省で、画像が読み込めたのかを判定する変数を作るべきだった。そのため、今回は撮った後３秒したら読み込む形でError回避をするようにした。ものすごく力技なのでアスキーアート化する処理などが３秒以上かかるとバグる。
```python:puriGUI_ver2.1
# 管理関数 ------------------------------------- #
def world_timer():  # 時間管理
    global time, scene_num, shot_count, animation

    time += 1

    if scene_num == 1:
        if time % 10 == 0 and soundFlag[1] == False:
            QRcodeRead.play()
            soundFlag[0] = time
            soundFlag[1] = True
        if time == int(soundFlag[0] + 1):
            soundFlag[1] = False

    if scene_num == 2:
        if time == 3:
            if soundFlag[1] == False:
                position_explanation.play()
                soundFlag[1] = True
        if time == scene2_wait:
            animation = 0
            scene_num = 3
            soundFlag[1] = False

    if scene_num == 3:
        if time == scene2_wait + (shot_time * 3) + 5:  # 7s待機
            show_scene3()
            

        if time > scene2_wait + 4:
            if time == scene2_wait + 5:
                pose1.play()  # かわいくピース
            if time == scene2_wait + shot_time + 4:
                pose2.play()  # うさみみポーズ
            if time == scene2_wait + (shot_time * 2) + 4:
                pose3.play()  # おまかせポーズ
            if ((time - (scene2_wait + (shot_time - 2))) % shot_time) == 0:
                count3.play()
            if ((time - (scene2_wait + (shot_time - 1))) % shot_time) == 0:
                count2.play()
            if ((time - (scene2_wait + (shot_time))) % shot_time) == 0:
                count1.play()
            if ((time - (scene2_wait + (shot_time + 1))) % shot_time) == 0:
                shutter.play()  # シャッター音（効果音ラボより）
        if (time - (scene2_wait + 1)) % shot_time == 0:
            if time > (scene2_wait + 1):
                if shot_count < 3:
                    shot_count += 1

    if scene_num == 4:
        if time == scene2_wait + (shot_time * 3) + 17:  # 10s待機
            show_scene1()

    frame2.after(1000, world_timer)


def road_picture(read_num):  # 画像ロード用関数
    global notice_2, slot1_AF, slot2_AF, slot3_AF, slot4_AF, slot5_AF, slot6_AF

    if read_num == 0:
        notice_2 = tk.PhotoImage(file="notice_2.png")

    if read_num == 2:
        slot1_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/comp_S_1_temp.png"
        )
        slot2_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/AA_S_1.png"
        )

    if read_num == 3:
        slot1_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/comp_S_1_temp.png"
        )
        slot2_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/AA_S_1.png"
        )
        slot3_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/comp_S_2_temp.png"
        )
        slot4_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/AA_S_2.png"
        )

    if read_num == 4:
        slot1_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/comp_S_1_temp.png"
        )
        slot2_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/AA_S_1.png"
        )
        slot3_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/comp_S_2_temp.png"
        )
        slot4_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/AA_S_2.png"
        )
        slot5_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/comp_S_3_temp.png"
        )
        slot6_AF = tk.PhotoImage(
            file="./shot_picture/customer" + str(qr_UUID) + "/AA_S_3.png"
        )


# -------------------------------------------- #
```

***

全部で３つのシーンで構成されている。
それぞれのシーンを見せる時（最上面に移動させる）変数を初期化。
```python:puriGUI_ver2.1
# シーンチェンジ関数 ---------------------------- #
def show_scene1():
    global scene_num, soundFlag, qrreadFlag, data
    scene_num = 1
    soundFlag[1] = False
    qrreadFlag = False
    data = None
    scene1.tkraise()


def show_scene2():
    global scene_num, time, shot_count, soundFlag
    scene_num = 2
    time = 0
    shot_count = 0  # 撮影枚数カウント
    soundFlag[1] = False
    scene2.tkraise()

def show_scene3():
    global scene_num, qr_UUID
    
    ImageTransfer.upload_image(
        qr_UUID, "./shot_picture/customer" + str(qr_UUID) + "/AA_L_1.png"
    )
    ImageTransfer.upload_image(
        qr_UUID, "./shot_picture/customer" + str(qr_UUID) + "/AA_L_2.png"
    )
    ImageTransfer.upload_image(
        qr_UUID, "./shot_picture/customer" + str(qr_UUID) + "/AA_L_3.png"
    )
    ImageTransfer.upload_image(
        qr_UUID, "./shot_picture/customer" + str(qr_UUID) + "/comp_L_1_temp.png"
    )
    ImageTransfer.upload_image(
        qr_UUID, "./shot_picture/customer" + str(qr_UUID) + "/comp_L_2_temp.png"
    )
    ImageTransfer.upload_image(
        qr_UUID, "./shot_picture/customer" + str(qr_UUID) + "/comp_L_3_temp.png"
    )

    rakugaki_move.play()
    scene_num = 4
    scene3.tkraise()

# -------------------------------------------- #
```

***

アスキーアート化する処理部分。
ライブラリがごちゃごちゃでいちいち変換したり戻したりでもっとスマートにできたと思う。特に、いちいち画像ファイルとして書き出して読み込んでという処理がもったいない。

等幅フォントを用いてきれいにAAになるようにはなったもののフォントサイズが整数でしか定義できず、無理やりクロップしたり引き延ばして対応した。正確には少し写真とずれている；；
```python:puriGUI_ver2.1
# 画像加工関数 ---------------------------- #
def printText(img, text, point, size, color):  # テキスト描画処理
    # 等幅フォントであるMenloを使用
    font = ImageFont.truetype("/System/Library/Fonts/Menlo.ttc", size)

    # imgをndarrayからPILに変換
    img_pil = Image.fromarray(img)

    # drawインスタンス生成
    draw = ImageDraw.Draw(img_pil)

    # テキスト描画
    draw.text(point, text, fill=color, font=font)

    # PILからndarrayに変換して返す
    return np.array(img_pil)


def AAFrame():  # AA処理
    capframe = cv2.imread(
        "./shot_picture/customer"
        + str(qr_UUID)
        + "/comp_L_"
        + str(shot_count)
        + "_temp.png"
    )
    capframe = cv2.convertScaleAbs(capframe, alpha=1.3, beta=0)  # コントラスト調整
    moziframe = cv2.resize(capframe, (75, 90))  # 1/12に縮小

    gray = cv2.cvtColor(moziframe, cv2.COLOR_BGR2GRAY)
    gray1 = cv2.equalizeHist(gray)  # ヒストグラムの平坦化処理

    outputM = ""

    # AA化処理
    for gray2 in gray1:
        outputM += "\n"
        for dark in gray2:
            outputM += colorset[dark // 16] * 2

    # 同ファイル内に「AAmozi.txt」を作った上で実行してください
    with open("AAmozi.txt", mode="w") as f:
        f.write(outputM)

    # 改行ごとにリスト化
    mozi_textList = outputM.split("\n")

    AAframe = np.full((1080, 950, 3), (255, 255, 255), dtype=np.uint8)  # 1080*950
    # AAを書き込み
    for i in range(len(mozi_textList)):
        AAframe = printText(
            AAframe, mozi_textList[i], (0, int(i * 11.75)), 10, (0, 0, 0)
        )  # 等倍
        # AAframe = printText(AAframe, mozi_textList[i], (5, 0 + int(i * 7.45)), 6, (0, 0, 0)) #二倍
    # cv2.imwrite('AA.png', AAframe)

    AAfin = AAframe[12:1068, 0:903]
    resize_AAfin_L = cv2.resize(AAfin, (900, 1080))
    cv2.imwrite(
        "./shot_picture/customer" + str(qr_UUID) + "/AA_L_" + str(shot_count) + ".png",
        resize_AAfin_L,
        [cv2.IMWRITE_PNG_COMPRESSION, 9],
    )

    resize_AAfin_S = cv2.resize(resize_AAfin_L, (250, 300))
    cv2.imwrite(
        "./shot_picture/customer" + str(qr_UUID) + "/AA_S_" + str(shot_count) + ".png",
        resize_AAfin_S,
        [cv2.IMWRITE_PNG_COMPRESSION, 9],
    )


def keying(capframe):  # グリーンバック合成処理
    shotframe = cv2.cvtColor(capframe, cv2.COLOR_BGR2RGB)
    shotframe = cv2.resize(shotframe, (1920, 1080))
    human_mask = remove(shotframe)
    resize_human_mask_L = human_mask[0:1080, 510:1410]
    cv2.imwrite(
        "./shot_picture/customer"
        + str(qr_UUID)
        + "/comp_L_"
        + str(shot_count)
        + "_temp.png",
        resize_human_mask_L,
        [cv2.IMWRITE_PNG_COMPRESSION, 9],
    )

    resize_human_mask_S = cv2.resize(resize_human_mask_L, (250, 300))
    cv2.imwrite(
        "./shot_picture/customer"
        + str(qr_UUID)
        + "/comp_S_"
        + str(shot_count)
        + "_temp.png",
        resize_human_mask_S,
        [cv2.IMWRITE_PNG_COMPRESSION, 9],
    )


def image_processing(capframe):
    # ------AA / keying------#
    keying(capframe)
    AAFrame()

# -------------------------------------------- #
```

***

最大の反省ポイント。
afterでループさせて再描画はよかったが、これらがずっと回り続けているのがよくない。絶対にafter_cancel()を使うべきだった。また、マルチスレッドにして描画と画像処理を分けるべき。
※解決しなかったバグとしてはQRコードの判別部分で何度かエラーを吐き、カメラ映像が描画されないという症状があった。「data = detector.detectAndDecode(capframe)」これがよくないみたい。
```python:puriGUI_ver2.1
# 描画関数-------------------------------------- #
def frame1_2_GUI():
    global time, qr_UUID, qrreadFlag
    global data

    if scene_num == 1:
        canvas1_2.delete("all")  # キャッシュ処理

        canvas1_2.create_image(420, 375, image=bg_2)

        ret, capframe = capture.read()
        capframe = cv2.cvtColor(capframe, cv2.COLOR_BGR2RGB)

        if ret == True:
            # QRコードを認識
            data = detector.detectAndDecode(capframe)
            if data != None:
                qr_UUID = data[0]  # https://tekken.work/art-market/[UUID]/
                qr_UUID = qr_UUID.replace("https://tekken.work/art-market/", "")
                qr_UUID = qr_UUID.replace("/", "")

                if qr_UUID in UUID_list:
                    if qrreadFlag == False:
                        is_dir = os.path.exists("shot_picture/customer" + str(qr_UUID))
                        if is_dir == False:  # 二回目を弾くため
                            start_shot.play()

                            show_scene2()

                            os.mkdir(
                                "shot_picture/customer" + str(qr_UUID)
                            )  # 撮影データ補完ファイル作成
                            qrreadFlag = True

        frame1_2.photo = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(capframe))
        canvas1_2.create_image(-246, 50, image=frame1_2.photo, anchor=tkinter.NW)

    frame1_2.after(50, frame1_2_GUI)  # ディレイ・繰り返し処理


def frame2_1_GUI():
    global time, shot_count, scene_num, animation, soundFlag
    canvas2_1.delete("all")  # キャッシュ処理

    canvas2_1.create_image(270, 375, image=bg_1)

    if scene_num == 3:
        if shot_count == 0:
            canvas2_1.create_image(295, 150, image=countPic1)
            if animation % 3 == 0:
                canvas2_1.create_image(145 + 150, 250 + 175, image=samplepose1_1)
            if animation % 3 == 1:
                canvas2_1.create_image(145 + 150, 250 + 175, image=samplepose1_2)
            if animation % 3 == 2:
                canvas2_1.create_image(145 + 150, 250 + 175, image=samplepose1_3)
        if shot_count == 1:
            canvas2_1.create_image(295, 150, image=countPic2)
            if animation % 3 == 0:
                canvas2_1.create_image(145 + 150, 250 + 175, image=samplepose2_1)
            if animation % 3 == 1:
                canvas2_1.create_image(145 + 150, 250 + 175, image=samplepose2_2)
            if animation % 3 == 2:
                canvas2_1.create_image(145 + 150, 250 + 175, image=samplepose2_3)
        if shot_count == 2:
            canvas2_1.create_image(295, 150, image=countPic3)
            canvas2_1.create_image(145 + 150, 250 + 175, image=samplepose3_1)

    animation += 1
    frame1.after(500, frame2_1_GUI)  # ディレイ・繰り返し処理


def frame2_2_GUI():
    global time

    if scene_num == 2 or scene_num == 3:
        canvas2_2.delete("all")  # キャッシュ処理

        canvas2_2.create_image(420, 375, image=bg_2)

        ret, capframe = capture.read()

        capframe = cv2.cvtColor(capframe, cv2.COLOR_BGR2RGB)
        capframe = cv2.flip(capframe, 1)

        frame2.photo = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(capframe))
        canvas2_2.create_image(-246, 50, image=frame2.photo, anchor=tkinter.NW)

        if time > scene2_wait:
            canvas2_2.create_image(420, 400, image=guide)
            canvas2_2.create_image(420, 400, image=angle_frame)

        if time > scene2_wait + 3:  # [+3]は最初の余裕分の排除のため
            if (time - (scene2_wait + (shot_time - 3))) % shot_time == 0:
                canvas2_2.create_image(420, 400, image=camera_count3)
            if (time - (scene2_wait + (shot_time - 2))) % shot_time == 0:
                canvas2_2.create_image(420, 400, image=camera_count2)
            if (time - (scene2_wait + (shot_time - 1))) % shot_time == 0:
                canvas2_2.create_image(420, 400, image=camera_count1)
            if (time - (scene2_wait + shot_time)) % shot_time == 0:
                canvas2_2.create_image(420, 400, image=camera_count0)
            if (
                (time - (scene2_wait + (shot_time + 1))) % shot_time == 0
                or (time - (scene2_wait + (shot_time + 2))) % shot_time == 0
                or (time - (scene2_wait + (shot_time + 3))) % shot_time == 0
            ):  # 3s処理分の余裕を持たせる
                canvas2_2.create_image(420, 400, image=camera_loading)

        if time > (scene2_wait + 1):
            if (time - (scene2_wait + 1)) % shot_time == 0:
                image_processing(capframe)

    frame2.after(10, frame2_2_GUI)  # ディレイ・繰り返し処理 #最適なループ時間を検証中


def frame2_4_GUI():  # ループさせなくても毎回読み込めばいけるのでは、またキャッシュ処理がなくても問題なさそう
    global notice_2, slot1_AF, slot2_AF, slot3_AF, slot4_AF, slot5_AF, slot6_AF
    global time
    if scene_num == 2:
        canvas2_4.delete("all")  # キャッシュ処理
        canvas2_4.create_image(960, 165, image=bg4_slot)
        road_picture(0)
        canvas2_4.create_image(960, 165, image=notice_2)

    if scene_num == 3:
        if time >= (scene2_wait) and time < (scene2_wait + (shot_time + 1)):
            canvas2_4.delete("all")  # キャッシュ処理
            canvas2_4.create_image(960, 165, image=bg4_slot)

        if time == scene2_wait + shot_time + 3:
            canvas2_4.delete("all")  # キャッシュ処理
            canvas2_4.create_image(960, 165, image=bg4_slot)
            road_picture(2)
            canvas2_4.create_image(60 + 125, 165, image=slot1_AF)
            canvas2_4.create_image(370 + 125, 165, image=slot2_AF)

        if time == scene2_wait + (shot_time * 2) + 3:
            canvas2_4.delete("all")  # キャッシュ処理
            canvas2_4.create_image(960, 165, image=bg4_slot)
            road_picture(3)
            canvas2_4.create_image(60 + 125, 165, image=slot1_AF)
            canvas2_4.create_image(370 + 125, 165, image=slot2_AF)
            canvas2_4.create_image(680 + 125, 165, image=slot3_AF)
            canvas2_4.create_image(990 + 125, 165, image=slot4_AF)

        if time == scene2_wait + (shot_time * 3) + 3:
            canvas2_4.delete("all")  # キャッシュ処理
            canvas2_4.create_image(960, 165, image=bg4_slot)
            road_picture(4)
            canvas2_4.create_image(60 + 125, 165, image=slot1_AF)
            canvas2_4.create_image(370 + 125, 165, image=slot2_AF)
            canvas2_4.create_image(680 + 125, 165, image=slot3_AF)
            canvas2_4.create_image(990 + 125, 165, image=slot4_AF)
            canvas2_4.create_image(1300 + 125, 165, image=slot5_AF)
            canvas2_4.create_image(1610 + 125, 165, image=slot6_AF)

    frame4.after(500, frame2_4_GUI)  # ディレイ・繰り返し処理

# -------------------------------------------- #
```

***

画面構成。初めてでわからないことだらけだったが、こんなに多重構造にするのは果たしてよかったのか。
```python:puriGUI_ver2.1
if __name__ == "__main__":
    root = tkinter.Tk()  # この下に画面構成を記述

    pygame.init()

    # -------------------------------------------- #
    root.title("プリクラ")  # 画面タイトル設定
    root.geometry("1920x1080")  # 画面サイズ設定
    root.resizable(False, False)  # リサイズ不可に設定
    root.attributes("-fullscreen", True)  # 画面最大化

    # rootメインウィンドウのグリッドを 1x1 にする
    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)
    # -------------------------------------------- #

    # -------------------------------------------- #
    time = 0  # タイマー

    detector = cv2.QRCodeDetector()

    with open("UUID.csv", encoding="utf-8-sig") as f:
        UUID_list = f.readlines()

    UUID_list = [line.strip() for line in UUID_list]  # 改行を削除

    scene_num = 1  # シーン番号
    shot_count = 0  # 撮影枚数カウント
    scene2_wait = 8  # 注意事項の表示時間
    shot_time = 15  # 撮影にかかる時間（scene_waitの値以上 and 3s分の余裕を持たせたい)

    animation = 0

    qrreadFlag = False
    soundFlag = [0, False]

    colorset = "#@$&/?(*)=~^:,. "  #AA用文字セット

    bg_1 = tk.PhotoImage(file="bg_1.png")
    bg_2 = tk.PhotoImage(file="bg_2.png")
    bg_3 = tk.PhotoImage(file="bg_3.png")
    bg4_slot = tk.PhotoImage(file="bg4_slot.png")

    # -------------------------------------------- #

    # -------------------------------------------- #

    QRcodeRead = pygame.mixer.Sound("QRcodeRead.wav")
    start_shot = pygame.mixer.Sound("start_shot.wav")
    position_explanation = pygame.mixer.Sound("position_explanation.wav")
    pose1 = pygame.mixer.Sound("pose1.wav")
    pose2 = pygame.mixer.Sound("pose2.wav")
    pose3 = pygame.mixer.Sound("pose3.wav")
    count1 = pygame.mixer.Sound("count1.wav")
    count2 = pygame.mixer.Sound("count2.wav")
    count3 = pygame.mixer.Sound("count3.wav")
    shutter = pygame.mixer.Sound("shutter.wav")
    rakugaki_move = pygame.mixer.Sound("rakugaki_move.wav")

    # -------------------------------------------- #

    # -------------------------------------------- #

    capture = cv2.VideoCapture(0)
    capture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc("H", "2", "6", "4"))
    capture.set(cv2.CAP_PROP_FPS, 30)
    capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1244)
    capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 700)

    # -------------------------------------------- #

    # ------------------ Scene1 ------------------ #
    scene1 = tk.Frame(root, width=1920, height=1080, bg="white")
    scene1.grid(row=0, column=0, sticky="nsew")

    scene1.propagate(False)  # Frameサイズを固定

    frame1_1 = tk.Frame(scene1, width=540, height=750)
    frame1_2 = tk.Frame(scene1, width=840, height=750)
    frame1_3 = tk.Frame(scene1, width=540, height=750)
    frame1_4 = tk.Frame(scene1, width=1920, height=330)

    frame1_1.propagate(False)
    frame1_2.propagate(False)
    frame1_3.propagate(False)
    frame1_4.propagate(False)

    frame1_1.grid(row=0, column=0)
    frame1_2.grid(row=0, column=1)
    frame1_3.grid(row=0, column=2)
    frame1_4.grid(row=1, column=0, columnspan=3)

    canvas1_1 = tk.Canvas(frame1_1, width=540, height=750, highlightthickness=0)
    canvas1_2 = tk.Canvas(frame1_2, width=840, height=750, highlightthickness=0)
    canvas1_3 = tk.Canvas(frame1_3, width=540, height=750, highlightthickness=0)
    canvas1_4 = tk.Canvas(frame1_4, width=1920, height=330, highlightthickness=0)

    canvas1_1.grid(row=0, column=0)
    canvas1_2.grid(row=0, column=1)
    canvas1_3.grid(row=0, column=2)
    canvas1_4.grid(row=1, column=0, columnspan=3)

    canvas1_1.create_image(270, 375, image=bg_1)
    canvas1_3.create_image(270, 375, image=bg_3)

    qrread = tk.PhotoImage(file="qrread.png")
    canvas1_4.create_image(960, 165, image=qrread)

    frame1_2_GUI()

    # ------------------ Scene2 ------------------ #
    scene2 = tk.Frame(root, width=1920, height=108)
    scene2.grid(row=0, column=0, sticky="nsew")

    scene2.propagate(False)  # Frameサイズを固定

    frame1 = tk.Frame(scene2, width=540, height=750)
    frame2 = tk.Frame(scene2, width=840, height=750)
    frame3 = tk.Frame(scene2, width=540, height=750)
    frame4 = tk.Frame(scene2, width=1920, height=330)

    frame1.propagate(False)  # Frameサイズを固定
    frame2.propagate(False)
    frame3.propagate(False)
    frame4.propagate(False)

    frame1.grid(row=0, column=0)  # Frameを配置（grid）
    frame2.grid(row=0, column=1)
    frame3.grid(row=0, column=2)
    frame4.grid(row=1, column=0, columnspan=3)

    # ----------- frame1 ----------- #
    countPic1 = tk.PhotoImage(file="count1.png")
    samplepose1_1 = tk.PhotoImage(file="samplepose1_1.png")
    samplepose1_2 = tk.PhotoImage(file="samplepose1_2.png")
    samplepose1_3 = tk.PhotoImage(file="samplepose1_3.png")
    countPic2 = tk.PhotoImage(file="count2.png")
    samplepose2_1 = tk.PhotoImage(file="samplepose2_1.png")
    samplepose2_2 = tk.PhotoImage(file="samplepose2_2.png")
    samplepose2_3 = tk.PhotoImage(file="samplepose2_3.png")
    countPic3 = tk.PhotoImage(file="count3.png")
    samplepose3_1 = tk.PhotoImage(file="samplepose3_1.png")

    canvas2_1 = tk.Canvas(frame1, width=540, height=750, highlightthickness=0)
    canvas2_1.grid(row=0, column=0)

    # ----------- frame2 ----------- #
    camera_count3 = tk.PhotoImage(file="camera_count3.png")
    camera_count2 = tk.PhotoImage(file="camera_count2.png")
    camera_count1 = tk.PhotoImage(file="camera_count1.png")
    camera_count0 = tk.PhotoImage(file="camera_count0.png")
    camera_loading = tk.PhotoImage(file="camera_loading.png")
    guide = tk.PhotoImage(file="guide.png")
    angle_frame = tk.PhotoImage(file="angle_frame.png")

    canvas2_2 = tk.Canvas(frame2, width=840, height=750, highlightthickness=0)
    canvas2_2.grid(row=0, column=1)

    # ----------- frame3 ----------- #
    canvas2_3 = tk.Canvas(frame3, width=540, height=750, highlightthickness=0)
    canvas2_3.grid(row=0, column=2)

    canvas2_3.create_image(270, 375, image=bg_3)

    # ----------- frame4 ----------- #

    canvas2_4 = tk.Canvas(frame4, width=1920, height=330, highlightthickness=0)
    canvas2_4.grid(row=1, column=0, columnspan=3)

    world_timer()  # タイマースタート

    frame2_2_GUI()
    frame2_1_GUI()
    frame2_4_GUI()

    # ------------------ Scene3 ------------------ #
    scene3 = tk.Frame(root, width=1920, height=1080)
    scene3.grid(row=0, column=0, sticky="nsew")

    scene3.propagate(False)  # Frameサイズを固定

    canvas3_1 = tk.Canvas(scene3, width=1920, height=1080, highlightthickness=0)
    canvas3_1.pack(padx=0, pady=0)

    scene3_1 = tk.PhotoImage(file="scene3_1.png")

    canvas3_1.create_image(960, 540, image=scene3_1)

    # -------------------------------------------- #

    show_scene1()

    root.mainloop()

```

</details>

### ラクガキブース
<details><summary>ソースコード</summary>

使用したライブラリ一覧。
```python:drawGUI_ver1.0
import tkinter as tk
import tkinter.ttk as ttk
import cv2
import numpy as np
import tkinter.filedialog
import PIL.ImageTk
import PIL.Image
import os
import pygame
import requests
import pyautogui
import random

from PIL import Image, ImageTk
```

***

撮影ブース同様です。
```python:drawGUI_ver1.0
# 管理関数 ------------------------------------- #
def world_timer(): #時間管理
    global time,loadFlag

    time += 1

    if scene_num == 2:
        if loadFlag == False:
            if time == 2:
                time_explanation.play()
            if time == 7:
                select_explanation.play()
            if time == 12:
                start_call.play()
                time = 0
                loadFlag = True        

        if loadFlag == True:
            if time_limit-time==10:
                rest10.play()
            if time_limit-time==5:
                rest5.play()
            if time_limit-time==2:
                rest3.play()
            if time_limit-time==1:
                rest2.play()
            if time_limit-time==0:
                rest1.play()
            if time_limit-time==-1:
                show_scene3()

    if scene_num == 3:
        if time_limit-time==-1:
            canvas3_1.create_image(960,540,image=scene3_1)
            DL_explanation.play()
        if time_limit-time==-8:
            canvas3_1.create_image(960,540,image=scene3_2)
            printing_explanation.play()
        if time_limit-time==-20:
            show_scene1()

    frame1.after(1000,world_timer)

def road_picture():
    global data
    global comp,comp_tk,aa,aa_tk
    global result_tk_out,result_tk,mask
    global comp_select,comp_select_off

    comp = [None,None,None]
    comp_tk = [None,None,None]
    aa = [None,None,None]
    aa_tk = [None,None,None]
    result_tk_out = [None,None,None]
    result_tk = [None,None,None]
    mask = [None,None,None]
    comp_select = [None,None,None]
    comp_select_off = [None,None,None]

    ImageTransfer.download_image(qr_UUID,'AA_L_1.png')
    ImageTransfer.download_image(qr_UUID,'AA_L_2.png')
    ImageTransfer.download_image(qr_UUID,'AA_L_3.png')
    ImageTransfer.download_image(qr_UUID,'comp_L_1_temp.png')
    ImageTransfer.download_image(qr_UUID,'comp_L_2_temp.png')
    ImageTransfer.download_image(qr_UUID,'comp_L_3_temp.png')

    aa[0] = cv2.imread("AA_L_1.png")
    aa[1] = cv2.imread("AA_L_2.png")
    aa[2] = cv2.imread("AA_L_3.png")
    comp[0] = cv2.imread("comp_L_1_temp.png")
    comp[1] = cv2.imread("comp_L_2_temp.png")
    comp[2] = cv2.imread("comp_L_3_temp.png")

    for i in range(3):
        # ラクガキ用（frame2/4）
        comp[i] = cv2.resize(comp[i], (625, 750))
        comp_tk[i] = cv2_to_tk(comp[i])

        aa[i] = cv2.resize(aa[i], (625, 750))
        aa_tk[i] = cv2_to_tk(aa[i])

        result_tk_out[i] = aa_tk[i]

        mask[i] = np.zeros_like(comp[i]) #マスク画像生成

        # セレクト写真用（frame1）
        comp_select[i] = cv2.resize(comp[i], (165, 198))
        comp_select_off[i] = cv2.cvtColor(comp_select[i],cv2.COLOR_BGR2GRAY)
        comp_select[i] = cv2_to_tk(comp_select[i])
        comp_select_off[i] = cv2_to_tk(comp_select_off[i])
# -------------------------------------------- #

# 変換関数 ------------------------------------ #
def cv2_to_tk(cv2_image):
    cv2_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB) # imreadはBGRなのでRGBに変換
    PIL_image = Image.fromarray(cv2_image) # RGBからPILフォーマットへ変換     
    tk_image  = ImageTk.PhotoImage(PIL_image) # ImageTkフォーマットへ変換
    return tk_image
# -------------------------------------------- #
```

```python:drawGUI_ver1.0
# シーンチェンジ関数 --------------------------- #
def show_scene1():
    global scene_num,soundFlag,upload_Flag
    scene_num = 1
    soundFlag[1] = False
    upload_Flag = False
    scene1.tkraise()

def show_scene2():
    global time,scene_num,loadFlag
    global select_num_R,select_num_L
    global brush_num,brush_widgh,stamp_num,stamp_list,stamp_count,stampselect_Flag_R,stampselect_Flag_L,pen_or_stamp

    #初期化
    time = 0
    scene_num = 2
    loadFlag = False

    select_num_R = 0
    select_num_L = 1

    brush_num = 0
    brush_widgh = 70
    stamp_num = 0
    stamp_list = []
    stamp_count = 0
    stampselect_Flag_R = False
    stampselect_Flag_L = False
    pen_or_stamp = 0 #0:ペン 1:スタンプ

    scene2.tkraise()

def show_scene3():
    global scene_num,result_tk,qr_UUID
    scene_num = 3
    scene3.tkraise()

    cv2.imwrite("result_L_1.png", result_tk[0])
    cv2.imwrite("result_L_2.png", result_tk[1])
    cv2.imwrite("result_L_3.png", result_tk[2])

    picRandom = random.randrange(2)
    if picRandom == 0:
        base = Image.open("print_bg1_1.png") #1日目
        #base = Image.open("print_bg1_2.png") #2日目
        #base = Image.open("print_bg1_3.png") #3日目
    if picRandom == 1:
        base = Image.open("print_bg2_1.png") #1日目
        #base = Image.open("print_bg2_2.png") #2日目
        #base = Image.open("print_bg2_3.png") #3日目

    stamp1_img_PIL = Image.open("icon_stamp1.png")
    stamp2_img_PIL = Image.open("icon_stamp2.png")
    stamp3_img_PIL = Image.open("icon_stamp3.png")
    stamp4_img_PIL = Image.open("icon_stamp4.png")

    # base.paste(logo, (0, 0))
    base.paste(logo, (0, 0), logo)
    base.save(out_path)

    #スタンプ描画
    '''
    for i in range(stamp_count): #stamp_list[stamp_num(0),sx(1),sy(2),select_num(3)]
        if stamp_list[i][3]==0:
            if stamp_list[i][0]==0:
                canvas2_2.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp1_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==1:
                canvas2_2.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp2_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==2:
                canvas2_2.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp3_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==3:
                canvas2_2.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp4_img, anchor='nw',tag="stamp_comp")    
    '''

    ImageTransfer.upload_image(qr_UUID, "./result_L_1.png")
    ImageTransfer.upload_image(qr_UUID, "./result_L_2.png")
    ImageTransfer.upload_image(qr_UUID, "./result_L_3.png")
# -------------------------------------------- #

```

***

rootでマウスの動作を検知して「クリック」「ドラック」の二種類から描画する形をとったが、あまり綺麗にラクガキする体験を提供できなかった。重くなると露骨に直線になってしまうし、文字を書こうとするとなかなか難しくなってしまったのは反省点です。この処理はうまくやる方法を現在も模索中です。
```python:drawGUI_ver1.0
# マウス検知関数 ------------------------------ #
def on_pressed(event,lr):
    global sx,sy
    global comp,comp_tk,aa,aa_tk
    global result_tk,result_tk_out,mask
    global stamp_list,stamp_count

    if 87.5<event.x and event.x<712.5 and 65<event.y and event.y<815:
        sx = event.x
        sy = event.y

    if pen_or_stamp == 0:
        if lr == 0:
            if brush_num == 0:
                color = (85,85,85)
                color = (85,85,85)
            if brush_num == 1:
                color = (255,255,255)
            if brush_num == 2:
                color = (63,105,39)         
            if brush_num == 3:
                color = (0,0,0)
            cv2.circle(mask[select_num_R],(int(sx-87.5),int(sy-65)),int(brush_widgh),color,thickness=-1)
            result_tk[select_num_R] = addweight(comp[select_num_R],aa[select_num_R],mask[select_num_R])
            result_tk_out[select_num_R] = cv2_to_tk(result_tk[select_num_R])
        if lr == 1:
            if brush_num == 0:
                color = (85,85,85)
            if brush_num == 1:
                color = (255,255,255)
            if brush_num == 2:
                color = (63,105,39)         
            if brush_num == 3:
                color = (0,0,0)
            cv2.circle(mask[select_num_L],(int(sx-87.5),int(sy-65)),brush_widgh,color,thickness=-1)
            result_tk[select_num_L] = addweight(comp[select_num_L],aa[select_num_L],mask[select_num_L])
            result_tk_out[select_num_L] = cv2_to_tk(result_tk[select_num_L])
    if pen_or_stamp == 1:
        if lr == 0 : stamp_list.append([stamp_num,sx,sy,select_num_R])
        if lr == 1 : stamp_list.append([stamp_num,sx,sy,select_num_L])
        stamp_count+=1
        if stamp_num == 0:
            pyautogui.moveTo(900, 850) #連打回避用
        if stamp_num == 1:
            pyautogui.moveTo(1015, 850)
        if stamp_num == 2:
            pyautogui.moveTo(900, 985)
        if stamp_num == 3:
            pyautogui.moveTo(1015, 985)

def on_dragged(event,lr):
    global sx,sy
    global comp,comp_tk,aa,aa_tk
    global result_tk,result_tk_out,mask
    if pen_or_stamp == 0:
        if lr == 0:
            if brush_num == 0:
                color = (85,85,85)
                brush_widgh_line = int(brush_widgh*2)
            if brush_num == 1:
                color = (255,255,255)
                brush_widgh_line = int(brush_widgh*2)
            if brush_num == 2:
                color = (63,105,39)
                brush_widgh_line = int(brush_widgh*2)              
            if brush_num == 3:
                color = (0,0,0)
                brush_widgh_line = int(brush_widgh*2)
            if 87.5<event.x and event.x<712.5 and 65<event.y and event.y<815:
                cv2.line(mask[select_num_R], (int(sx-87.5), int(sy-65)), (int(event.x-87.5), int(event.y-65)), color, thickness=brush_widgh_line, lineType=cv2.LINE_AA)
                result_tk[select_num_R] = addweight(comp[select_num_R],aa[select_num_R],mask[select_num_R])
                result_tk_out[select_num_R] = cv2_to_tk(result_tk[select_num_R])
                
        if lr == 1:
            if brush_num == 0:
                color = (85,85,85)
                brush_widgh_line = int(brush_widgh*2)
            if brush_num == 1:
                color = (255,255,255)
                brush_widgh_line = int(brush_widgh*2)
            if brush_num == 2:
                color = (63,105,39)
                brush_widgh_line = int(brush_widgh*2)              
            if brush_num == 3:
                color = (0,0,0)
                brush_widgh_line = int(brush_widgh*2)
            if 87.5<event.x and event.x<712.5 and 65<event.y and event.y<815:
                cv2.line(mask[select_num_L], (int(sx-87.5), int(sy-65)), (int(event.x-87.5), int(event.y-65)), color, thickness=brush_widgh_line, lineType=cv2.LINE_AA)
                result_tk[select_num_L] = addweight(comp[select_num_L],aa[select_num_L],mask[select_num_L])
                result_tk_out[select_num_L] = cv2_to_tk(result_tk[select_num_L])

        if 87.5<event.x and event.x<712.5 and 65<event.y and event.y<815:
            sx = event.x
            sy = event.y

def on_moved(event,lr):
    global stamp_sx_L,stamp_sy_L,stamp_sx_R,stamp_sy_R,stampselect_Flag_R,stampselect_Flag_L
    if lr == 0:
        stamp_sx_R = event.x
        stamp_sy_R = event.y
        stampselect_Flag_R = True
        stampselect_Flag_L = False
    if lr == 1:
        stamp_sx_L = event.x
        stamp_sy_L = event.y
        stampselect_Flag_R = False
        stampselect_Flag_L = True
# -------------------------------------------- #

# ブラシ関数 ---------------------------------- #
def addweight(im1,im2,mask):
    result_aa_pic = im2.copy()
    mask = mask/255
    indexForIm2 = np.where( mask == [0,0,0] )
    indexForIm1 = np.where( mask == [1,1,1] )
    indexForWeight = np.where( (mask != [0,0,0]) & (mask != [1,1,1]) )
    result_aa_pic[ indexForIm1[0] ,indexForIm1[1] ] = im1[ indexForIm1[0] ,indexForIm1[1] ]
    result_aa_pic[ indexForWeight[0] ,indexForWeight[1] ] = ( (1 - mask[ indexForWeight[0] ,indexForWeight[1] ]) * im2[ indexForWeight[0] ,indexForWeight[1] ]) + ( mask[ indexForWeight[0] ,indexForWeight[1] ] * im1[ indexForWeight[0] ,indexForWeight[1] ])
    result_aa_pic[ indexForIm2[0] ,indexForIm2[1] ] = im2[ indexForIm2[0] ,indexForIm2[1]]
    result_aa_pic = result_aa_pic.astype(np.uint8)

    return result_aa_pic

def select1_R():
    global select_num_R
    if not select_num_L == 0:
        select_img_reset_R()
        select_num_R = 0
        button_comp1_R = tk.Button(canvas2_1a, image = comp_select_off[0], compound="top", command=select1_R , relief=tk.FLAT).place(x = 80, y = 1, width = 160, height = 200)

def select2_R():
    global select_num_R
    if not select_num_L == 1:
        select_img_reset_R()
        select_num_R = 1
        button_comp2_R = tk.Button(canvas2_1a, image = comp_select_off[1], compound="top", command=select2_R , relief=tk.FLAT).place(x = 320, y = 1, width = 160, height = 200)

def select3_R():
    global select_num_R
    if not select_num_L == 2:
        select_img_reset_R()
        select_num_R = 2
        button_comp3_R = tk.Button(canvas2_1a, image = comp_select_off[2], compound="top", command=select3_R , relief=tk.FLAT).place(x = 560, y = 1, width = 160, height = 200)

def select1_L():
    global select_num_L
    if not select_num_R == 0:
        select_img_reset_L()
        select_num_L = 0
        button_comp1_L = tk.Button(canvas2_1c, image = comp_select_off[0], compound="top", command=select1_L , relief=tk.FLAT).place(x = 140, y = 1, width = 160, height = 200)

def select2_L():
    global select_num_L
    if not select_num_R == 1:
        select_img_reset_L()
        select_num_L = 1
        button_comp2_L = tk.Button(canvas2_1c, image = comp_select_off[1], compound="top", command=select2_L , relief=tk.FLAT).place(x = 380, y = 1, width = 160, height = 200)

def select3_L():
    global select_num_L
    if not select_num_R == 2:
        select_img_reset_L()
        select_num_L = 2
        button_comp3_L = tk.Button(canvas2_1c, image = comp_select_off[2], compound="top", command=select3_L , relief=tk.FLAT).place(x = 620, y = 1, width = 160, height = 200)

def select_img_reset_R():
    if select_num_R == 0:
        button_comp1_R = tk.Button(canvas2_1a, image = comp_select[0], compound="top", command=select1_R , relief=tk.FLAT).place(x = 80, y = 1, width = 160, height = 200)
    if select_num_R == 1:
        button_comp2_R = tk.Button(canvas2_1a, image = comp_select[1], compound="top", command=select2_R , relief=tk.FLAT).place(x = 320, y = 1, width = 160, height = 200)
    if select_num_R == 2:
        button_comp3_R = tk.Button(canvas2_1a, image = comp_select[2], compound="top", command=select3_R , relief=tk.FLAT).place(x = 560, y = 1, width = 160, height = 200)

def select_img_reset_L():
    if select_num_L == 0:
        button_comp1_L = tk.Button(canvas2_1c, image = comp_select[0], compound="top", command=select1_L , relief=tk.FLAT).place(x = 140, y = 1, width = 160, height = 200)
    if select_num_L == 1:
        button_comp2_L = tk.Button(canvas2_1c, image = comp_select[1], compound="top", command=select2_L , relief=tk.FLAT).place(x = 380, y = 1, width = 160, height = 200)
    if select_num_L == 2:
        button_comp3_L = tk.Button(canvas2_1c, image = comp_select[2], compound="top", command=select3_L , relief=tk.FLAT).place(x = 620, y = 1, width = 160, height = 200)

def brush1():
    brush_img_reset()
    global brush_num,stampselect_Flag_R,stampselect_Flag_L,pen_or_stamp
    pen_or_stamp = 0
    brush_num = 0
    stampselect_Flag_R = False
    stampselect_Flag_L = False
    button_icon1 = tk.Button(canvas2_3, image=icon1_off, compound="top", command=brush1, relief=tk.RAISED)
    button_icon1.place(x = 30, y = 30)

def brush2():
    brush_img_reset()
    global brush_num,stampselect_Flag_R,stampselect_Flag_L,pen_or_stamp
    pen_or_stamp = 0
    brush_num = 1
    stampselect_Flag_R = False
    stampselect_Flag_L = False
    button_icon2 = tk.Button(canvas2_3, image=icon2_off, compound="top", command=brush2, relief=tk.RAISED)
    button_icon2.place(x = 30, y = 140)

def brush3():
    brush_img_reset()
    global brush_num,stampselect_Flag_R,stampselect_Flag_L,pen_or_stamp
    pen_or_stamp = 0
    brush_num = 2
    stampselect_Flag_R = False
    stampselect_Flag_L = False
    button_icon3 = tk.Button(canvas2_3, image=icon3_off, compound="top", command=brush2, relief=tk.RAISED)
    button_icon3.place(x = 30, y = 250)

def eraser1():
    brush_img_reset()
    global brush_num,stampselect_Flag_R,stampselect_Flag_L,pen_or_stamp
    pen_or_stamp = 0
    brush_num = 3
    stampselect_Flag_R = False
    stampselect_Flag_L = False
    button_icon4 = tk.Button(canvas2_3, image=icon4_off, compound="top", command=eraser1, relief=tk.RAISED)
    button_icon4.place(x = 30, y = 360)

def brush_img_reset():
    if brush_num == 0:
        button_icon1 = tk.Button(canvas2_3, image=icon1, compound="top", command=brush1, relief=tk.RAISED)
        button_icon1.place(x = 30, y = 30)
    if brush_num == 1:
        button_icon2 = tk.Button(canvas2_3, image=icon2, compound="top", command=brush2, relief=tk.RAISED)
        button_icon2.place(x = 30, y = 140)
    if brush_num == 2:
        button_icon3 = tk.Button(canvas2_3, image=icon3, compound="top", command=brush3, relief=tk.RAISED)
        button_icon3.place(x = 30, y = 250)      
    if brush_num == 3:
        button_icon4 = tk.Button(canvas2_3, image=icon4, compound="top", command=eraser1, relief=tk.RAISED)
        button_icon4.place(x = 30, y = 360) 

    if stamp_num == 0:
        button_stamp1 = tk.Button(canvas2_3, image=icon_stamp1, compound="top", command=stamp1, relief=tk.RAISED)
        button_stamp1.place(x = 50, y = 590)
    if stamp_num == 1:
        button_stamp2 = tk.Button(canvas2_3, image=icon_stamp2, compound="top", command=stamp2, relief=tk.RAISED)
        button_stamp2.place(x = 165, y = 590)
    if stamp_num == 2:
        button_stamp3 = tk.Button(canvas2_3, image=icon_stamp3, compound="top", command=stamp3, relief=tk.RAISED)
        button_stamp3.place(x = 50, y = 725)
    if stamp_num == 3:
        button_stamp4 = tk.Button(canvas2_3, image=icon_stamp4, compound="top", command=stamp4, relief=tk.RAISED)
        button_stamp4.place(x = 165, y = 725)

def brush_widgh4_setting():
    brush_widgh_img_reset()
    global brush_widgh
    brush_widgh = 70

    button_brush_widgh4 = tk.Button(canvas2_3, image=brush_widgh4_off, compound="top", command=brush_widgh4_setting, relief=tk.RAISED)
    button_brush_widgh4.place(x = 185, y = 30)

def brush_widgh3_setting():
    brush_widgh_img_reset()
    global brush_widgh
    brush_widgh = 50

    button_brush_widgh3 = tk.Button(canvas2_3, image=brush_widgh3_off, compound="top", command=brush_widgh3_setting, relief=tk.RAISED)
    button_brush_widgh3.place(x = 185, y = 140)

def brush_widgh2_setting():
    brush_widgh_img_reset()
    global brush_widgh
    brush_widgh = 30

    button_brush_widgh2 = tk.Button(canvas2_3, image=brush_widgh2_off, compound="top", command=brush_widgh2_setting, relief=tk.RAISED)
    button_brush_widgh2.place(x = 185, y = 250)

def brush_widgh1_setting():
    brush_widgh_img_reset()
    global brush_widgh
    brush_widgh = 10
    
    button_brush_widgh1 = tk.Button(canvas2_3, image=brush_widgh1_off, compound="top", command=brush_widgh1_setting, relief=tk.RAISED)
    button_brush_widgh1.place(x = 185, y = 360)

def brush_widgh_img_reset():
    if brush_widgh == 70:
        button_brush_widgh4 = tk.Button(canvas2_3, image=brush_widgh4, compound="top", command=brush_widgh4_setting, relief=tk.RAISED)
        button_brush_widgh4.place(x = 185, y = 30)
    if brush_widgh == 50:
        button_brush_widgh3 = tk.Button(canvas2_3, image=brush_widgh3, compound="top", command=brush_widgh3_setting, relief=tk.RAISED)
        button_brush_widgh3.place(x = 185, y = 140)
    if brush_widgh == 30:
        button_brush_widgh2 = tk.Button(canvas2_3, image=brush_widgh2, compound="top", command=brush_widgh2_setting, relief=tk.RAISED)
        button_brush_widgh2.place(x = 185, y = 250)
    if brush_widgh == 10:
        button_brush_widgh1 = tk.Button(canvas2_3, image=brush_widgh1, compound="top", command=brush_widgh1_setting, relief=tk.RAISED)
        button_brush_widgh1.place(x = 185, y = 360)

def stamp1():
    stamp_img_reset()
    global stamp_num,pen_or_stamp,stamp_sx_L,stamp_sy_L,stamp_sx_R,stamp_sy_R
    pen_or_stamp = 1
    stamp_num = 0
    stamp_sx_L = -100
    stamp_sy_L = -100
    stamp_sx_R = -100
    stamp_sy_R = -100
    button_stamp1 = tk.Button(canvas2_3, image=icon_stamp1_off, compound="top", command=stamp1, relief=tk.RAISED)
    button_stamp1.place(x = 50, y = 590)

def stamp2():
    stamp_img_reset()
    global stamp_num,pen_or_stamp,stamp_sx_L,stamp_sy_L,stamp_sx_R,stamp_sy_R
    pen_or_stamp = 1
    stamp_num = 1
    stamp_sx_L = -100
    stamp_sy_L = -100
    stamp_sx_R = -100
    stamp_sy_R = -100
    button_stamp2 = tk.Button(canvas2_3, image=icon_stamp2_off, compound="top", command=stamp2, relief=tk.RAISED)
    button_stamp2.place(x = 165, y = 590)

def stamp3():
    stamp_img_reset()
    global stamp_num,pen_or_stamp,stamp_sx_L,stamp_sy_L,stamp_sx_R,stamp_sy_R
    pen_or_stamp = 1
    stamp_num = 2
    stamp_sx_L = -100
    stamp_sy_L = -100
    stamp_sx_R = -100
    stamp_sy_R = -100
    button_stamp3 = tk.Button(canvas2_3, image=icon_stamp3_off, compound="top", command=stamp3, relief=tk.RAISED)
    button_stamp3.place(x = 50, y = 725)

def stamp4():
    stamp_img_reset()
    global stamp_num,pen_or_stamp,stamp_sx_L,stamp_sy_L,stamp_sx_R,stamp_sy_R
    pen_or_stamp = 1
    stamp_num = 3
    stamp_sx_L = -100
    stamp_sy_L = -100
    stamp_sx_R = -100
    stamp_sy_R = -100
    button_stamp4 = tk.Button(canvas2_3, image=icon_stamp4_off, compound="top", command=stamp4, relief=tk.RAISED)
    button_stamp4.place(x = 165, y = 725)

def stamp_img_reset():
    if stamp_num == 0:
        button_stamp1 = tk.Button(canvas2_3, image=icon_stamp1, compound="top", command=stamp1, relief=tk.RAISED)
        button_stamp1.place(x = 50, y = 590)
    if stamp_num == 1:
        button_stamp2 = tk.Button(canvas2_3, image=icon_stamp2, compound="top", command=stamp2, relief=tk.RAISED)
        button_stamp2.place(x = 165, y = 590)
    if stamp_num == 2:
        button_stamp3 = tk.Button(canvas2_3, image=icon_stamp3, compound="top", command=stamp3, relief=tk.RAISED)
        button_stamp3.place(x = 50, y = 725)
    if stamp_num == 3:
        button_stamp4 = tk.Button(canvas2_3, image=icon_stamp4, compound="top", command=stamp4, relief=tk.RAISED)
        button_stamp4.place(x = 165, y = 725)

    if brush_num == 0:
        button_icon1 = tk.Button(canvas2_3, image=icon1, compound="top", command=brush1, relief=tk.RAISED)
        button_icon1.place(x = 30, y = 30)
    if brush_num == 1:
        button_icon2 = tk.Button(canvas2_3, image=icon2, compound="top", command=brush2, relief=tk.RAISED)
        button_icon2.place(x = 30, y = 140)
    if brush_num == 2:
        button_icon3 = tk.Button(canvas2_3, image=icon3, compound="top", command=brush3, relief=tk.RAISED)
        button_icon3.place(x = 30, y = 250)      
    if brush_num == 3:
        button_icon4 = tk.Button(canvas2_3, image=icon4, compound="top", command=eraser1, relief=tk.RAISED)
        button_icon4.place(x = 30, y = 360) 
# -------------------------------------------- #
```

※※※

撮影ブースと同様。
```python:drawGUI_ver1.0
# 描画関数 ------------------------------------ #
def frame1_2_GUI():
    global time,soundFlag,qr_UUID

    if scene_num == 1:
        canvas1_2.delete('all') #キャッシュ処理

        canvas1_2.create_image(420,375,image=bg_2)

        ret, capframe = capture.read()

        capframe = cv2.cvtColor(capframe, cv2.COLOR_BGR2RGB)

        if ret == True:
            if time%10==0 and soundFlag[1]==False:
                QRcodeRead.play()
                soundFlag[0] = time
                soundFlag[1] = True
            if time==int(soundFlag[0]+1):
                soundFlag[1] = False

            # QRコードを認識
            data = detector.detectAndDecode(capframe)

            qr_UUID = data[0] #https://tekken.work/art-market/[UUID]/
            qr_UUID = qr_UUID.replace('https://tekken.work/art-market/', '')
            qr_UUID = qr_UUID.replace('/', '')

            if qr_UUID in UUID_list:
                road_picture() #画像のダウンロードおよびセットアップ
                frame1ac_GUI()
                frame2_GUI()
                frame4_GUI()

                show_scene2()

        frame1_2.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(capframe)) 
        canvas1_2.create_image(-246,50, image=frame1_2.photo, anchor = tkinter.NW)
        
    frame1_2.after(33, frame1_2_GUI) #ディレイ・繰り返し処理 #最適なループ時間を検証中

def frame1b_GUI():
    canvas2_1b.delete('all')

    canvas2_1b.create_image(100,100,image=bg_1_b)

    canvas2_1b.create_oval(10, 10, 190, 190, width=10, outline="#000000")
    if loadFlag == False:
        canvas2_1b.create_text(100,100,text='60',font=("Menlo",80),fill="black",anchor="c") #フォント指定注意
    if loadFlag == True:
        #canvas2_1b.create_image(130,100,image='timer_pic'+str(int((time_limit-time)/10))) #１０の位
        #canvas2_1b.create_image(70,100,image='timer_pic'+str((time_limit-time)%10)) #１の位
        
        if time_limit-time==10:
            canvas2_1b.create_text(100,100,text=time_limit-time,font=("Menlo",80),fill="red",anchor="c") #フォント指定注意
        elif time_limit - time < 10:
            canvas2_1b.create_text(100,100,text=time_limit-time,font=("Menlo",100),fill="red",anchor="c")
        else:
            canvas2_1b.create_text(100,100,text=time_limit-time,font=("Menlo",80),fill="black",anchor="c")
    
    frame2.after(500, frame1b_GUI) #ディレイ・繰り返し処理

def frame1ac_GUI():
    # 各種ウィジェットの作成
    button_comp1_R = tk.Button(canvas2_1a, image = comp_select_off[0], compound="top", command=select1_R , relief=tk.FLAT)
    button_comp2_R = tk.Button(canvas2_1a, image = comp_select[1], compound="top", command=select2_R , relief=tk.FLAT)
    button_comp3_R = tk.Button(canvas2_1a, image = comp_select[2], compound="top", command=select3_R , relief=tk.FLAT)
    button_comp1_R.place(x = 80, y = 1, width = 160, height = 200)
    button_comp2_R.place(x = 320, y = 1, width = 160, height = 200)
    button_comp3_R.place(x = 560, y = 1, width = 160, height = 200)

    button_comp1_L = tk.Button(canvas2_1c, image = comp_select[0], compound="top", command=select1_L , relief=tk.FLAT)
    button_comp2_L = tk.Button(canvas2_1c, image = comp_select_off[1], compound="top", command=select2_L , relief=tk.FLAT)
    button_comp3_L = tk.Button(canvas2_1c, image = comp_select[2], compound="top", command=select3_L , relief=tk.FLAT)
    button_comp1_L.place(x = 140, y = 1, width = 160, height = 200)
    button_comp2_L.place(x = 380, y = 1, width = 160, height = 200)
    button_comp3_L.place(x = 620, y = 1, width = 160, height = 200)

def frame2_GUI():
    global select_num_R,result_tk,result_tk_out,stamp_sx_R,stamp_sy_R
    global upload_Flag

    canvas2_2.delete('img')

    canvas2_2.create_image(400,440,image=bg_2,tag="BG")

    canvas2_2.create_image(87.5, 65, image=result_tk_out[select_num_R], anchor='nw',tag="img")

    if stampselect_Flag_R == True and pen_or_stamp == 1:
        if stamp_num == 0:
            canvas2_2.create_image(stamp_sx_R-38, stamp_sy_R-38, image=stamp1_img, anchor='nw',tag="stamp")
        if stamp_num == 1:
            canvas2_2.create_image(stamp_sx_R-38, stamp_sy_R-38, image=stamp2_img, anchor='nw',tag="stamp")
        if stamp_num == 2:
            canvas2_2.create_image(stamp_sx_R-38, stamp_sy_R-38, image=stamp3_img, anchor='nw',tag="stamp")
        if stamp_num == 3:
            canvas2_2.create_image(stamp_sx_R-38, stamp_sy_R-38, image=stamp4_img, anchor='nw',tag="stamp")

    for i in range(stamp_count): #stamp_list[stamp_num(0),sx(1),sy(2),select_num(3)]
        if stamp_list[i][3]==select_num_R:
            if stamp_list[i][0]==0:
                canvas2_2.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp1_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==1:
                canvas2_2.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp2_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==2:
                canvas2_2.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp3_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==3:
                canvas2_2.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp4_img, anchor='nw',tag="stamp_comp")                  

    frame2.after(33, frame2_GUI) #ディレイ・繰り返し処理

def frame4_GUI():
    global select_num_L,result_tk,result_tk_out,stamp_sx_L,stamp_sy_L

    canvas2_4.delete('img')

    canvas2_4.create_image(400,440,image=bg_4,tag="BG")

    canvas2_4.create_image(87.5, 65, image=result_tk_out[select_num_L], anchor='nw',tag="img")

    if stampselect_Flag_L == True and pen_or_stamp == 1:
        if stamp_num == 0:
            canvas2_4.create_image(stamp_sx_L-38, stamp_sy_L-38, image=stamp1_img, anchor='nw',tag="stamp")
        if stamp_num == 1:
            canvas2_4.create_image(stamp_sx_L-38, stamp_sy_L-38, image=stamp2_img, anchor='nw',tag="stamp")
        if stamp_num == 2:
            canvas2_4.create_image(stamp_sx_L-38, stamp_sy_L-38, image=stamp3_img, anchor='nw',tag="stamp")
        if stamp_num == 3:
            canvas2_4.create_image(stamp_sx_L-38, stamp_sy_L-38, image=stamp4_img, anchor='nw',tag="stamp")

    for i in range(stamp_count): #stamp_list[stamp_num(0),sx(1),sy(2),select_num(3)]
        if stamp_list[i][3]==select_num_L:
            
            if stamp_list[i][0]==0:
                canvas2_4.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp1_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==1:
                canvas2_4.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp2_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==2:
                canvas2_4.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp3_img, anchor='nw',tag="stamp_comp")
            if stamp_list[i][0]==3:
                canvas2_4.create_image(stamp_list[i][1]-38, stamp_list[i][2]-38, image=stamp4_img, anchor='nw',tag="stamp_comp")    

    frame4.after(33, frame4_GUI) #ディレイ・繰り返し処理
# -------------------------------------------- #
```

***

撮影ブースと同様です。
```python:drawGUI_ver1.0
if __name__ == "__main__":
    root = tkinter.Tk() # この下に画面構成を記述

    pygame.init() #初期化

    # -------------------------------------------- #

    root.title('ラクガキ') #画面タイトル設定
    root.geometry('1920x1080') #画面サイズ設定
    root.resizable(False, False) #リサイズ不可に設定
    root.attributes('-fullscreen', True) #画面最大化

    # rootメインウィンドウのグリッドを 1x1 にする
    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)

    # -------------------------------------------- #

    scene_num = 1 #シーン番号
    time = 0
    time_limit = 15

    detector = cv2.QRCodeDetector()

    with open('UUID.csv', encoding = 'utf-8-sig') as f:
        UUID_list = f.readlines()
    UUID_list = [ line.strip() for line in UUID_list] #改行を削除

    loadFlag = False #Scene1>2へのロード待機用

    select_num_R = 0
    select_num_L = 1

    brush_num = 0
    brush_widgh = 70

    stamp_num = 0
    stamp_list = [[0,0,0,0]]
    stamp_count = 0
    stamp_redo = [0,0,0,0] #redo用の保管

    stampselect_Flag_R = False
    stampselect_Flag_L = False

    pen_or_stamp = 0 #0:ペン 1:スタンプ

    stamp1_img = tk.PhotoImage(file="stamp1.png")
    stamp2_img = tk.PhotoImage(file="stamp2.png")
    stamp3_img = tk.PhotoImage(file="stamp3.png")
    stamp4_img = tk.PhotoImage(file="stamp4.png")

    bg_1 = tk.PhotoImage(file="bg_1.png")
    bg_1_a = tk.PhotoImage(file="bg_1_a.png")
    bg_1_b = tk.PhotoImage(file="bg_1_b.png")
    bg_1_c = tk.PhotoImage(file="bg_1_c.png")
    bg_2 = tk.PhotoImage(file="bg_2.png")
    bg_3 = tk.PhotoImage(file="bg_3.png")
    bg_4 = tk.PhotoImage(file="bg_4.png")

    soundFlag = [0,False]

    QRcodeRead = pygame.mixer.Sound("QRcodeRead.wav")
    start_call = pygame.mixer.Sound("start_call.wav")
    time_explanation = pygame.mixer.Sound("time_explanation.wav")
    select_explanation = pygame.mixer.Sound("select_explanation.wav")
    rest10 = pygame.mixer.Sound("rest10.wav")
    rest5 = pygame.mixer.Sound("rest5.wav")
    rest3 = pygame.mixer.Sound("rest3.wav")
    rest2 = pygame.mixer.Sound("rest2.wav")
    rest1 = pygame.mixer.Sound("rest1.wav")
    DL_explanation = pygame.mixer.Sound("DL_explanation.wav")
    printing_explanation = pygame.mixer.Sound("printing_explanation.wav")

    # -------------------------------------------- #

    # -------------------------------------------- #
    capture = cv2.VideoCapture(0)
    #capture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(‘H’, ‘2’, ‘6’, ‘4’))
    capture.set(cv2.CAP_PROP_FPS, 30)
    capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1244)
    capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 700)
    # -------------------------------------------- #

    # ------------------ Scene1 ------------------ #

    scene1 = tk.Frame(root, width=1920, height=1080)
    scene1.grid(row=0, column=0, sticky="nsew")

    scene1.propagate(False) #Frameサイズを固定

    frame1_1 = tk.Frame(scene1, width=540, height=750)
    frame1_2 = tk.Frame(scene1, width=840, height=750)
    frame1_3 = tk.Frame(scene1, width=540, height=750)
    frame1_4 = tk.Frame(scene1, width=1920, height=330)

    frame1_1.propagate(False) #Frameサイズを固定
    frame1_2.propagate(False)
    frame1_3.propagate(False)
    frame1_4.propagate(False)
 
    frame1_1.grid(row=0, column=0) #Frameを配置（grid）
    frame1_2.grid(row=0, column=1)
    frame1_3.grid(row=0, column=2)
    frame1_4.grid(row=1, column=0, columnspan = 3)

    canvas1_1 = tk.Canvas(frame1_1,width=540,height=750, highlightthickness=0)
    canvas1_2 = tk.Canvas(frame1_2,width=840,height=750, highlightthickness=0)
    canvas1_3 = tk.Canvas(frame1_3,width=540,height=750, highlightthickness=0)
    canvas1_4 = tk.Canvas(frame1_4,width=1920,height=330, highlightthickness=0)

    canvas1_1.grid(row=0, column=0)
    canvas1_2.grid(row=0, column=1)
    canvas1_3.grid(row=0, column=2)
    canvas1_4.grid(row=1, column=0, columnspan=3)

    qrread = tk.PhotoImage(file="qrread.png")

    canvas1_1.create_image(270,375,image=bg_1)
    canvas1_3.create_image(270,375,image=bg_3)
    canvas1_4.create_image(960,165,image=qrread)

    frame1_2_GUI()

    # ------------------ Scene2 ------------------ #

    scene2 = tk.Frame(root, width=1920, height=1080)
    scene2.grid(row=0, column=0, sticky="nsew")

    scene2.propagate(False) #Frameサイズを固定

    frame1 = tk.Frame(scene2, width=1920, height=200)
    frame2 = tk.Frame(scene2, width=800, height=880)
    frame3 = tk.Frame(scene2, width=320, height=880)
    frame4 = tk.Frame(scene2, width=800, height=880)

    frame1.propagate(False) #Frameサイズを固定
    frame2.propagate(False)
    frame3.propagate(False)
    frame4.propagate(False)
 
    frame1.grid(row=0, column=0, columnspan = 3) #Frameを配置（grid）
    frame2.grid(row=1, column=0)
    frame3.grid(row=1, column=1)
    frame4.grid(row=1, column=2)

    # ----------- frame1 ----------- #
    canvas2_1a = tkinter.Canvas(frame1,width=860,height=200, highlightthickness=0)
    canvas2_1b = tkinter.Canvas(frame1,width=200,height=200, highlightthickness=0)
    canvas2_1c = tkinter.Canvas(frame1,width=860,height=200, highlightthickness=0)

    canvas2_1a.grid(row=0, column=0)
    canvas2_1b.grid(row=0, column=1)
    canvas2_1c.grid(row=0, column=2)

    canvas2_1a.create_image(430,100,image=bg_1_a)
    canvas2_1c.create_image(430,100,image=bg_1_c)

    # ----------- frame2 ----------- #    
    canvas2_2 = tkinter.Canvas(frame2,width=800,height=880, highlightthickness=0)                             
    canvas2_2.pack()

    canvas2_2.bind("<ButtonPress-1>", lambda event:on_pressed(event,0))
    canvas2_2.bind("<B1-Motion>", lambda event:on_dragged(event,0))
    canvas2_2.bind("<Motion>", lambda event:on_moved(event,0))
    
    # ----------- frame3 ----------- #
    canvas2_3 = tkinter.Canvas(frame3,width=320,height=880, highlightthickness=0)
    canvas2_3.pack()

    pen_bg = tk.PhotoImage(file="pen_bg.png")
    stamp_bg = tk.PhotoImage(file="stamp_bg.png")

    canvas2_3.create_image(160,440,image=bg_3)
    canvas2_3.create_image(82.5,250,image=pen_bg)
    canvas2_3.create_image(237.5,250,image=pen_bg)
    canvas2_3.create_image(160,690,image=stamp_bg)

    icon1 = tk.PhotoImage(file="icon1.png")
    icon2 = tk.PhotoImage(file="icon2.png")
    icon3 = tk.PhotoImage(file="icon3.png")
    icon4 = tk.PhotoImage(file="icon4.png")
    icon1_off = tk.PhotoImage(file="icon1_off.png")
    icon2_off = tk.PhotoImage(file="icon2_off.png")
    icon3_off = tk.PhotoImage(file="icon3_off.png")
    icon4_off = tk.PhotoImage(file="icon4_off.png")
    brush_widgh1 = tk.PhotoImage(file="brush_widgh1.png")
    brush_widgh2 = tk.PhotoImage(file="brush_widgh2.png")
    brush_widgh3 = tk.PhotoImage(file="brush_widgh3.png")
    brush_widgh4 = tk.PhotoImage(file="brush_widgh4.png")
    brush_widgh1_off = tk.PhotoImage(file="brush_widgh1_off.png")
    brush_widgh2_off = tk.PhotoImage(file="brush_widgh2_off.png")
    brush_widgh3_off = tk.PhotoImage(file="brush_widgh3_off.png")
    brush_widgh4_off = tk.PhotoImage(file="brush_widgh4_off.png")
    icon_stamp1 = tk.PhotoImage(file="icon_stamp1.png")
    icon_stamp2 = tk.PhotoImage(file="icon_stamp2.png")
    icon_stamp3 = tk.PhotoImage(file="icon_stamp3.png")
    icon_stamp4 = tk.PhotoImage(file="icon_stamp4.png")
    icon_stamp1_off = tk.PhotoImage(file="icon_stamp1_off.png")
    icon_stamp2_off = tk.PhotoImage(file="icon_stamp2_off.png")
    icon_stamp3_off = tk.PhotoImage(file="icon_stamp3_off.png")
    icon_stamp4_off = tk.PhotoImage(file="icon_stamp4_off.png")

    # 各種ウィジェットの作成
    button_icon1 = tk.Button(canvas2_3, image=icon1_off, compound="top", command=brush1, relief=tk.RAISED)
    button_icon2 = tk.Button(canvas2_3, image=icon2, compound="top", command=brush2, relief=tk.RAISED)
    button_icon3 = tk.Button(canvas2_3, image=icon3, compound="top", command=brush3, relief=tk.RAISED)
    button_icon4 = tk.Button(canvas2_3, image=icon4, compound="top", command=eraser1, relief=tk.RAISED)

    button_brush_widgh4 = tk.Button(canvas2_3, image=brush_widgh4_off, compound="top", command=brush_widgh4_setting, relief=tk.RAISED)
    button_brush_widgh3 = tk.Button(canvas2_3, image=brush_widgh3, compound="top", command=brush_widgh3_setting, relief=tk.RAISED)
    button_brush_widgh2 = tk.Button(canvas2_3, image=brush_widgh2, compound="top", command=brush_widgh2_setting, relief=tk.RAISED)
    button_brush_widgh1 = tk.Button(canvas2_3, image=brush_widgh1, compound="top", command=brush_widgh1_setting, relief=tk.RAISED)

    button_stamp1 = tk.Button(canvas2_3, image=icon_stamp1, compound="top", command=stamp1, relief=tk.RAISED)
    button_stamp2 = tk.Button(canvas2_3, image=icon_stamp2, compound="top", command=stamp2, relief=tk.RAISED)
    button_stamp3 = tk.Button(canvas2_3, image=icon_stamp3, compound="top", command=stamp3, relief=tk.RAISED)
    button_stamp4 = tk.Button(canvas2_3, image=icon_stamp4, compound="top", command=stamp4, relief=tk.RAISED)

    button_icon1.place(x = 30, y = 30)
    button_icon2.place(x = 30, y = 140)
    button_icon3.place(x = 30, y = 250)
    button_icon4.place(x = 30, y = 360)
    button_brush_widgh4.place(x = 185, y = 30)
    button_brush_widgh3.place(x = 185, y = 140)
    button_brush_widgh2.place(x = 185, y = 250)
    button_brush_widgh1.place(x = 185, y = 360)
    button_stamp1.place(x = 50, y = 590)
    button_stamp2.place(x = 165, y = 590)
    button_stamp3.place(x = 50, y = 725)
    button_stamp4.place(x = 165, y = 725)

    # ----------- frame4 ----------- #
    canvas2_4 = tkinter.Canvas(frame4,width=800,height=880, highlightthickness=0)                             
    canvas2_4.pack()

    canvas2_4.bind("<ButtonPress-1>", lambda event:on_pressed(event,1))
    canvas2_4.bind("<B1-Motion>", lambda event:on_dragged(event,1))
    canvas2_4.bind("<Motion>", lambda event:on_moved(event,1))

    frame1b_GUI()

    # ------------------ Scene3 ------------------ #

    scene3 = tk.Frame(root, width=1920, height=1080)
    scene3.grid(row=0, column=0, sticky="nsew")

    scene3.propagate(False) #Frameサイズを固定

    canvas3_1 = tk.Canvas(scene3,width=1920,height=1080, highlightthickness=0)
    canvas3_1.pack(padx=0, pady=0)

    scene3_1=tk.PhotoImage(file='scene3_1.png')
    scene3_2=tk.PhotoImage(file='scene3_2.png')

    # -------------------------------------------- #

    show_scene1()
    world_timer()

    root.mainloop()
```

</details>

# さいごに
ここまで読んでいただきありがとうございます。
初めての制作ということもあって有識者の方から見たな至らぬところがたくさんあると思いまが、来年度へ向けて改善していきたいと考えています。
もしアドバイスや改善案などありましたらコメントいただけますと大変うれしいです。
よろしくお願いいたします。