はじめに
Webサイト上で高解像度画像をスムーズにズーム表示するために使用されるDeep Zoom技術。Microsoft Deep Zoom Composerなどで生成されたタイル化された画像データから、元の高解像度画像を復元する必要に迫られることがあります。
本記事では、Deep Zoom形式で公開されている画像データから、元の高解像度TIFF画像を復元する技術について解説します。
Deep Zoom画像の仕組み
タイル構造
Deep Zoom画像は、1枚の大きな画像を複数の小さなタイル画像に分割し、ピラミッド構造で保存します:
- レベル0 : 最も低解像度(通常1タイル)
- レベルN : 最高解像度(元画像の解像度に相当)
- 各レベルで解像度が2倍になる
ファイル構成
dzc_output.xml # メタデータ
dzc_output_files/
├── 0/
│ └── 0_0.jpg # レベル0の唯一のタイル
├── 1/
│ ├── 0_0.jpg
│ └── ...
└── 16/ # 最高レベル
├── 0_0.jpg
├── 0_1.jpg
└── ... # 数万枚のタイル
実装の課題と解決策
課題1: XMLメタデータの名前空間の違い
Deep Zoomには複数のバージョンがあり、XMLの名前空間が異なります:
http://schemas.microsoft.com/deepzoom/2008http://schemas.microsoft.com/deepzoom/2009
解決策 : 複数の名前空間に対応した柔軟なXMLパーサーを実装
def fetch_xml_info(xml_url):
root = ET.fromstring(response.content)
# 複数の名前空間を試行
namespaces = [
'{http://schemas.microsoft.com/deepzoom/2008}Size',
'{http://schemas.microsoft.com/deepzoom/2009}Size',
'Size'
]
for ns in namespaces:
image_elem = root.find('.//' + ns)
if image_elem is not None:
break
width = int(image_elem.attrib['Width'])
height = int(image_elem.attrib['Height'])
return config
課題2: 最大レベルの自動検出
XMLに記載された最大レベルと、実際にサーバー上に存在するレベルが異なる場合があります。
解決策 : 実際にHEADリクエストを送信して存在確認
def find_actual_max_level(base_url, format_ext):
"""実際に存在する最大レベルを検出"""
for level in range(20, -1, -1):
url = f"{base_url}{level}/0_0.{format_ext}"
try:
response = requests.head(url, timeout=10)
if response.status_code == 200:
return level
except:
continue
return None
課題3: 大量タイルの効率的ダウンロード
高解像度画像では、数万枚のタイルをダウンロードする必要があります(例: 29,146タイル)。
解決策 : ThreadPoolExecutorによる並列ダウンロード
def download_tiles(tiles_list, base_url, level, format_ext):
session = requests.Session()
downloaded_tiles = []
with ThreadPoolExecutor(max_workers=10) as executor:
futures = {
executor.submit(download_tile, base_url, level,
col, row, format_ext, session): (col, row)
for col, row in tiles_list
}
with tqdm(total=len(futures)) as pbar:
for future in as_completed(futures):
result = future.result()
if result:
downloaded_tiles.append(result)
pbar.update(1)
return downloaded_tiles
課題4: タイルオーバーラップの処理
Deep Zoomのタイルには、シームレスな表示のためのオーバーラップ(重複領域)があります。
解決策 : オーバーラップを考慮した座標計算
def reconstruct_image(tiles, tile_size, overlap):
for col, row, tile_img in tiles:
# オーバーラップを考慮した配置座標
x = col * (tile_size - overlap)
y = row * (tile_size - overlap)
canvas.paste(tile_img, (x, y))
課題5: 大容量画像の保存
復元した画像は数GB規模になることがあり、標準TIFFの4GB制限を超える場合があります。
解決策 : BigTIFF形式での保存
def save_bigtiff(image, output_path):
# まずPNGで保存(ファイルサイズ制限なし)
png_file = output_path.replace('.tif', '.png')
image.save(png_file, format='PNG', compress_level=6)
# tifffileライブラリでBigTIFFに変換
import tifffile
img_array = np.array(image)
tifffile.imwrite(
output_path,
img_array,
bigtiff=True, # BigTIFF有効化
compression='deflate', # 圧縮
tile=(256, 256) # タイル化
)
実装結果
処理性能
| 画像サイズ | タイル数 | ダウンロード時間 | 最終ファイルサイズ |
|---|---|---|---|
| 62533 x 29734 | 28,899 | 約12分 | 3.7GB (TIFF) |
| 62588 x 29800 | 29,146 | 約12分 | 3.4GB (TIFF) |
| 7760 x 10328 | 1,271 | 約2分 | 72MB (TIFF) |
並列処理の効果
- 並列度: 10スレッド
- 平均ダウンロード速度: 約40タイル/秒
- ネットワーク帯域幅の効率的な利用
技術スタック
# 主要ライブラリ
import requests # HTTP通信
from PIL import Image # 画像処理
import numpy as np # 配列操作
import tifffile # BigTIFF対応
from concurrent.futures import ThreadPoolExecutor
from tqdm import tqdm # プログレスバー
コード構成
download_deepzoom.py # 単一画像処理
batch_download_deepzoom.py # バッチ処理
├─ fetch_xml_info() # XML解析
├─ find_actual_max_level() # レベル自動検出
├─ download_tile() # タイルダウンロード
├─ reconstruct_image() # 画像復元
└─ save_bigtiff() # BigTIFF保存
最適化のポイント
1. セッションの再利用
session = requests.Session()
# 同一セッションでHTTP接続を再利用
response = session.get(url)
2. エラーハンドリング
try:
response = session.get(url, timeout=30)
if response.status_code == 200:
return Image.open(BytesIO(response.content))
except Exception as e:
print(f"Failed to download tile: {e}")
return None
3. メモリ効率
- タイルごとに処理し、メモリ使用量を抑制
- 大きなキャンバスを一度だけ作成
応用例
デジタルアーカイブ
- 古文書・美術品の高解像度画像保存
- 地図データの完全復元
- 文化財のデジタル保存
データ移行
- プラットフォーム移行時の画像データ変換
- バックアップ目的での完全画像取得
- オフライン環境での画像利用
まとめ
Deep Zoom画像の復元には以下の技術的課題がありましたが、適切な対処により完全な復元が可能になりました:
- ✓ XMLの名前空間の違いへの対応
- ✓ 実際の最大レベルの自動検出
- ✓ 大量タイルの並列ダウンロード
- ✓ オーバーラップを考慮した画像復元
- ✓ BigTIFF形式での大容量画像保存
本手法により、6万×3万ピクセル級の超高解像度画像を、約12分で完全復元することができました。
参考資料
- Microsoft Deep Zoom Specification
- PIL/Pillow Documentation
- tifffile Library Documentation
- Python concurrent.futures
注意事項 : 本記事の技術は、適切な権限を持つ画像データに対してのみ使用してください。著作権やライセンスを遵守した利用を心がけましょう。