うみゅ commited on
Commit
9fe3aaa
2 Parent(s): 4eb0e5c 4b09826

Merge pull request #8 from umyuu/feature/0.0.7

Browse files
.github/workflows/deploy.yml CHANGED
@@ -1,18 +1,21 @@
1
- # このGit Actionのワークフローは、git pushコマンドを使用し、HuggingFaceのSpaceにデプロイを行います。
2
- # 公式資料 https://huggingface.co/docs/hub/spaces-github-actions
3
- ## ワークフロー構成
4
- # [GitHub]のリポジトリ → ワークフローによるgit push → [HuggingFace]のSpaceのリポジトリ
5
- ## ワークフローの初期設定
6
- # 1, 認証情報を環境変数に設定
7
- # Settingsタブの「Secrets and variables」 > 「Actions」 > 「Repository secrets」に変数を設定してください。
8
- # HF_TOKEN…アクセストークン、アクセストークンの発行は、https://huggingface.co/settings/tokens よりTypeを「Write」で発行します。
9
- # HF_USER_NAME…ユーザー名
10
- # HF_SPACE_URL…HuggingFaceのSpaceのアドレス
11
- # 2, デプロイ時の環境保護ルールを適用します。
12
- # Settingsタブの「Environments」 > 「new Environment」 > Name に「production」で作成します。
13
- # Deployment protection rulesを設定します。
 
 
14
  name: "Deploy"
15
  on:
 
16
  push:
17
  branches: [ "main" ]
18
  # Actionsタブからワークフローの手動実行を許可します。
@@ -21,13 +24,14 @@ on:
21
  jobs:
22
  sync-to-hub:
23
  runs-on: ubuntu-latest
24
- # productionの設定情報を使用します。
25
  environment: production
26
  steps:
 
27
  - uses: actions/checkout@v4
28
  with:
29
  fetch-depth: 0
30
  lfs: true
31
-
32
  - name: Push to hub
33
  run: git push https://${{ secrets.HF_USER_NAME }}:${{ secrets.HF_TOKEN }}@${{ secrets.HF_SPACE_URL }} main
 
1
+ # このGitHub Actionsのワークフローは、HuggingFaceのSpace(以下、Space)にデプロイを行うためのものです。
2
+ # 具体的には、GitHubのリポジトリをチェックアウトし、その内容をSpaceにgit pushします。
3
+ # 詳細な手順はHuggingFaceの公式ドキュメントを参照してください: https://huggingface.co/docs/hub/spaces-github-actions
4
+ ## ワークフローの設定手順
5
+ # 1, HuggingFaceで「Write」タイプのアクセストークンを生成します。このトークンは認証に使用します。
6
+ # 生成はこちらから: https://huggingface.co/settings/tokens
7
+ # 2, GitHubのリポジトリの設定で、生成したアクセストークンと他の情報を環境変数として設定します。
8
+ # 設定は「Settings」タブの「Secrets and variables」 > 「Actions」 > 「Repository secrets」から行います。
9
+ # 設定する変数は以下の通りです:
10
+ # HF_TOKEN: HuggingFaceで生成したアクセストークン
11
+ # HF_USER_NAME: HuggingFaceのユーザー名
12
+ # HF_SPACE_URL: SpaceのURL
13
+ # 3, デプロイ時の環境保護ルールを適用します。
14
+ # 「Settings」タブの「Environments」 > 「new Environment」 > Name に「production」を入力して新しい環境設定を作成します。
15
+ # その後、Deployment protection rulesを設定します。
16
  name: "Deploy"
17
  on:
18
+ # mainブランチへのpushをトリガーにします。
19
  push:
20
  branches: [ "main" ]
21
  # Actionsタブからワークフローの手動実行を許可します。
 
24
  jobs:
25
  sync-to-hub:
26
  runs-on: ubuntu-latest
27
+ # productionの設定情報を使用します。これにより、デプロイ時の環境保護ルールを適用できます。
28
  environment: production
29
  steps:
30
+ # GitHubのリポジトリをチェックアウトします。
31
  - uses: actions/checkout@v4
32
  with:
33
  fetch-depth: 0
34
  lfs: true
35
+ # チェックアウトしたコードをSpaceにgit pushします。
36
  - name: Push to hub
37
  run: git push https://${{ secrets.HF_USER_NAME }}:${{ secrets.HF_TOKEN }}@${{ secrets.HF_SPACE_URL }} main
.vscode/extensions.json CHANGED
@@ -1,5 +1,6 @@
1
  {
2
  "recommendations": [
3
- "ms-python.flake8"
 
4
  ]
5
  }
 
1
  {
2
  "recommendations": [
3
+ "ms-python.flake8",
4
+ "ms-python.vscode-pylance"
5
  ]
6
  }
.vscode/launch.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // IntelliSense を使用して利用可能な属性を学べます。
3
+ // 既存の属性の説明をホバーして表示します。
4
+ // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "Python デバッガー: 引数を含む現在のファイル",
9
+ "type": "debugpy",
10
+ "request": "launch",
11
+ "program": "app.py",
12
+ "console": "integratedTerminal",
13
+ "args": "${command:pickArgs}"
14
+ }
15
+ ]
16
+ }
.vscode/settings.json CHANGED
@@ -2,10 +2,13 @@
2
  "cSpell.words": [
3
  "asctime",
4
  "astype",
 
 
5
  "dtype",
6
  "fromarray",
7
  "Gradio",
8
  "inbrowser",
 
9
  "ndarray"
10
  ],
11
  "python.analysis.typeCheckingMode": "basic",
 
