Spaces:
Sleeping
Sleeping
Merge pull request #2 from umyuu/feature/0.0.2
Browse files- README.md +40 -25
- ThirdPartyNotices.txt +18 -0
- run.bat +1 -1
- src/app.py +50 -22
- src/launch.py +28 -0
- src/utils.py +34 -0
README.md
CHANGED
|
@@ -1,26 +1,41 @@
|
|
| 1 |
-
#
|
| 2 |
-
##
|
| 3 |
-
|
| 4 |
-
私は画像処理についてはまだ初心者ですが、興味を持っています。
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
[MIT License](LICENSE)
|
|
|
|
| 1 |
+
# SaliencyMap
|
| 2 |
+
## 概要
|
| 3 |
+
顕著性マップを表示するデモアプリです。
|
| 4 |
+
私は画像処理についてはまだ初心者ですが、興味を持っています。
|
| 5 |
+
> **技術的なお話**
|
| 6 |
+
> opencv-contribパッケージの`cv2.saliency.StaticSaliencySpectralResidual`を呼び出すラッパーアプリです。
|
| 7 |
+
|
| 8 |
+
## 導入方法
|
| 9 |
+
### 1. セットアップ
|
| 10 |
+
- 以下のファイルをダブルクリックします。
|
| 11 |
+
~~~
|
| 12 |
+
01-installation.bat
|
| 13 |
+
~~~
|
| 14 |
+
### 2. 実行
|
| 15 |
+
1. 以下のファイルをダブルクリックします。
|
| 16 |
+
~~~
|
| 17 |
+
run.bat
|
| 18 |
+
~~~
|
| 19 |
+
2. 実行するとブラウザが起動し[http://127.0.0.1:9999](http://127.0.0.1:9999)を開きます。
|
| 20 |
+
> **NOTE**
|
| 21 |
+
> デフォルトポート番号は、9999です。
|
| 22 |
+
> アプリが起動せずポート番号を変更する時は、メモ帳で`run.bat`を開きの以下行の9999を別の数字(8888)などに変更し保存してください。
|
| 23 |
+
> python src\launch.py --server_port 9999
|
| 24 |
+
> REM 変更後
|
| 25 |
+
> python src\launch.py --server_port 8888
|
| 26 |
+
|
| 27 |
+
## 補足事項
|
| 28 |
+
- ローカルで処理が完結します。画像を外部には送信しません。
|
| 29 |
+
|
| 30 |
+
## Uninstall
|
| 31 |
+
このアプリをアンインストールするには、以下の手順に従ってください。
|
| 32 |
+
- アプリのフォルダをフォルダ毎削除してください。
|
| 33 |
+
- アプリで処理した画像ファイルが一時フォルダに残ります。不要な場合は削除をお願いします。
|
| 34 |
+
- 一時フォルダの場所
|
| 35 |
+
パソコンの画面左下の「検索するには、ここに入力します」に以下をコピペしてEnterを押します。
|
| 36 |
+
~~~
|
| 37 |
+
C:\Users\%USERNAME%\AppData\Local\Temp\gradio
|
| 38 |
+
~~~
|
| 39 |
+
|
| 40 |
+
## Source code License.
|
| 41 |
[MIT License](LICENSE)
|
ThirdPartyNotices.txt
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
NOTICES
|
| 2 |
+
|
| 3 |
+
This repository uses the materials listed or described below.
|
| 4 |
+
|
| 5 |
+
---------------------------------------------------------
|
| 6 |
+
|
| 7 |
+
Gradio - Apache-2.0
|
| 8 |
+
https://github.com/gradio-app/gradio
|
| 9 |
+
---------------------------------------------------------
|
| 10 |
+
|
| 11 |
+
---------------------------------------------------------
|
| 12 |
+
|
| 13 |
+
opencv-python - MIT
|
| 14 |
+
https://github.com/opencv/opencv-python
|
| 15 |
+
|
| 16 |
+
LICENSE-3RD-PARTY.txt
|
| 17 |
+
https://github.com/opencv/opencv-python/blob/master/LICENSE-3RD-PARTY.txt
|
| 18 |
+
---------------------------------------------------------
|
run.bat
CHANGED
|
@@ -2,6 +2,6 @@
|
|
| 2 |
|
| 3 |
cd %~dp0
|
| 4 |
call venv\Scripts\activate
|
| 5 |
-
python src\
|
| 6 |
|
| 7 |
TIMEOUT /T 10
|
|
|
|
| 2 |
|
| 3 |
cd %~dp0
|
| 4 |
call venv\Scripts\activate
|
| 5 |
+
python src\launch.py --server_port 9999
|
| 6 |
|
| 7 |
TIMEOUT /T 10
|
src/app.py
CHANGED
|
@@ -3,15 +3,31 @@
|
|
| 3 |
SaliencyMapDemo
|
| 4 |
"""
|
| 5 |
import argparse
|
|
|
|
|
|
|
|
|
|
| 6 |
import cv2
|
| 7 |
import gradio as gr
|
| 8 |
import numpy as np
|
| 9 |
-
|
|
|
|
| 10 |
|
| 11 |
PROGRAM_NAME = 'SaliencyMapDemo'
|
| 12 |
-
__version__ =
|
| 13 |
|
| 14 |
def compute_saliency(image: np.ndarray):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
# OpenCVのsaliencyを作成
|
| 16 |
saliency = cv2.saliency.StaticSaliencySpectralResidual_create()
|
| 17 |
# 画像の顕著性を計算
|
|
@@ -21,23 +37,41 @@ def compute_saliency(image: np.ndarray):
|
|
| 21 |
# 顕著性マップをカラーマップに変換
|
| 22 |
saliencyMap = (saliencyMap * 255).astype("uint8")
|
| 23 |
saliencyMap = cv2.applyColorMap(saliencyMap, cv2.COLORMAP_JET)
|
|
|
|
|
|
|
| 24 |
# 元の画像とカラーマップを重ね合わせ
|
| 25 |
overlay = cv2.addWeighted(image, 0.5, saliencyMap, 0.5, 0)
|
|
|
|
| 26 |
return overlay
|
| 27 |
else:
|
| 28 |
return image # エラーが発生した場合は元の画像を返す
|
| 29 |
|
| 30 |
-
def
|
| 31 |
"""
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
"""
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
gr.Markdown(
|
| 36 |
"""
|
| 37 |
# Saliency Map demo.
|
| 38 |
1. inputタブで画像を選択します。
|
| 39 |
-
2. Submit
|
| 40 |
-
|
|
|
|
| 41 |
""")
|
| 42 |
|
| 43 |
submit_button = gr.Button("submit")
|
|
@@ -46,26 +80,20 @@ def main(args):
|
|
| 46 |
with gr.Tab("input"):
|
| 47 |
image_input = gr.Image()
|
| 48 |
with gr.Tab("overlay"):
|
| 49 |
-
image_overlay = gr.Image()
|
| 50 |
|
| 51 |
|
| 52 |
submit_button.click(compute_saliency, inputs=image_input, outputs=image_overlay)
|
| 53 |
-
|
| 54 |
gr.Markdown(
|
| 55 |
f"""
|
| 56 |
Python {sys.version}
|
| 57 |
App {__version__}
|
| 58 |
""")
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
parser.add_argument('--server_port', type=int, default=9999, help="Gradio server port")
|
| 67 |
-
parser.add_argument('--max_file_size', type=int, default=20 * gr.FileSize.MB, help="Gradio max file size")
|
| 68 |
-
parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(__version__))
|
| 69 |
-
|
| 70 |
-
main(parser.parse_args())
|
| 71 |
-
|
|
|
|
| 3 |
SaliencyMapDemo
|
| 4 |
"""
|
| 5 |
import argparse
|
| 6 |
+
from datetime import datetime
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
import cv2
|
| 10 |
import gradio as gr
|
| 11 |
import numpy as np
|
| 12 |
+
|
| 13 |
+
import utils
|
| 14 |
|
| 15 |
PROGRAM_NAME = 'SaliencyMapDemo'
|
| 16 |
+
__version__ = utils.get_package_version()
|
| 17 |
|
| 18 |
def compute_saliency(image: np.ndarray):
|
| 19 |
+
"""
|
| 20 |
+
入力画像から顕著性マップを作成しJET画像を返します。
|
| 21 |
+
Parameters
|
| 22 |
+
----------
|
| 23 |
+
param1 : np.ndarray
|
| 24 |
+
入力画像
|
| 25 |
+
|
| 26 |
+
Returns
|
| 27 |
+
-------
|
| 28 |
+
np.ndarray
|
| 29 |
+
カラーマップのJET画像
|
| 30 |
+
"""
|
| 31 |
# OpenCVのsaliencyを作成
|
| 32 |
saliency = cv2.saliency.StaticSaliencySpectralResidual_create()
|
| 33 |
# 画像の顕著性を計算
|
|
|
|
| 37 |
# 顕著性マップをカラーマップに変換
|
| 38 |
saliencyMap = (saliencyMap * 255).astype("uint8")
|
| 39 |
saliencyMap = cv2.applyColorMap(saliencyMap, cv2.COLORMAP_JET)
|
| 40 |
+
|
| 41 |
+
#overlay = saliencyMap
|
| 42 |
# 元の画像とカラーマップを重ね合わせ
|
| 43 |
overlay = cv2.addWeighted(image, 0.5, saliencyMap, 0.5, 0)
|
| 44 |
+
|
| 45 |
return overlay
|
| 46 |
else:
|
| 47 |
return image # エラーが発生した場合は元の画像を返す
|
| 48 |
|
| 49 |
+
def run(args: argparse.Namespace, watch: utils.Stopwatch) -> None:
|
| 50 |
"""
|
| 51 |
+
アプリの画面を作成し、Gradioサービスを起動します。
|
| 52 |
+
----------
|
| 53 |
+
param1 : argparse.Namespace
|
| 54 |
+
コマンドライン引数
|
| 55 |
+
param2 : utils.Stopwatch
|
| 56 |
+
起動したスタート時間
|
| 57 |
"""
|
| 58 |
+
# analytics_enabled=False
|
| 59 |
+
# https://github.com/gradio-app/gradio/issues/4226
|
| 60 |
+
with gr.Blocks(analytics_enabled=False, \
|
| 61 |
+
title=f"{PROGRAM_NAME} {__version__}", \
|
| 62 |
+
head="""
|
| 63 |
+
<meta name="format-detection" content="telephone=no">
|
| 64 |
+
<meta name="robots" content="noindex, nofollow, noarchive">
|
| 65 |
+
<meta name="referrer" content="no-referrer" />
|
| 66 |
+
""") as demo:
|
| 67 |
+
|
| 68 |
gr.Markdown(
|
| 69 |
"""
|
| 70 |
# Saliency Map demo.
|
| 71 |
1. inputタブで画像を選択します。
|
| 72 |
+
2. Submitボタンを押します。
|
| 73 |
+
※画像は外部送信していません。ローカルで処理が完結します。
|
| 74 |
+
3. 結果は、overlayタブに表示します。
|
| 75 |
""")
|
| 76 |
|
| 77 |
submit_button = gr.Button("submit")
|
|
|
|
| 80 |
with gr.Tab("input"):
|
| 81 |
image_input = gr.Image()
|
| 82 |
with gr.Tab("overlay"):
|
| 83 |
+
image_overlay = gr.Image(interactive=False)
|
| 84 |
|
| 85 |
|
| 86 |
submit_button.click(compute_saliency, inputs=image_input, outputs=image_overlay)
|
| 87 |
+
|
| 88 |
gr.Markdown(
|
| 89 |
f"""
|
| 90 |
Python {sys.version}
|
| 91 |
App {__version__}
|
| 92 |
""")
|
| 93 |
+
|
| 94 |
+
demo.queue(default_concurrency_limit=5)
|
| 95 |
+
|
| 96 |
+
print(f"{datetime.now()}:アプリ起動完了({watch.stop():.3f}s)")
|
| 97 |
+
|
| 98 |
+
# https://www.gradio.app/docs/gradio/blocks#blocks-launch
|
| 99 |
+
demo.launch(max_file_size=args.max_file_size, server_port=args.server_port, inbrowser=True, share=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/launch.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
SaliencyMapDemo
|
| 4 |
+
"""
|
| 5 |
+
import argparse
|
| 6 |
+
from datetime import datetime
|
| 7 |
+
|
| 8 |
+
from utils import get_package_version, Stopwatch
|
| 9 |
+
|
| 10 |
+
def main():
|
| 11 |
+
"""
|
| 12 |
+
エントリーポイント
|
| 13 |
+
コマンドライン引数の解析を行います
|
| 14 |
+
"""
|
| 15 |
+
print(f"{datetime.now()}:アプリ起動中")
|
| 16 |
+
watch = Stopwatch.startNew()
|
| 17 |
+
|
| 18 |
+
import app
|
| 19 |
+
|
| 20 |
+
parser = argparse.ArgumentParser(prog=app.PROGRAM_NAME, description="SaliencyMapDemo")
|
| 21 |
+
parser.add_argument('--server_port', type=int, default=9999, help="Gradio server port")
|
| 22 |
+
parser.add_argument('--max_file_size', type=int, default=20 * 1024 * 1024, help="Gradio max file size")
|
| 23 |
+
parser.add_argument('--version', action='version', version=f'%(prog)s {get_package_version()}')
|
| 24 |
+
|
| 25 |
+
app.run(parser.parse_args(), watch)
|
| 26 |
+
|
| 27 |
+
if __name__ == "__main__":
|
| 28 |
+
main()
|
src/utils.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
import time
|
| 3 |
+
|
| 4 |
+
def get_package_version() -> str:
|
| 5 |
+
return '0.0.2'
|
| 6 |
+
|
| 7 |
+
class Stopwatch:
|
| 8 |
+
"""
|
| 9 |
+
Stopwatch 経過時間を計測するためのクラスです。
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
def __init__(self):
|
| 13 |
+
self._start_time = None
|
| 14 |
+
self._elapsed = 0;
|
| 15 |
+
|
| 16 |
+
@property
|
| 17 |
+
def Elapsed(self):
|
| 18 |
+
return self._elapsed
|
| 19 |
+
|
| 20 |
+
def start(self) -> None:
|
| 21 |
+
self._start_time = time.perf_counter()
|
| 22 |
+
self._elapsed = 0;
|
| 23 |
+
|
| 24 |
+
@classmethod
|
| 25 |
+
def startNew(cls):
|
| 26 |
+
stopwatch = Stopwatch()
|
| 27 |
+
stopwatch.start()
|
| 28 |
+
return stopwatch
|
| 29 |
+
|
| 30 |
+
def stop(self):
|
| 31 |
+
end_time = time.perf_counter()
|
| 32 |
+
self._elapsed = end_time - self._start_time
|
| 33 |
+
return self._elapsed
|
| 34 |
+
|