TripoSR による単一画像からの3次元モデル推定
Python開発環境,ライブラリ類
Python 3.12 のインストール
インストール済みの場合は実行不要。
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。
REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul
【関連する外部ページ】
Python の公式ページ: https://www.python.org/
AI エディタ Windsurf のインストール
Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは,Windsurfのインストールを説明する。
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。
winget install --scope machine Codeium.Windsurf -e --silent
【関連する外部ページ】
Windsurf の公式ページ: https://windsurf.com/
Gitのインストール
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。
REM Git をシステム領域にインストール
winget install --scope machine --id Git.Git -e --silent
REM Git のパス設定
set "GIT_PATH=C:\Program Files\Git\cmd"
if exist "%GIT_PATH%" (
echo "%PATH%" | find /i "%GIT_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%GIT_PATH%" /M >nul
)
CMakeのインストール
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。
REM CMake をシステム領域にインストール
winget install --scope machine --id Kitware.CMake -e --silent
REM CMake のパス設定
set "GMAKE_PATH=C:\Program Files\CMake\bin"
if exist "%GMAKE_PATH%" (
echo "%PATH%" | find /i "%GMAKE_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%GMAKE_PATH%" /M >nul
)
Visual Studio 2022 Build Toolsとランタイムのインストール
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。
REM Visual Studio 2022 Build Toolsとランタイムのインストール
winget install --scope machine Microsoft.VisualStudio.2022.BuildTools Microsoft.VCRedist.2015+.x64
set VS_INSTALLER="C:\Program Files (x86)\Microsoft Visual Studio\Installer\setup.exe"
set VS_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"
REM C++開発ワークロードのインストール
%VS_INSTALLER% modify --installPath %VS_PATH% ^
--add Microsoft.VisualStudio.Workload.VCTools ^
--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ^
--add Microsoft.VisualStudio.Component.Windows11SDK.22621 ^
--includeRecommended --quiet --norestart
必要なライブラリのインストール
コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install rembg pillow opencv-python trimesh numpy transformers huggingface-hub
cd %USERPROFILE%
git clone https://github.com/VAST-AI-Research/TripoSR.git
cd TripoSR
pip install -r requirements.txt
cd ..
icacls "C:\Program Files\Python312\Lib\site-packages\pymatting" /grant %USERNAME%:(OI)(CI)F /T
icacls "C:\Program Files\Python312\Lib\site-packages\numba" /grant %USERNAME%:(OI)(CI)F /T
mkdir "%USERPROFILE%\.cache\huggingface\hub" 2>nul
icacls "%USERPROFILE%\.cache\huggingface\hub" /grant %USERNAME%:(OI)(CI)F /T
icacls "C:\Program Files\Python312\Lib\site-packages" /grant %USERNAME%:(OI)(CI)M /T
TripoSR による単一画像からの3次元モデル推定プログラム
# プログラム名: TripoSR による単一画像からの3次元モデル推定プログラム
# 特徴技術名: TripoSR(単一画像から3Dモデルを推定する手法)
# 出典: Tochilkin, D., et al. (2024). TripoSR: Fast 3D Object Reconstruction from a Single Image. arXiv preprint arXiv:2403.02151.
# 特徴機能: 高速フィードフォワード3D生成により、単一画像から0.5秒以内で高品質な3Dメッシュを生成する能力
# 学習済みモデル: HuggingFaceで提供されるstabilityai/TripoSRモデル(model.ckpt、1.68GB)。Large Reconstruction Model(LRM)アーキテクチャをベースとし、DINOv1ビジョントランスフォーマーで初期化されたイメージエンコーダを使用。URL: https://huggingface.co/stabilityai/TripoSR
#
# === Windowsでのキャッシュディレクトリ権限設定 ===
#
# 問題1: pymatting/numbaのキャッシュ権限エラーの解決
# 管理者権限のコマンドプロンプトで以下を実行:
# icacls "C:\Program Files\Python312\Lib\site-packages\pymatting" /grant %USERNAME%:(OI)(CI)F /T
# icacls "C:\Program Files\Python312\Lib\site-packages\numba" /grant %USERNAME%:(OI)(CI)F /T
#
# 問題2: HuggingFaceのキャッシュディレクトリ権限
# HuggingFaceのモデルキャッシュはデフォルトで C:\Users\ユーザー名\.cache\huggingface\hub に保存されます。
# mkdir "%USERPROFILE%\.cache\huggingface\hub" 2>nul
# icacls "%USERPROFILE%\.cache\huggingface\hub" /grant %USERNAME%:(OI)(CI)F /T
#
# 方式設計:
# 関連利用技術:
# - PIL(画像処理)
# - NumPy(数値計算)
# - PyTorch(機械学習フレームワーク)
# - rembg(背景除去)
# - trimesh(3Dメッシュ処理)
# - OpenCV(画像入出力・表示)
# - tkinter(ファイル選択)
# - tsr(TripoSRシステム)
# 入力と出力:
# - 入力: 画像(ユーザは「0:画像ファイル,1:カメラ,2:サンプル画像」のメニューで選択.0:画像ファイルの場合はtkinterで複数ファイル選択可能.1の場合はOpenCVでカメラが開き,スペースキーで撮影(複数回可能).2の場合はhttps://github.com/opencv/opencv/raw/master/samples/data/fruits.jpg とhttps://github.com/opencv/opencv/raw/master/samples/data/messi5.jpg とhttps://github.com/opencv/opencv/raw/master/samples/data/aero3.jpgを使用)
# - 出力: 3DメッシュファイルOBJ形式、OpenCV画面での結果表示、result.txtファイルへの処理結果保存
# 処理手順:
# 1. 入力画像の読み込み・前処理
# 2. 背景除去処理
# 3. TripoSRモデルによる3D再構成
# 4. メッシュデータの生成・保存
# 5. 結果の可視化
# 前処理、後処理:
# - 前処理: 背景除去(rembg)、画像リサイズ・正規化
# - 後処理: メッシュの最適化、テクスチャマッピング
# 追加処理: 画像品質向上のための自動コントラスト調整、メッシュの頂点数最適化
# 調整を必要とする設定値: resolution(メッシュ解像度、32-320の範囲)、threshold(背景除去閾値)
#
# 将来方策: 複数画像からの統合3Dモデル生成、リアルタイム処理への拡張
# その他の重要事項: CUDA対応によるGPU加速、メモリ使用量の最適化
#
# 前準備:
# 1. TripoSRのインストール:
# git clone https://github.com/VAST-AI-Research/TripoSR.git
# cd TripoSR
# pip install -r requirements.txt
# cd ..
# そして、TripoSRフォルダをPythonのsite-packagesにコピーするか、
# このスクリプトと同じディレクトリに配置してください
#
# 2. その他の依存関係:
# pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# pip install rembg pillow opencv-python trimesh numpy transformers huggingface-hub
#
# rembg/numbaで問題が発生する場合:
# 1. 以下のコマンドで権限を修正(管理者権限のコマンドプロンプトで実行):
# icacls "C:\Program Files\Python312\Lib\site-packages" /grant %USERNAME%:(OI)(CI)M /T
# 2. または、rembgをアンインストールして背景除去なしで実行:
# pip uninstall rembg pymatting numba llvmlite -y
import os
# Numbaを無効化(必ずインポート前に設定)
os.environ['NUMBA_DISABLE_JIT'] = '1' # Numbaの無効化
os.environ['NUMBA_DISABLE_CUDA'] = '1' # NumbaのCUDA機能を無効化
os.environ['NUMBA_CACHE_DIR'] = r'C:\Users\user\AppData\Local\Temp\numba_cache' # キャッシュディレクトリを変更
# 環境変数の設定(Windowsでキャッシュディレクトリを変更する場合)
# コメントを外して使用してください
# os.environ['HUGGINGFACE_HUB_CACHE'] = r'D:\AI_Models\huggingface\hub'
import cv2
import tkinter as tk
from tkinter import filedialog
import urllib.request
import numpy as np
from PIL import Image
import torch
import trimesh
import tempfile
# rembgのインポートを条件付きに
try:
import rembg
REMBG_AVAILABLE = True
except ImportError:
print('警告: rembgがインストールされていないか、エラーが発生しました。背景除去機能は使用できません。')
REMBG_AVAILABLE = False
# TripoSRシステムのインポート
import sys
import os
# TripoSRがローカルにある場合のパスを追加
if os.path.exists('./TripoSR'):
sys.path.insert(0, './TripoSR')
elif os.path.exists('../TripoSR'):
sys.path.insert(0, '../TripoSR')
try:
from tsr.system import TSR
from tsr.utils import remove_background, resize_foreground
TRIPOSR_AVAILABLE = True
except ImportError:
print('エラー: TripoSRがインストールされていません。')
print('インストール方法:')
print('1. git clone https://github.com/VAST-AI-Research/TripoSR.git')
print('2. cd TripoSR')
print('3. pip install -r requirements.txt')
print('4. このスクリプトと同じディレクトリにTripoSRフォルダを配置')
print('プログラムを終了します。')
exit(1)
# デバイスの設定
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f'使用デバイス: {device}')
# TripoSRモデルのセットアップ
model = None
rembg_session = None
def setup_triposr_model():
global model, rembg_session
try:
print('TripoSRモデルを初期化中...')
model = TSR.from_pretrained(
"stabilityai/TripoSR",
config_name="config.yaml",
weight_name="model.ckpt"
)
# チャンクサイズを調整(メモリ使用量とスピードのバランス)
model.renderer.set_chunk_size(8192)
model.to(device)
print('TripoSRモデルの初期化完了')
# 背景除去セッションの初期化
if REMBG_AVAILABLE:
rembg_session = rembg.new_session()
else:
rembg_session = None
return True
except Exception as e:
print(f'エラー: TripoSRモデルの初期化に失敗しました: {e}')
print('インターネット接続を確認してください。')
print('プログラムを終了します。')
exit(1)
# 背景除去処理(TripoSR互換)
def remove_background_custom(image, session=None):
try:
if not REMBG_AVAILABLE:
print('警告: rembgが利用できません。背景除去をスキップします。')
if isinstance(image, np.ndarray):
return image.astype(np.float32) / 255.0
else:
return np.array(image).astype(np.float32) / 255.0
if session is None:
session = rembg.new_session()
if isinstance(image, np.ndarray):
image_pil = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
else:
image_pil = image
# 背景除去
result = rembg.remove(image_pil, session=session)
# アルファチャンネルを使用して背景を白に設定
result_np = np.array(result).astype(np.float32) / 255.0
if result_np.shape[2] == 4: # RGBA
rgb = result_np[:, :, :3]
alpha = result_np[:, :, 3:4]
result_rgb = rgb * alpha + (1 - alpha)
result_np = result_rgb
return result_np
except Exception as e:
print(f'背景除去に失敗しました: {e}')
if isinstance(image, np.ndarray):
return image.astype(np.float32) / 255.0
else:
return np.array(image).astype(np.float32) / 255.0
# TripoSRを使用した3D再構成
def reconstruct_3d_triposr(image, mc_resolution=256, bake_texture=False, texture_resolution=1024):
try:
if model is None:
return None, None
# 画像の前処理
if isinstance(image, np.ndarray):
if image.dtype == np.uint8:
image = image.astype(np.float32) / 255.0
# BGRからRGBに変換
if len(image.shape) == 3 and image.shape[2] == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# モデルに入力
with torch.no_grad():
scene_codes = model([image], device=device)
# メッシュの抽出
meshes = model.extract_mesh(scene_codes, vertex_colors=not bake_texture, resolution=mc_resolution)
texture_data = None
if bake_texture and meshes:
try:
from tsr.bake_texture import bake_texture as bake_tex
texture_data = bake_tex(meshes[0], model, scene_codes[0], texture_resolution)
except Exception as e:
print(f'テクスチャベイキングに失敗しました: {e}')
meshes = model.extract_mesh(scene_codes, vertex_colors=True, resolution=mc_resolution)
return meshes[0] if meshes else None, texture_data
except Exception as e:
print(f'TripoSR 3D再構成に失敗しました: {e}')
return None, None
# 簡易3Dプレビュー表示
def preview_3d_mesh(mesh, window_name="3D Preview"):
if mesh is None:
return
print('3Dプレビュー: マウスドラッグで回転、ESCで終了')
# メッシュの頂点を取得
vertices = np.array(mesh.vertices)
faces = np.array(mesh.faces)
# 中心を原点に
center = vertices.mean(axis=0)
vertices = vertices - center
# スケール調整
max_dist = np.max(np.abs(vertices))
vertices = vertices / max_dist * 200
# 回転パラメータ
rot_x, rot_y = 0, 0
mouse_down = False
prev_x, prev_y = 0, 0
def mouse_callback(event, x, y, flags, param):
nonlocal rot_x, rot_y, mouse_down, prev_x, prev_y
if event == cv2.EVENT_LBUTTONDOWN:
mouse_down = True
prev_x, prev_y = x, y
elif event == cv2.EVENT_LBUTTONUP:
mouse_down = False
elif event == cv2.EVENT_MOUSEMOVE and mouse_down:
rot_y += (x - prev_x) * 0.5
rot_x += (y - prev_y) * 0.5
prev_x, prev_y = x, y
cv2.namedWindow(window_name)
cv2.setMouseCallback(window_name, mouse_callback)
while True:
# 画像をクリア
img = np.ones((600, 800, 3), dtype=np.uint8) * 255
# 回転行列
rx = np.radians(rot_x)
ry = np.radians(rot_y)
# Y軸回転
rot_y_mat = np.array([
[np.cos(ry), 0, np.sin(ry)],
[0, 1, 0],
[-np.sin(ry), 0, np.cos(ry)]
])
# X軸回転
rot_x_mat = np.array([
[1, 0, 0],
[0, np.cos(rx), -np.sin(rx)],
[0, np.sin(rx), np.cos(rx)]
])
# 頂点を回転
rotated = vertices @ rot_y_mat @ rot_x_mat
# 投影(簡易的な平行投影)
projected = rotated[:, :2] + [400, 300]
projected = projected.astype(int)
# ワイヤーフレーム描画
for face in faces:
pts = projected[face]
for i in range(3):
cv2.line(img, tuple(pts[i]), tuple(pts[(i+1)%3]), (0, 0, 0), 1)
cv2.putText(img, "Mouse drag to rotate, ESC to exit", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 128, 0), 2)
cv2.imshow(window_name, img)
key = cv2.waitKey(30) & 0xFF
if key == 27: # ESC
break
cv2.destroyWindow(window_name)
# 画像処理メイン関数
def image_processing(img, resolution=256, use_texture=False, texture_resolution=1024):
try:
print('3D再構成処理を開始します...')
# 背景除去
no_bg_img = remove_background_custom(img, rembg_session)
# 前景のリサイズ(TripoSR互換)
if TRIPOSR_AVAILABLE and hasattr(TSR, 'resize_foreground'):
# float32画像をPIL Imageに変換
if no_bg_img.dtype == np.float32:
pil_img = Image.fromarray((no_bg_img * 255).astype(np.uint8))
else:
pil_img = Image.fromarray(no_bg_img)
no_bg_img = resize_foreground(pil_img, 0.85)
no_bg_img = np.array(no_bg_img).astype(np.float32) / 255.0
# 3D再構成
mesh, texture_data = reconstruct_3d_triposr(no_bg_img, resolution, use_texture, texture_resolution)
if mesh is not None:
# メッシュの保存
timestamp = len([f for f in os.listdir('.') if f.startswith('output_3d_model_')]) if os.path.exists('.') else 0
output_filename = f'output_3d_model_{timestamp}.obj'
try:
# テクスチャ付きで保存
if use_texture and texture_data is not None:
output_mtl = f'output_3d_model_{timestamp}.mtl'
output_tex = f'output_3d_model_{timestamp}_texture.png'
# MTLファイルの作成
with open(output_mtl, 'w') as f:
f.write(f'newmtl material_0\n')
f.write(f'Ka 1.0 1.0 1.0\n')
f.write(f'Kd 1.0 1.0 1.0\n')
f.write(f'Ks 0.0 0.0 0.0\n')
f.write(f'map_Kd {os.path.basename(output_tex)}\n')
# テクスチャ画像の保存
if 'texture' in texture_data:
Image.fromarray(texture_data['texture']).save(output_tex)
# UV座標付きでメッシュを保存
if 'mesh' in texture_data:
texture_data['mesh'].export(output_filename)
else:
mesh.export(output_filename)
result_text = f'3Dモデルを生成しました: {output_filename} (テクスチャ付き)'
else:
# 頂点カラーで保存
mesh.export(output_filename)
result_text = f'3Dモデルを生成しました: {output_filename} (頂点カラー)'
result_text += f' (頂点数: {len(mesh.vertices)}, 面数: {len(mesh.faces)})'
print(result_text)
# 結果をファイルに保存
with open('result.txt', 'a', encoding='utf-8') as f:
f.write(result_text + '\n')
# 画像に結果テキストを描画
if no_bg_img.dtype == np.float32:
result_img = (no_bg_img * 255).astype(np.uint8)
else:
result_img = no_bg_img.copy()
# BGRに変換
if len(result_img.shape) == 3 and result_img.shape[2] == 3:
result_img = cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR)
cv2.putText(result_img, f'3D Model: {output_filename}', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.putText(result_img, f'Vertices: {len(mesh.vertices)}', (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.putText(result_img, f'Faces: {len(mesh.faces)}', (10, 90),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
# 最後のメッシュを保存(プレビュー用)
show_processed_image.last_mesh = mesh
return result_img
except Exception as e:
print(f'メッシュの保存に失敗しました: {e}')
if no_bg_img.dtype == np.float32:
return (no_bg_img * 255).astype(np.uint8)
else:
return no_bg_img
else:
if no_bg_img.dtype == np.float32:
return (no_bg_img * 255).astype(np.uint8)
else:
return no_bg_img
except Exception as e:
print(f'画像処理中にエラーが発生しました: {e}')
return img
def show_processed_image(img, window_name, resolution=256, use_texture=False, texture_resolution=1024, preview_3d=False):
if img is None:
print('画像の読み込みに失敗しました')
return
processed_img = image_processing(img, resolution, use_texture, texture_resolution)
cv2.imshow(window_name, processed_img)
cv2.waitKey(0)
# 3Dプレビュー表示
if preview_3d and hasattr(show_processed_image, 'last_mesh'):
preview_3d_mesh(show_processed_image.last_mesh)
# プログラム開始時の説明
print('TripoSR 3D Object Reconstruction')
print('単一画像から3Dモデルを生成します')
print('操作方法:')
print('- カメラモード: スペースキーで撮影、qキーで終了')
print('- 画像表示中: 任意のキーで次へ')
print()
# モデルセットアップ
print('モデルの初期化中...')
setup_triposr_model()
print()
print('0: 画像ファイル')
print('1: カメラ')
print('2: サンプル画像')
choice = input('選択: ')
# メッシュ解像度の選択
print()
print('メッシュ解像度を選択してください:')
print('1: 低解像度 (64) - 高速')
print('2: 中解像度 (128) - バランス')
print('3: 高解像度 (256) - 高品質(デフォルト)')
print('4: 最高解像度 (320) - 最高品質・低速')
res_choice = input('選択 (1-4, デフォルト: 3): ').strip()
resolution_map = {'1': 64, '2': 128, '3': 256, '4': 320}
resolution = resolution_map.get(res_choice, 256)
print(f'選択された解像度: {resolution}')
# テクスチャ生成の選択
print()
print('テクスチャを生成しますか?')
print('1: いいえ(頂点カラーのみ) - 高速')
print('2: はい(テクスチャマップ生成) - 高品質・低速')
tex_choice = input('選択 (1-2, デフォルト: 1): ').strip()
use_texture = (tex_choice == '2')
texture_resolution = 1024
if use_texture:
print('テクスチャ解像度:')
print('1: 512x512')
print('2: 1024x1024(デフォルト)')
print('3: 2048x2048')
tex_res_choice = input('選択 (1-3, デフォルト: 2): ').strip()
tex_res_map = {'1': 512, '2': 1024, '3': 2048}
texture_resolution = tex_res_map.get(tex_res_choice, 1024)
# 3Dプレビューの選択
print()
preview_3d = input('3Dプレビューを表示しますか? (y/N): ').strip().lower() == 'y'
print()
if choice == '0':
root = tk.Tk()
root.withdraw()
paths = filedialog.askopenfilenames(
filetypes=[('Image files', '*.jpg *.jpeg *.png *.bmp *.tiff')]
)
if not paths:
exit()
for path in paths:
img = cv2.imread(path)
if img is not None:
show_processed_image(img, 'Image', resolution, use_texture, texture_resolution, preview_3d)
else:
print(f'画像の読み込みに失敗しました: {path}')
elif choice == '1':
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
if not cap.isOpened():
print('カメラを開けませんでした')
exit()
try:
print('カメラを起動しました。スペースキーで撮影、qキーで終了')
while True:
ret, frame = cap.read()
if not ret:
break
cv2.imshow('Camera', frame)
key = cv2.waitKey(1) & 0xFF
if key == ord(' '):
show_processed_image(frame, 'Image', resolution, use_texture, texture_resolution, preview_3d)
elif key == ord('q'):
break
finally:
cap.release()
elif choice == '2':
urls = [
'https://github.com/opencv/opencv/raw/master/samples/data/fruits.jpg',
'https://github.com/opencv/opencv/raw/master/samples/data/messi5.jpg',
'https://github.com/opencv/opencv/raw/master/samples/data/aero3.jpg'
]
downloaded_files = []
for i, url in enumerate(urls):
filename = f'sample_{i}.jpg'
try:
print(f'サンプル画像をダウンロード中: {url}')
urllib.request.urlretrieve(url, filename)
downloaded_files.append(filename)
img = cv2.imread(filename)
if img is not None:
show_processed_image(img, 'Sample Image', resolution, use_texture, texture_resolution, preview_3d)
else:
print(f'画像の読み込みに失敗しました: {filename}')
except Exception as e:
print(f'画像のダウンロードに失敗しました: {url}')
print(f'エラー: {e}')
continue
# ダウンロードしたファイルを削除
for filename in downloaded_files:
try:
os.remove(filename)
except OSError:
pass
else:
print('無効な選択です')
exit()
cv2.destroyAllWindows()
# 結果ファイルの保存確認
if os.path.exists('result.txt'):
print('result.txtに結果を保存しました')
else:
print('処理結果がありませんでした')