OpenVINO™ によるスタイル転送#
この Jupyter ノートブックはオンラインで起動でき、ブラウザーのウィンドウで対話型環境を開きます。ローカルにインストールすることもできます。次のオプションのいずれかを選択します:
このノートブックは、ONNX モデル・リポジトリーのスタイル転送モデルを使用して、OpenVINO によるスタイル転送を示します。具体的には、画像のコンテンツと別の画像のスタイルを混合するように設計された 高速ニューラルスタイル転送 モデルです。

スタイル転送#
このノートブックでは、次のスタイルに対して 5 つの事前トレーニング済みモデルを使用します: モザイク、レインプリンセス、キャンディー、ウドニー、点描。モデルは ONNX モデル・リポジトリーのものであり、研究論文リアルタイム・スタイル転送と超解像度、およびインスタンス正規化による知覚損失に基づいています。このノートブックの最後では、Web カメラからのライブ推論結果が表示されます。さらに、ビデオファイルをアップロードすることもできます。
注: コンピューターにウェブカメラが搭載されている場合、ノートブックでライブの結果をストリーミングで確認できます。ノートブックをサーバーで実行する場合、ウェブカメラは機能しませんが、ビデオファイルを使用して推論を実行できます。
目次:
準備#
要件をインストール#
%pip install -q "openvino>=2023.1.0"
%pip install -q opencv-python requests tqdm
# `notebook_utils` モジュールを取得
import requests
r = requests.get(
url="https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/utils/notebook_utils.py",
)
open("notebook_utils.py", "w").write(r.text)
Note: you may need to restart the kernel to use updated packages.
Note: you may need to restart the kernel to use updated packages.
23215
インポート#
import collections
import time
import cv2
import numpy as np
from pathlib import Path
import ipywidgets as widgets
from IPython.display import display, clear_output, Image
import openvino as ov
import notebook_utils as utils
次のスタイル:のいずれかを選択します: スタイル転送を行うには、モザイク、レインプリンセス、キャンディー、ウドニー、点描のいずれかのスタイルを選択します。
# ドロップダウンを使用してさまざまなスタイルを選択するオプション
style_dropdown = widgets.Dropdown(
options=["MOSAIC", "RAIN-PRINCESS", "CANDY", "UDNIE", "POINTILISM"],
value="MOSAIC", # デフォルト値を設定
description="Select Style:",
disabled=False,
style={"description_width": "initial"}, # 必要に応じて幅を調整 )
# ドロップダウンの変更を処理し、選択したスタイルをプリントする関数
def print_style(change):
if change["type"] == "change" and change["name"] == "value":
print(f"Selected style {change['new']}")
# ドロップダウンの値の変化を観察
style_dropdown.observe(print_style, names="value")
# ドロップダウンをプリント
display(style_dropdown)
Dropdown(description='Select Style:', options=('MOSAIC', 'RAIN-PRINCESS', 'CANDY', 'UDNIE', 'POINTILISM'), sty…
モデル#
モデルのダウンロード#
前の手順で選択したスタイル転送モデルがダウンロードされていない場合、 model_path
にダウンロードされます。モデルは ONNX Model Zoo によって .onnx
形式で提供されるため、OpenVINO で直接使用できます。ただし、このノートブックでは、トランスフォーメーション API を使用して ONNX を FP16
精度の OpenVINO 中間表現 (IR) に変換する方法も説明します。
# ONNX モデル動物園からモデルをダウンロードするディレクトリー
base_model_dir = "model"
base_url =
"https://github.com/onnx/models/raw/69d69010b7ed6ba9438c392943d2715026792d40/archive/vision/style_transfer/fast_neural_style/model"
# 選択した ONNX モデルはパスにダウンロードされます
model_path = Path(f"{style_dropdown.value.lower()}-9.onnx")
style_url = f"{base_url}/{model_path}"
utils.download_file(style_url, directory=base_model_dir)
model/mosaic-9.onnx: 0%| | 0.00/6.42M [00:00<?, ?B/s]
PosixPath('/opt/home/k8sworker/ci-ai/cibuilds/ov-notebook/OVNotebookOps-727/.workspace/scm/ov-notebook/notebooks/style-transfer-webcam/model/mosaic-9.onnx')
ONNX モデルを OpenVINO IR 形式に変換#
次のステップでは、ONNX モデルを FP16
精度の OpenVINO IR 形式に変換します。ONNX モデルは OpenVINO ランタイムによって直接サポートされていますが、OpenVINO 最適化ツールと機能を活用するには、それらを IR 形式に変換すると便利です。モデル・トランスフォーメーション API の ov.convert_model
Python 関数を使用できます。変換されたモデルはモデル・ディレクトリーに保存されます。この関数は OpenVINO モデルクラスのインスタンスを返します。これは Python インターフェイスですぐに使用できますが、以降に実行するため OpenVINO IR 形式にシリアル化することもできます。モデルがすでに変換されている場合、この手順をスキップできます。
# モデル・トランスフォーメーション API のコマンドを構築します
ov_model = ov.convert_model(f"model/{style_dropdown.value.lower()}-9.onnx")
ov.save_model(ov_model, f"model/{style_dropdown.value.lower()}-9.xml")
# 変換された IR モデルパス
ir_path = Path(f"model/{style_dropdown.value.lower()}-9.xml")
onnx_path = Path(f"model/{model_path}")
モデルのロード#
ONNX モデルと変換された IR モデルの両方が model
ディレクトリーに保存されます。
モデルを実行するには、数行のコードで済みます。まず、OpenVINO ランタイムを初期化します。次に、.bin
および .xml
ファイルからネットワーク・アーキテクチャーとモデルの重みを読み取り、目的のデバイス用にコンパイルします。GPU
を選択した場合は、起動時間が CPU
よりも多少長くなるため、読み込みが完了するまで少し待つ必要があることがあります。
OpenVINO が推論に最適なデバイスを自動的に選択するようにするには、AUTO
を使用します。ほとんどの場合、最適なデバイスは GPU
です (パフォーマンスは向上しますが、起動時間がわずかに長くなります)。下のドロップダウン・リストから利用可能なデバイスを 1 つ選択できます。
OpenVINO ランタイムは、ONNX モデル・リポジトリーから ONNX モデルを直接読み込むことができます。このような場合、IR モデルではなく ONNX パスを使用してモデルをロードします。最良の結果を得るには、OpenVINO 中間表現 (IR) モデルをロードすることを推奨します。
# OpenVINO ランタイムを初期化
core = ov.Core()
# ONNX モデルからネットワークと対応する重みを読み取り
# model = ie_core.read_model(model=onnx_path)
# IR モデルからネットワークと対応する重みを読み取り
model = core.read_model(model=ir_path)
import ipywidgets as widgets
device = widgets.Dropdown(
options=core.available_devices + ["AUTO"],
value="AUTO",
description="Device:",
disabled=False,
)
# CPU 用にモデルをコンパイルするか (または他のデバイスの場合は GPU などに変更)、
# OpenVINO に AUTO で利用可能な最適なデバイスを選択させる
device
Dropdown(description='Device:', index=1, options=('CPU', 'AUTO'), value='AUTO')
compiled_model = core.compile_model(model=model, device_name=device.value)
# 入力ノードと出力ノードを取得
input_layer = compiled_model.input(0)
output_layer = compiled_model.output(0)
入力レイヤーと出力レイヤーには、それぞれ入力ノードと出力ノードの名前があります。fast-neural-style-mosaic-onnx の場合、(1, 3, 224, 224)
形状の入力と出力が 1 つずつあります。
print(input_layer.any_name, output_layer.any_name)
print(input_layer.shape)
print(output_layer.shape)
# 入力サイズを取得
N, C, H, W = list(input_layer.shape)
input1 output1
[1,3,224,224]
[1,3,224,224]
画像を前処理#
モデルを実行する前に入力画像を前処理します。元の画像と入力テンソルを一致させるため、画像の次元とチャネル順序を準備します
フレームを前処理して、
unit8
からfloat32
に変換します。ネットワーク入力サイズに合わせて配列を転置します
# 入力画像を前処理
def preprocess_images(frame, H, W):
"""
Preprocess input image to align with network size
Parameters:
:param frame: input frame
:param H: height of the frame to style transfer model
:param W: width of the frame to style transfer model
:returns: resized and transposed frame
"""
image = np.array(frame).astype("float32")
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
image = cv2.resize(src=image, dsize=(H, W), interpolation=cv2.INTER_AREA)
image = np.transpose(image, [2, 0, 1])
image = np.expand_dims(image, axis=0)
return image
様式化された画像を後処理するヘルパー関数#
変換された IR モデルは、(1, 3, 224, 224) 形状の NumPy float32
配列を出力します。
# 結果を後処理
def convert_result_to_image(frame, stylized_image) -> np.ndarray:
"""
Postprocess stylized image for visualization
Parameters:
:param frame: input frame
:param stylized_image: stylized image with specific style applied
:returns: resized stylized image for visualization
"""
h, w = frame.shape[:2]
stylized_image = stylized_image.squeeze().transpose(1, 2, 0)
stylized_image = cv2.resize(src=stylized_image, dsize=(w, h), interpolation=cv2.INTER_CUBIC)
stylized_image = np.clip(stylized_image, 0, 255).astype(np.uint8)
stylized_image = cv2.cvtColor(stylized_image, cv2.COLOR_BGR2RGB)
return stylized_image
メイン処理関数#
スタイル転送機能は、ウェブカメラまたはビデオファイルを使用して、さまざまな動作モードで実行できます。
def run_style_transfer(source=0, flip=False, use_popup=False, skip_first_frames=0):
"""
Main function to run the style inference:
1. Create a video player to play with target fps (utils.VideoPlayer).
2. Prepare a set of frames for style transfer.
3. Run AI inference for style transfer.
4. 結果を視覚化します。
Parameters:
source: The webcam number to feed the video stream with primary webcam set to "0", or the video path.
flip: To be used by VideoPlayer function for flipping capture image.
use_popup: False for showing encoded frames over this notebook, True for creating a popup window.
skip_first_frames: Number of frames to skip at the beginning of the video.
"""
# ターゲット fps で再生するビデオプレーヤーを作成
player = None
try:
player = utils.VideoPlayer(source=source, flip=flip, fps=30, skip_first_frames=skip_first_frames)
# ビデオ・キャプチャーを開始
Player.start().start()
if use_popup:
title = "Press ESC to Exit"
cv2.namedWindow(winname=title, flags=cv2.WINDOW_GUI_NORMAL | cv2.WINDOW_AUTOSIZE)
processing_times = collections.deque()
while True:
# フレームをグラブ
frame = player.next()
if frame is None:
print("Source ended")
break
# フレームがフル HD より大きい場合は、サイズを縮小してパフォーマンスを向上させます
scale = 720 / max(frame.shape)
if scale < 1:
frame = cv2.resize(
src=frame,
dsize=None,
fx=scale,
fy=scale,
interpolation=cv2.INTER_AREA,
)
# 入力画像を前処理
image = preprocess_images(frame, H, W)
# 入力画像の処理時間を測定
start_time = time.time()
# 推論ステップを実行
stylized_image = compiled_model([image])[output_layer]
stop_time = time.time()
# 様式化された画像の後処理
result_image = convert_result_to_image(frame, stylized_image)
processing_times.append(stop_time - start_time)
# 最後の 200 フレームの処理時間を使用
if len(processing_times) > 200:
processing_times.popleft()
processing_time_det = np.mean(processing_times) * 1000
# 結果を視覚化
f_height, f_width = frame.shape[:2]
fps = 1000 / processing_time_det
cv2.putText(
result_image,
text=f"Inference time: {processing_time_det:.1f}ms ({fps:.1f} FPS)",
org=(20, 40),
fontFace=cv2.FONT_HERSHEY_COMPLEX,
fontScale=f_width / 1000,
color=(0, 0, 255),
thickness=1,
lineType=cv2.LINE_AA,
)
# ちらつきがある場合はこの回避策を使用
if use_popup:
cv2.imshow(title, result_image)
key = cv2.waitKey(1)
# escape = 27
if key == 27:
break
else:
# numpy 配列を jpg にエンコード
_, encoded_img = cv2.imencode(".jpg", result_image, params=[cv2.IMWRITE_JPEG_QUALITY, 90])
# IPython イメージを作成
i = Image(data=encoded_img)
# このノートブックに画像を表示
clear_output(wait=True)
display(i)
# ctrl-c
except KeyboardInterrupt:
print("Interrupted")
# 異なるエラー
except RuntimeError as e:
print(e)
finally:
if player is not None:
# キャプチャーを停止
Player.stop().stop()
if use_popup:
cv2.destroyAllWindows()
スタイル転送の実行#
次に、ウェブカメラまたはビデオファイルのビデオを使用して、スタイル転送モデルを適用します。デフォルトでは、プライマリー Web カメラは source=0
に設定されます。複数のウェブカメラがある場合、0 から始まる連続した番号が割り当てられます。前面カメラを使用する場合は、flip=True
を設定します。一部のウェブブラウザー、特に Mozilla Firefox ではちらつきが発生する場合があります。ちらつきが発生する場合、use_popup=True
を設定してください。
注: ウェブカメラを使用するには、ウェブカメラを備えたコンピューター上でこの Jupyter ノートブックを実行する必要があります。サーバー上で実行すると、ウェブカメラにアクセスできなくなります。ただし、最終ステップではビデオファイルに対して推論を実行することはできます。
ウェブカメラがない場合でも、ビデオファイルを使用してこのデモを実行できます。OpenCV でサポートされている任意の形式
USE_WEBCAM = False
cam_id = 0
video_file =
"https://storage.openvinotoolkit.org/repositories/openvino_notebooks/data/data/video/Coco%20Walking%20in%20Berkeley.mp4"
source = cam_id if USE_WEBCAM else video_file
run_style_transfer(source=source, flip=isinstance(source, int), use_popup=False)

ソースの終わり