2
  "cSpell.words": [
3
  "asctime",
4
  "astype",
5
+ "codeql",
6
+ "Colab",
7
  "dtype",
8
  "fromarray",
9
  "Gradio",
10
  "inbrowser",
11
+ "msecs",
12
  "ndarray"
13
  ],
14
  "python.analysis.typeCheckingMode": "basic",
CONTRIBUTING.md DELETED
@@ -1,5 +0,0 @@
1
- ## プルリクエストについて
2
- - プルリクエストの派生元ブランチ
3
- main ブランチから派生させてプルリクエストを作成してください。
4
- - プルリクエストのライセンス:
5
- プルリクエストを送信することで、あなたの貢献がリポジトリと同じMITライセンスに従うこと、そしてあなたの貢献が将来的にプロジェクトのライセンス変更に含まれる可能性があることに**ご理解とご協力**をお願いします。
 
 
 
 
 
 
README.md CHANGED
@@ -7,33 +7,33 @@ colorFrom: yellow
7
  colorTo: yellow
8
  pinned: false
9
  ---
10
- # SaliencyMap — in Python
11
- ![Python version](https://img.shields.io/badge/python-3.8+-important)
12
- <a href="https://colab.research.google.com/github/umyuu/SaliencyMapDemo/blob/main/launch_app.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>
13
 
14
- ## 概要
15
  画像における注目すべき領域を可視化する「顕著性マップ」を表示するデモアプリです。
16
  私は画像処理についてはまだ初心者ですが、この技術に興味があります。
17
  本アプリは、opencv-contribパッケージの`cv2.saliency.StaticSaliencySpectralResidual`を関数を実行するラッパーアプリです。
18
 
19
- ## 使い方
20
  ### a. Google Colabで実行
21
- <a href="https://colab.research.google.com/github/umyuu/SaliencyMapDemo/blob/main/launch_app.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>をクリックして、簡単に実行できます。
22
 
23
  ### b. アプリをダウンロードして実行
24
- #### システム要件
25
  - 必要ディスク容量:500MB(Pythonを含みません)
26
  - Python のダウンロード:https://www.python.org/downloads/
27
 
28
- #### 導入方法
29
  ##### 1. セットアップ
30
- 1. [Releases](https://github.com/umyuu/SaliencyMapDemo/releases)ページを開き、一番上の `Assets` 欄にある `Source code (zip)` をダウンロードして展開します。
31
  2. `01-installation.bat`ファイルをダブルクリックします。
32
  ##### 2. 実行
33
  `run.bat`ファイルをダブルクリックします。
34
  ブラウザが自動起動し、http://127.0.0.1:9999 にアクセスできます。
35
 
36
- **トラブルシューティング**
37
  - アプリが起動しない場合
38
  既定のポート番号 (9999) が使用されている可能性があります。
39
  メモ帳で `run.bat` ファイルを開き、以下の行の `9999` を別の数字 (例: 8888) に変更して上書き保存します。
@@ -44,10 +44,10 @@ pinned: false
44
  ~~~
45
  python app.py --server_port 8888
46
  ~~~
47
- ##### 補足事項
48
  - アプリをダウンロードして実行の場合は、画像処理はローカル環境で行われます。画像は外部に送信されません。
49
 
50
- ##### アンインストール
51
  以下の手順でアンインストールできます。
52
  1. アプリのフォルダを丸ごと削除します。
53
  2. アプリで処理した画像は一時フォルダに残ります。不要な場合は削除してください。
@@ -57,5 +57,8 @@ pinned: false
57
  C:\Users\%USERNAME%\AppData\Local\Temp\gradio
58
  ~~~
59
 
60
- ## Source code License.
 
 
 
61
  [MIT License](LICENSE)
 
7
  colorTo: yellow
8
  pinned: false
9
  ---
10
+ # 📖 SaliencyMap — in Python
11
+ ![Python version](https://img.shields.io/badge/python-3.9+-important)
12
+ <a href="https://colab.research.google.com/github/umyuu/SaliencyMapDemo/blob/main/scripts/launch_app.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>
13
 
14
+ ## 📝 概要
15
  画像における注目すべき領域を可視化する「顕著性マップ」を表示するデモアプリです。
16
  私は画像処理についてはまだ初心者ですが、この技術に興味があります。
17
  本アプリは、opencv-contribパッケージの`cv2.saliency.StaticSaliencySpectralResidual`を関数を実行するラッパーアプリです。
18
 
19
+ ## 🚀 使い方
20
  ### a. Google Colabで実行
21
+ <a href="https://colab.research.google.com/github/umyuu/SaliencyMapDemo/blob/main/scripts/launch_app.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>をクリックして、簡単に実行できます。
22
 
23
  ### b. アプリをダウンロードして実行
24
+ #### 💻 システム要件
25
  - 必要ディスク容量:500MB(Pythonを含みません)
26
  - Python のダウンロード:https://www.python.org/downloads/
27
 
28
+ #### 📥 導入方法
29
  ##### 1. セットアップ
30
+ 1. [Releases](/releases)ページを開き、一番上の `Assets` 欄にある `Source code (zip)` をダウンロードして展開します。
31
  2. `01-installation.bat`ファイルをダブルクリックします。
32
  ##### 2. 実行
33
  `run.bat`ファイルをダブルクリックします。
34
  ブラウザが自動起動し、http://127.0.0.1:9999 にアクセスできます。
35
 
36
+ **🔧 トラブルシューティング**
37
  - アプリが起動しない場合
38
  既定のポート番号 (9999) が使用されている可能性があります。
39
  メモ帳で `run.bat` ファイルを開き、以下の行の `9999` を別の数字 (例: 8888) に変更して上書き保存します。
 
44
  ~~~
45
  python app.py --server_port 8888
46
  ~~~
47
+ ##### 💡 補足事項
48
  - アプリをダウンロードして実行の場合は、画像処理はローカル環境で行われます。画像は外部に送信されません。
49
 
50
+ ##### 🗑️ アンインストール
51
  以下の手順でアンインストールできます。
52
  1. アプリのフォルダを丸ごと削除します。
53
  2. アプリで処理した画像は一時フォルダに残ります。不要な場合は削除してください。
 
57
  C:\Users\%USERNAME%\AppData\Local\Temp\gradio
58
  ~~~
59
 
60
+ ## 🤝 コントリビューターガイドライン
61
+ [CONTRIBUTING](docs/CONTRIBUTING.md)
62
+
63
+ ## 📜 Source code License.
64
  [MIT License](LICENSE)
app.py CHANGED
@@ -3,18 +3,26 @@
3
  SaliencyMapDemo
4
  """
5
  from argparse import ArgumentParser, BooleanOptionalAction
 
 
 
 
 
 
6
 
7
  from src import PROGRAM_NAME, get_package_version
8
- from src.myapp import run_app
 
 
9
 
10
  __version__ = get_package_version()
 
 
11
 
12
 
13
- def main():
14
  """
15
- エントリーポイント
16
- 1, コマンドライン引数の解析を行います
17
- 2, アプリを起動します。
18
  """
19
  parser = ArgumentParser(prog=PROGRAM_NAME, description=PROGRAM_NAME)
20
  parser.add_argument('--inbrowser',
@@ -25,11 +33,144 @@ def main():
25
  type=int, default=7860, help="Gradio server port")
26
  parser.add_argument('--max_file_size',
27
  type=str, default="20MB", help="Gradio max file size")
28
- parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
- args = parser.parse_args()
31
- run_app(args)
32
 
33
 
34
  if __name__ == "__main__":
35
- main()
 
 
 
 
 
 
 
 
3
  SaliencyMapDemo
4
  """
5
  from argparse import ArgumentParser, BooleanOptionalAction
6
+ #from datetime import datetime
7
+ import sys
8
+ from typing import Literal
9
+
10
+ import gradio as gr
11
+ import numpy as np
12
 
13
  from src import PROGRAM_NAME, get_package_version
14
+ from src.reporter import log
15
+ from src.saliency import SaliencyMap, convert_colormap
16
+ from src.utils import Stopwatch
17
 
18
  __version__ = get_package_version()
19
+ log.info("#アプリ起動中")
20
+ watch = Stopwatch.start_new()
21
 
22
 
23
+ def parse_args():
24
  """
25
+ コマンドライン引数の解析を行います
 
 
26
  """
27
  parser = ArgumentParser(prog=PROGRAM_NAME, description=PROGRAM_NAME)
28
  parser.add_argument('--inbrowser',
 
33
  type=int, default=7860, help="Gradio server port")
34
  parser.add_argument('--max_file_size',
35
  type=str, default="20MB", help="Gradio max file size")
36
+ parser.add_argument('--version',
37
+ action='version', version=f'%(prog)s {__version__}')
38
+
39
+ return parser.parse_args()
40
+
41
+
42
+ def jet_tab_selected(image: np.ndarray):
43
+ """
44
+ JETタブを選択時
45
+ """
46
+ sw = Stopwatch.start_new()
47
+ log.info(f"#jet_tab_selected({sw.elapsed:.3f}s)")
48
+ saliency = SaliencyMap("SpectralResidual")
49
+ success, saliency_map = saliency.compute(image)
50
+ if not success:
51
+ return image # エラーが発生した場合は入力画像を返します。
52
+ retval = convert_colormap(image, saliency_map, "jet")
53
+ log.info(f"#jet_tab_selected({sw.elapsed:.3f}s)")
54
+ return retval
55
+
56
+
57
+ def hot_tab_selected(image: np.ndarray):
58
+ """
59
+ HOTタブを選択時
60
+ """
61
+ sw = Stopwatch.start_new()
62
+ log.info(f"#hot_tab_selected({sw.elapsed:.3f}s)")
63
+ saliency = SaliencyMap("SpectralResidual")
64
+ success, saliency_map = saliency.compute(image)
65
+ if not success:
66
+ return image # エラーが発生した場合は入力画像を返します。
67
+ retval = convert_colormap(image, saliency_map, "turbo")
68
+ log.info(f"#hot_tab_selected({sw.elapsed:.3f}s)")
69
+ return retval
70
+
71
+
72
+ def submit_clicked(image: np.ndarray, algorithm: Literal["SpectralResidual", "FineGrained"]):
73
+ """
74
+ 入力画像を元に顕著マップを計算します。
75
+
76
+ Parameters:
77
+ image: 入力画像
78
+ str: 顕著性マップのアルゴリズム
79
+ Returns:
80
+ np.ndarray: JET画像
81
+ np.ndarray: HOT画像
82
+ """
83
+ sw = Stopwatch.start_new()
84
+ log.info(f"#submit_clicked({sw.elapsed:.3f}s)")
85
+ #
86
+ saliency = SaliencyMap(algorithm)
87
+ log.debug(f"#SaliencyMap({sw.elapsed:.3f}s)")
88
+ success, saliency_map = saliency.compute(image)
89
+ log.debug(f"#compute({sw.elapsed:.3f}s)")
90
+
91
+ if not success:
92
+ return image, image # エラーが発生した場合は入力画像を返します。
93
+
94
+ log.debug(f"#jet({sw.elapsed:.3f}s)")
95
+ jet = convert_colormap(image, saliency_map, "jet")
96
+ # jet = None
97
+ log.debug(f"#hot({sw.elapsed:.3f}s)")
98
+ hot = convert_colormap(image, saliency_map, "hot")
99
+ saliency = None
100
+ log.info(f"#submit_clicked({sw.elapsed:.3f}s)")
101
+ return jet, hot
102
+
103
+
104
+ args = parse_args()
105
+ """
106
+ アプリの画面を作成し、Gradioサービスを起動します。
107
+ analytics_enabled=False
108
+ https://github.com/gradio-app/gradio/issues/4226
109
+ ホットリロード対応として、topレベルのインデントに。
110
+ https://www.gradio.app/guides/developing-faster-with-reload-mode
111
+ """
112
+ with gr.Blocks(
113
+ analytics_enabled=False,
114
+ title=f"{PROGRAM_NAME} {get_package_version()}",
115
+ head="""
116
+ <meta name="format-detection" content="telephone=no">
117
+ <meta name="robots" content="noindex, nofollow, noarchive">
118
+ <meta name="referrer" content="no-referrer" />
119
+ """
120
+ ) as demo:
121
+ gr.Markdown("""
122
+ # Saliency Map demo.
123
+ """)
124
+ with gr.Accordion("取り扱い説明書", open=False):
125
+ gr.Markdown("""
126
+ 1. inputタブで画像を選択します。
127
+ 2. Submitボタンを押します。
128
+ 3. 結果は、JETタブとHOTタブに表示します。
129
+ """)
130
+ algorithm_type = gr.Radio(
131
+ ["SpectralResidual", "FineGrained"],
132
+ label="Saliency",
133
+ value="SpectralResidual",
134
+ interactive=True
135
+ )
136
+
137
+ submit_button = gr.Button("submit", variant="primary")
138
+
139
+ with gr.Row():
140
+ with gr.Tab("input", id="input"):
141
+ image_input = gr.Image(sources=["upload", "clipboard"], interactive=True)
142
+ with gr.Tab("overlay(JET)"):
143
+ image_overlay_jet = gr.Image(interactive=False)
144
+ # tab_jet.select(jet_tab_selected,
145
+ # inputs=[image_input],
146
+ # outputs=image_overlay_jet)
147
+ with gr.Tab("overlay(HOT)"):
148
+ image_overlay_hot = gr.Image(interactive=False)
149
+ # tab_hot.select(hot_tab_selected,
150
+ # inputs=[image_input],
151
+ # outputs=image_overlay_hot, api_name=False)
152
+ #
153
+ submit_button.click(
154
+ submit_clicked,
155
+ inputs=[image_input, algorithm_type],
156
+ outputs=[image_overlay_jet, image_overlay_hot]
157
+ )
158
+ gr.Markdown(f"""
159
+ Python {sys.version}
160
+ App {get_package_version()}
161
+ """)
162
+
163
+ demo.queue(default_concurrency_limit=1)
164
 
165
+ log.info(f"#アプリ起動完了({watch.elapsed:.3f}s)アプリを終了するにはCtrl+Cキーを入力してください。")
 
166
 
167
 
168
  if __name__ == "__main__":
169
+ # アプリを起動します。
170
+ # https://www.gradio.app/docs/gradio/blocks#blocks-launch
171
+ demo.launch(
172
+ inbrowser=args.inbrowser,
173
+ share=args.share,
174
+ server_port=args.server_port,
175
+ max_file_size=args.max_file_size,
176
+ )
config.json CHANGED
@@ -26,7 +26,7 @@
26
  "handlers": {
27
  "console1": {
28
  "class": "logging.StreamHandler",
29
- "level": "DEBUG",
30
  "formatter": "jst"
31
  }
32
  },
 
26
  "handlers": {
27
  "console1": {
28
  "class": "logging.StreamHandler",
29
+ "level": "INFO",
30
  "formatter": "jst"
31
  }
32
  },
docs/CONTRIBUTING.md ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 📖 Contributing Guide
2
+ ## 🎉 ようこそ!
3
+ このプロジェクトへの関心と貢献に感謝します!あなたの貢献は、このプロジェクトを改善し、コミュニティを成長させるのに大いに役立ちます。このガイドは、プロジェクトへの貢献をスムーズに進めるためのものです。
4
+
5
+ ## 📚 概要
6
+ このガイドでは、リポジトリの構成、プルリクエストの作成方法、バグ報告の方法、およびコーディング規約について説明します。これらのガイドラインを理解し、遵守することで、あなたの貢献がプロジェクトにとって最大の価値を持つことができます。
7
+
8
+ ## 🏗️ リポジトリ構成
9
+ - 📂`/src`: Pythonソースコード。
10
+ 主要な機能のコードが含まれています。
11
+ - 🧪`/test`: Pythonの単体テストコード。
12
+ 各機能の正確さを確認するためのテストスクリプトが含まれています。
13
+ - 📜`/scripts`: 実行用スクリプト。
14
+ Jupyter NotebookとGradioの自動再読み込みスクリプトが含まれており、これらはアプリの実行とデバッグを容易にします。
15
+ - 🎨`/assets`: サンプル画像。
16
+ 視覚的な要素を提供します。
17
+ - 📚`/docs`: ドキュメンテーション。
18
+ - `./CONTRIBUTING.md`: これは現在ご覧になっているドキュメントで、プロジェクトへの貢献方法について詳しく説明しています。新しいコントリビューターはここから始めることをお勧めします。
19
+ - `./ThirdPartyNotices.txt`:参考情報としてこのプロジェクトで使用している外部ライブラリのライセンス情報が記載されています。
20
+ - 📚`/.github`: GitHubの設定ファイルが格納されています。
21
+ - `/.github\ISSUE_TEMPLATE`: issueを作成する際のテンプレートが含まれています。これらのテンプレートは、issueを作成する際のフォーマットを提供し、必要な情報を整理するのに役立ちます。
22
+ - `/.github\workflows`: GitHub Actionsのワークフロー設定。
23
+ - `./codeql.yml`:コードのセキュリティ問題を自動的に検出します。
24
+ - `./deploy.yml`:プロジェクトのデプロイを自動化します。
25
+ - `./python-app.yml`:アプリケーションのコンパイルとflake8のコードチェックとテストコードを実行します。
26
+ - 📚`/.vscode`: vscodeの設定
27
+ アプリケーションの開発に適したVSCodeの設定情報が含まれています。これには、推奨される拡張機能、コードフォーマットの設定などが含まれています。
28
+
29
+ ## 🔀 プルリクエストについて
30
+ - プルリクエストの派生元ブランチ
31
+ main ブランチから派生させてプルリクエストを作成してください。
32
+ - プルリクエストのライセンス:
33
+ プルリクエストを送信することで、あなたの貢献がリポジトリと同じMITライセンスに従うこと、そしてあなたの貢献が将来的にプロジェクトのライセンス変更に含まれる可能性があることに**ご理解とご協力**をお願いします。
34
+
35
+ ## 🐛 バグ報告
36
+ バグを見つけた場合は、まず[既存のissue](../issues)を確認してください。
37
+ 同じバグについてのissueが存在しない場合は、[新しいバグ報告](../issues/new?assignees=&labels=bug&projects=&template=10-problem.yaml)を作成してください。
38
+
39
+ ## 📝 コーディング規約
40
+ - コードスタイル: このプロジェクトではPEP8に準拠し、コードチェックツールとしてflake8を採用しています。VSCodeを使用し開発すると拡張機能がレコメンドされます。拡張機能を導入して確認してください。
41
+ - 変数名: 変数名は明確で意味のある名前を使用してください。ローカル変数以外では一文字の変数名は避け、名前から変数の目的が理解できるようにしてください。
42
+ - ドキュメンテーション: 公開されるすべての関数やクラス、メソッドにはDocstringを追加してください。これにより、他の開発者がコードの目的と動作を理解しやすくなります。
ThirdPartyNotices.txt → docs/ThirdPartyNotices.txt RENAMED
File without changes
launch_app.ipynb → scripts/launch_app.ipynb RENAMED
@@ -1,33 +1,22 @@
1
  {
2
- "nbformat": 4,
3
- "nbformat_minor": 0,
4
- "metadata": {
5
- "colab": {
6
- "provenance": []
7
- },
8
- "kernelspec": {
9
- "name": "python3",
10
- "display_name": "Python 3"
11
- },
12
- "language_info": {
13
- "name": "python"
14
- }
15
- },
16
  "cells": [
17
  {
18
  "cell_type": "markdown",
19
- "source": [
20
- "# アプリのインストール"
21
- ],
22
  "metadata": {
23
  "id": "QBBnZWaddxv4"
24
- }
 
 
 
 
 
 
 
 
25
  },
26
  {
27
  "cell_type": "code",
28
- "source": [
29
- "%cd /content"
30
- ],
31
  "metadata": {
32
  "colab": {
33
  "base_uri": "https://localhost:8080/"
@@ -35,15 +24,17 @@
35
  "id": "7a5Rf_Qee3N1",
36
  "outputId": "c3890145-930e-4889-e57e-22321250461f"
37
  },
38
- "execution_count": 1,
39
  "outputs": [
40
  {
41
- "output_type": "stream",
42
  "name": "stdout",
 
43
  "text": [
44
  "/content\n"
45
  ]
46
  }
 
 
 
47
  ]
48
  },
49
  {
@@ -58,8 +49,8 @@
58
  },
59
  "outputs": [
60
  {
61
- "output_type": "stream",
62
  "name": "stdout",
 
63
  "text": [
64
  "Cloning into 'SaliencyMapDemo'...\n",
65
  "remote: Enumerating objects: 84, done.\u001b[K\n",
@@ -77,9 +68,7 @@
77
  },
78
  {
79
  "cell_type": "code",
80
- "source": [
81
- "%cd SaliencyMapDemo"
82
- ],
83
  "metadata": {
84
  "colab": {
85
  "base_uri": "https://localhost:8080/"
@@ -87,15 +76,17 @@
87
  "id": "H0HI3iKRenJB",
88
  "outputId": "770d3024-43a2-4282-f59d-bc496cba9cf6"
89
  },
90
- "execution_count": 3,
91
  "outputs": [
92
  {
93
- "output_type": "stream",
94
  "name": "stdout",
 
95
  "text": [
96
  "/content/SaliencyMapDemo\n"
97
  ]
98
  }
 
 
 
99
  ]
100
  },
101
  {
@@ -110,8 +101,8 @@
110
  },
111
  "outputs": [
112
  {
113
- "output_type": "stream",
114
  "name": "stdout",
 
115
  "text": [
116
  "Collecting gradio==4.28.3 (from -r requirements.txt (line 1))\n",
117
  " Downloading gradio-4.28.3-py3-none-any.whl (12.2 MB)\n",
@@ -269,18 +260,21 @@
269
  },
270
  {
271
  "cell_type": "markdown",
272
- "source": [
273
- "# 実行"
274
- ],
275
  "metadata": {
276
  "id": "LUcp4xt2fJU9"
277
- }
 
 
 
 
 
 
 
 
278
  },
279
  {
280
  "cell_type": "code",
281
- "source": [
282
- "!python app.py --share"
283
- ],
284
  "metadata": {
285
  "colab": {
286
  "base_uri": "https://localhost:8080/"
@@ -288,11 +282,10 @@
288
  "id": "J3kKmi6Rd95n",
289
  "outputId": "d06135be-5c00-4b68-abba-6606f415ccce"
290
  },
291
- "execution_count": 5,
292
  "outputs": [
293
  {
294
- "output_type": "stream",
295
  "name": "stdout",
 
296
  "text": [
297
  "2024-05-11 12:13:31,862#アプリ起動中\n",
298
  "2024-05-11 12:13:36,775#アプリ起動完了(4.912s)\n",
@@ -304,7 +297,24 @@
304
  "Killing tunnel 127.0.0.1:9999 <> https://90361c40461e1540a1.gradio.live\n"
305
  ]
306
  }
 
 
 
307
  ]
308
  }
309
- ]
310
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  "cells": [
3
  {
4
  "cell_type": "markdown",
 
 
 
5
  "metadata": {
6
  "id": "QBBnZWaddxv4"
7
+ },
8
+ "source": [
9
+ "### アプリの起動 \n",
10
+ "アプリを起動するには、以下の手順を実行してください: \n",
11
+ "1. 画面上部のメニューバーの「ランタイム」をクリックしてください。 \n",
12
+ "2. ドロップダウンメニューが表示されます、「すべてのセルを実行」をクリックしてください。または、キーボードショートカットの「Ctrl+F9」を使用することもできます。 \n",
13
+ "\n",
14
+ "これにより、ノートブック内のすべてのセルが順番に実行され、アプリが起動します。 "
15
+ ]
16
  },
17
  {
18
  "cell_type": "code",
19
+ "execution_count": 1,
 
 
20
  "metadata": {
21
  "colab": {
22
  "base_uri": "https://localhost:8080/"
 
24
  "id": "7a5Rf_Qee3N1",
25
  "outputId": "c3890145-930e-4889-e57e-22321250461f"
26
  },
 
27
  "outputs": [
28
  {
 
29
  "name": "stdout",
30
+ "output_type": "stream",
31
  "text": [
32
  "/content\n"
33
  ]
34
  }
35
+ ],
36
+ "source": [
37
+ "%cd /content"
38
  ]
39
  },
40
  {
 
49
  },
50
  "outputs": [
51
  {
 
52
  "name": "stdout",
53
+ "output_type": "stream",
54
  "text": [
55
  "Cloning into 'SaliencyMapDemo'...\n",
56
  "remote: Enumerating objects: 84, done.\u001b[K\n",
 
68
  },
69
  {
70
  "cell_type": "code",
71
+ "execution_count": 3,
 
 
72
  "metadata": {
73
  "colab": {
74
  "base_uri": "https://localhost:8080/"
 
76
  "id": "H0HI3iKRenJB",
77
  "outputId": "770d3024-43a2-4282-f59d-bc496cba9cf6"
78
  },
 
79
  "outputs": [
80
  {
 
81
  "name": "stdout",
82
+ "output_type": "stream",
83
  "text": [
84
  "/content/SaliencyMapDemo\n"
85
  ]
86
  }
87
+ ],
88
+ "source": [
89
+ "%cd SaliencyMapDemo"
90
  ]
91
  },
92
  {
 
101
  },
102
  "outputs": [
103
  {
 
104
  "name": "stdout",
105
+ "output_type": "stream",
106
  "text": [
107
  "Collecting gradio==4.28.3 (from -r requirements.txt (line 1))\n",
108
  " Downloading gradio-4.28.3-py3-none-any.whl (12.2 MB)\n",
 
260
  },
261
  {
262
  "cell_type": "markdown",
 
 
 
263
  "metadata": {
264
  "id": "LUcp4xt2fJU9"
265
+ },
266
+ "source": [
267
+ "### 🚀 実行 \n",
268
+ "1, 「Running on public URL:」の横のリンクをクリックします。 \n",
269
+ "2, リンクをクリックすると、新しいブラウザのタブが開きアプリを自由に操作できます。 \n",
270
+ "### アプリの停止 \n",
271
+ "1,「!python app.py --share」の行の左側にある■ボタン(停止ボタン)をクリックします。 \n",
272
+ "2, アプリが停止します。 "
273
+ ]
274
  },
275
  {
276
  "cell_type": "code",
277
+ "execution_count": 5,
 
 
278
  "metadata": {
279
  "colab": {
280
  "base_uri": "https://localhost:8080/"
 
282
  "id": "J3kKmi6Rd95n",
283
  "outputId": "d06135be-5c00-4b68-abba-6606f415ccce"
284
  },
 
285
  "outputs": [
286
  {
 
287
  "name": "stdout",
288
+ "output_type": "stream",
289
  "text": [
290
  "2024-05-11 12:13:31,862#アプリ起動中\n",
291
  "2024-05-11 12:13:36,775#アプリ起動完了(4.912s)\n",
 
297
  "Killing tunnel 127.0.0.1:9999 <> https://90361c40461e1540a1.gradio.live\n"
298
  ]
299
  }
300
+ ],
301
+ "source": [
302
+ "!python app.py --share"
303
  ]
304
  }
305
+ ],
306
+ "metadata": {
307
+ "colab": {
308
+ "provenance": []
309
+ },
310
+ "kernelspec": {
311
+ "display_name": "Python 3",
312
+ "name": "python3"
313
+ },
314
+ "language_info": {
315
+ "name": "python"
316
+ }
317
+ },
318
+ "nbformat": 4,
319
+ "nbformat_minor": 0
320
+ }
scripts/run_hot_reload.bat ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ REM Gradioのオートリロード用のスクリプトです。
2
+ @echo on
3
+
4
+ cd %~dp0
5
+ cd ..
6
+ call venv\Scripts\activate
7
+ gradio app.py
8
+
9
+ TIMEOUT /T 10
src/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
  # -*- coding: utf-8 -*-
2
  """src Module"""
3
  from datetime import datetime
4
- import logging.config
5
  import re
6
  from zoneinfo import ZoneInfo
7
 
@@ -35,7 +35,7 @@ class LocalTimeFormatter(logging.Formatter):
35
 
36
  t = dt.strftime(re.sub(self.pattern, "", datefmt))
37
  match = re.search(self.pattern, datefmt)
38
- if not match:
39
  return t
40
 
41
  groups = match.groups()
 
1
  # -*- coding: utf-8 -*-
2
  """src Module"""
3
  from datetime import datetime
4
+ import logging
5
  import re
6
  from zoneinfo import ZoneInfo
7
 
 
35
 
36
  t = dt.strftime(re.sub(self.pattern, "", datefmt))
37
  match = re.search(self.pattern, datefmt)
38
+ if match is None:
39
  return t
40
 
41
  groups = match.groups()
src/myapp.py DELETED
@@ -1,153 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """myapp Widget"""
3
- import argparse
4
- #from datetime import datetime
5
- import sys
6
- from typing import Literal
7
-
8
- import gradio as gr
9
- import numpy as np
10
-
11
- from . import PROGRAM_NAME
12
- from src.reporter import log
13
- from src.saliency import SaliencyMap, convert_colormap
14
- from src.utils import Stopwatch, get_package_version
15
-
16
- log.info("#アプリ起動中")
17
- watch = Stopwatch.start_new()
18
-
19
-
20
- def jet_tab_selected(image: np.ndarray):
21
- """
22
- JETタブを選択時
23
- """
24
- #print(f"{datetime.now()}#jet")
25
- saliency = SaliencyMap("SpectralResidual")
26
- success, saliency_map = saliency.compute(image)
27
- if not success:
28
- return image # エラーが発生した場合は入力画像を返します。
29
- retval = convert_colormap(image, saliency_map, "jet")
30
- #print(f"{datetime.now()}#jet")
31
- return retval
32
-
33
-
34
- def hot_tab_selected(image: np.ndarray):
35
- """
36
- HOTタブを選択時
37
- """
38
- #print(f"{datetime.now()}#hot")
39
- saliency = SaliencyMap("SpectralResidual")
40
- success, saliency_map = saliency.compute(image)
41
- if not success:
42
- return image # エラーが発生した場合は入力画像を返します。
43
- retval = convert_colormap(image, saliency_map, "turbo")
44
- #print(f"{datetime.now()}#hot")
45
- return retval
46
-
47
-
48
- def submit_clicked(image: np.ndarray, algorithm: Literal["SpectralResidual", "FineGrained"]):
49
- """
50
- 入力画像を元に顕著マップを計算します。
51
-
52
- Parameters:
53
- image: 入力画像
54
- str: 顕著性マップのアルゴリズム
55
- Returns:
56
- np.ndarray: JET画像
57
- np.ndarray: HOT画像
58
- """
59
- log.info("#submit_Clicked")
60
- watch = Stopwatch.start_new()
61
- #
62
- saliency = SaliencyMap(algorithm)
63
- success, saliency_map = saliency.compute(image)
64
- #log.info("#SaliencyMap compute()")
65
-
66
- if not success:
67
- return image, image # エラーが発生した場合は入力画像を返します。
68
-
69
- #log.info("#jet")
70
- jet = convert_colormap(image, saliency_map, "jet")
71
- # jet = None
72
- #log.info("#hot")
73
- hot = convert_colormap(image, saliency_map, "hot")
74
- saliency = None
75
- log.info(f"#submit_Clicked End{watch.stop():.3f}")
76
- return jet, hot
77
-
78
-
79
- def run_app(args: argparse.Namespace) -> None:
80
- """
81
- アプリの画面を作成し、Gradioサービスを起動します。
82
-
83
- Parameters:
84
- args: コマンドライン引数
85
- watch: 起動したスタート時間
86
- """
87
- # analytics_enabled=False
88
- # https://github.com/gradio-app/gradio/issues/4226
89
- with gr.Blocks(
90
- analytics_enabled=False,
91
- title=f"{PROGRAM_NAME} {get_package_version()}",
92
- head="""
93
- <meta name="format-detection" content="telephone=no">
94
- <meta name="robots" content="noindex, nofollow, noarchive">
95
- <meta name="referrer" content="no-referrer" />
96
- """
97
- ) as demo:
98
-
99
- gr.Markdown("""
100
- # Saliency Map demo.
101
- """)
102
- with gr.Accordion("取り扱い説明書", open=False):
103
- gr.Markdown("""
104
- 1. inputタブで画像を選択します。
105
- 2. Submitボタンを押します。
106
- 3. 結果は、JETタブとHOTタブに表示します。
107
- """)
108
- algorithm_type = gr.Radio(
109
- ["SpectralResidual", "FineGrained"],
110
- label="Saliency",
111
- value="SpectralResidual",
112
- interactive=True
113
- )
114
-
115
- submit_button = gr.Button("submit", variant="primary")
116
-
117
- with gr.Row():
118
- with gr.Tab("input", id="input"):
119
- image_input = gr.Image(sources=["upload", "clipboard"],
120
- interactive=True)
121
- with gr.Tab("overlay(JET)"):
122
- image_overlay_jet = gr.Image(interactive=False)
123
- # tab_jet.select(jet_tab_selected,
124
- # inputs=[image_input],
125
- # outputs=image_overlay_jet)
126
- with gr.Tab("overlay(HOT)"):
127
- image_overlay_hot = gr.Image(interactive=False)
128
- # tab_hot.select(hot_tab_selected,
129
- # inputs=[image_input],
130
- # outputs=image_overlay_hot, api_name=False)
131
- #
132
- submit_button.click(
133
- submit_clicked,
134
- inputs=[image_input, algorithm_type],
135
- outputs=[image_overlay_jet,
136
- image_overlay_hot]
137
- )
138
-
139
- gr.Markdown(f"""
140
- Python {sys.version}
141
- App {get_package_version()}
142
- """)
143
-
144
- demo.queue(default_concurrency_limit=5)
145
-
146
- log.info(f"#アプリ起動完了({watch.stop():.3f}s)")
147
- # https://www.gradio.app/docs/gradio/blocks#blocks-launch
148
- demo.launch(
149
- inbrowser=args.inbrowser,
150
- share=args.share,
151
- server_port=args.server_port,
152
- max_file_size=args.max_file_size,
153
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/reporter.py CHANGED
@@ -11,6 +11,7 @@
11
  import json
12
  from logging import Logger, getLogger
13
  import logging.config
 
14
  from typing import Optional
15
 
16
  from . import PROGRAM_NAME
 
11
  import json
12
  from logging import Logger, getLogger
13
  import logging.config
14
+
15
  from typing import Optional
16
 
17
  from . import PROGRAM_NAME
src/saliency.py CHANGED
@@ -10,7 +10,7 @@ class SaliencyMap:
10
  """
11
  顕著性マップを計算するクラス。
12
  Example:
13
- from lib.saliency import SaliencyMap
14
 
15
  saliency = SaliencyMap("SpectralResidual")
16
  success, saliencyMap = saliency.compute(image)
 
10
  """
11
  顕著性マップを計算するクラス。
12
  Example:
13
+ from src.saliency import SaliencyMap
14
 
15
  saliency = SaliencyMap("SpectralResidual")
16
  success, saliencyMap = saliency.compute(image)
src/utils.py CHANGED
@@ -1,5 +1,6 @@
1
  # -*- coding: utf-8 -*-
2
  """ユーティリティ"""
 
3
  import time
4
 
5
 
@@ -7,37 +8,49 @@ def get_package_version() -> str:
7
  """
8
  バージョン情報
9
  """
10
- return '0.0.6'
11
 
12
 
 
13
  class Stopwatch:
14
  """
15
- Stopwatch 経過時間を計測するためのクラス。
16
  Example:
17
  from src.utils import Stopwatch
18
 
19
  watch = Stopwatch.start_new()
20
- # 計測する処理
21
- print(f"{watch.stop():.3f}")
22
  """
23
-
24
- def __init__(self):
25
- self._start_time = 0
26
- self._elapsed = 0
27
 
28
  @property
29
- def elapsed(self):
30
  """
31
- 経過時間
32
  """
 
 
 
 
33
  return self._elapsed
34
 
 
 
 
 
 
 
 
35
  def start(self) -> None:
36
  """
37
  計測を開始します。
38
  """
39
  self._start_time = time.perf_counter()
40
  self._elapsed = 0
 
41
 
42
  @classmethod
43
  def start_new(cls):
@@ -48,10 +61,12 @@ class Stopwatch:
48
  stopwatch.start()
49
  return stopwatch
50
 
51
- def stop(self):
52
  """
53
  計測を終了します。
54
  """
55
- end_time = time.perf_counter()
56
- self._elapsed = end_time - self._start_time
 
 
57
  return self._elapsed
 
1
  # -*- coding: utf-8 -*-
2
  """ユーティリティ"""
3
+ from dataclasses import dataclass
4
  import time
5
 
6
 
 
8
  """
9
  バージョン情報
10
  """
11
+ return '0.0.7'
12
 
13
 
14
+ @dataclass
15
  class Stopwatch:
16
  """
17
+ 経過時間を計測するためのクラス。
18
  Example:
19
  from src.utils import Stopwatch
20
 
21
  watch = Stopwatch.start_new()
22
+ ### 計測する処理
23
+ print(f"{watch.elapsed:.3f}")
24
  """
25
+ _start_time: float = 0
26
+ _elapsed: float = 0
27
+ _is_running: bool = False
 
28
 
29
  @property
30
+ def elapsed(self) -> float:
31
  """
32
+ 経過時間を取得します。
33
  """
34
+ if self._is_running:
35
+ end_time = time.perf_counter()
36
+ self._elapsed = end_time - self._start_time
37
+
38
  return self._elapsed
39
 
40
+ @property
41
+ def is_running(self) -> bool:
42
+ """
43
+ 実行中かどうかを取得します。
44
+ """
45
+ return self._is_running
46
+
47
  def start(self) -> None:
48
  """
49
  計測を開始します。
50
  """
51
  self._start_time = time.perf_counter()
52
  self._elapsed = 0
53
+ self._is_running = True
54
 
55
  @classmethod
56
  def start_new(cls):
 
61
  stopwatch.start()
62
  return stopwatch
63
 
64
+ def stop(self) -> float:
65
  """
66
  計測を終了します。
67
  """
68
+ if self._is_running:
69
+ end_time = time.perf_counter()
70
+ self._elapsed = end_time - self._start_time
71
+ self._is_running = False
72
  return self._elapsed