ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English
IIIF絵巻物をAI動画で動かす:Video Annotationという新しいアプローチ

IIIF絵巻物をAI動画で動かす:Video Annotationという新しいアプローチ

はじめに IIIF(International Image Interoperability Framework)は、デジタルアーカイブの画像を相互運用可能な形で公開するための国際標準です。世界中の図書館・博物館が採用しており、高解像度画像の深層ズームや、異なる機関のコレクションを横断的に閲覧することを可能にしています。 本記事では、IIIF画像の一部領域にAI生成動画を重ねて表示する「IIIF Animated Viewer」を開発した過程を紹介します。題材は東京大学が公開する「百鬼夜行図」――妖怪たちの行列を描いた絵巻物です。 静止画の妖怪たちが、ゆらゆらと動き出す。そんな体験を、IIIF標準の枠組みの中で実現しました。 狙い 1. 絵巻物に「動き」を与える 絵巻物は本来、巻きながら読む動的なメディアです。右から左へ進む行列、風にはためく衣、揺れる炎――静止画でありながら動きを内包しています。AI動画生成でその潜在的な動きを顕在化させることで、作品の新しい鑑賞体験を提供できるのではないか、という着想がありました。 2. IIIF標準に準拠する 独自フォーマットではなく、IIIF Presentation API 3.0のマニフェストとして動画情報を記述します。これにより、他のIIIFビューアとの互換性を保ちつつ、既存のIIIFエコシステムに乗る形で動画アノテーションを提供できます。 3. 汎用的なパイプラインにする 百鬼夜行図だけでなく、他のIIIF資料にも適用可能な仕組みを目指しました。マニフェストのメタデータと全体画像からコンテキストを自動生成し、個別領域のプロンプト生成に反映するアーキテクチャにしています。 デモ デモは GitHub Pages で公開しています。 コレクション一覧ページ。IIIFコレクションからマニフェスト一覧を読み込み、サムネイル付きで表示する。 ビューア全体表示。百鬼夜行図の全体像がOpenSeadragonで表示され、下部に再生ボタンがある。 ズームすると個々の妖怪が確認でき、動画オーバーレイが元画像の上に重なって表示される。 システム構成 docs/ … GitHub Pages公開ディレクトリ index.html … コレクション一覧ページ viewer.html … OpenSeadragon + 動画オーバーレイビューア collection.json … IIIF Collection manifest.json … IIIF Manifest(動画アノテーション含む) runs/run_002/ … 生成動画ファイル scripts/ pipeline.py … 一括生成パイプライン process_raw.py … Veo生成動画のトリミング+manifest更新 workspace/ anno.json … 領域アノテーション(19件) context.txt … 自動生成コンテキスト runs/ … 中間データ(クロップ画像、プロンプト等) IIIFマニフェストでの動画アノテーション 従来のIIIFアノテーション IIIF Presentation API 3.0では、Canvasに対するアノテーションとして画像を配置します。 ...

自動遷移機能を持つIIIF画像座標エディタの開発

自動遷移機能を持つIIIF画像座標エディタの開発

概要 今回開発したエディタは、IIIF対応の高解像度画像上で任意の座標を記録・管理するためのWebベースのツールです。URLパラメータで画像を指定でき、様々な研究プロジェクトで利用可能な汎用的な座標記録ツールとして設計されています。 https://youtu.be/UqPo5Xrkin8 主要技術スタック OpenSeadragon : IIIF画像ビューアライブラリ (v4.1) SVGオーバーレイ : マーカー表示用 localStorage : データの永続化 Vanilla JavaScript : フレームワークレス実装 技術的特徴 1. URLパラメータによる画像指定 ツールの最大の特徴は、URLパラメータで任意のIIIF画像を指定できることです: function getImageUrlFromQuery() { const urlParams = new URLSearchParams(window.location.search); const urlParam = urlParams.get('u'); if (urlParam) { try { return decodeURIComponent(urlParam); } catch (e) { console.error('Error decoding URL parameter:', e); alert('URLパラメータのデコードに失敗しました。デフォルト画像を使用します。'); } } // Default image URL return 'https://img.toyobunko-lab.jp/iiif/premodern_chinese/suikeichuzu/Suikeichuuzu_grid_l.tif'; } const imageUrl = getImageUrlFromQuery(); 使用例: intersection_editor.html?u=https%3A%2F%2Fexample.com%2Fiiif%2Fimage.tif URLエンコードされた画像URLを?u=パラメータで渡すだけで、任意の画像を開けます。 2. 画像URLごとのデータ分離 localStorageのキーに画像URLを含めることで、画像ごとに独立したデータを管理: const imageUrl = getImageUrlFromQuery(); const storageKey = `intersection_points_${btoa(imageUrl).substring(0, 50)}`; 画像URLをBase64エンコードしてキーの一部とすることで、複数の画像プロジェクトを同時に管理できます。 3. IIIF画像の自動読み込み 画像URLから自動的にIIIF info.json URLを生成: function getIIIFInfoUrl(imageUrl) { if (imageUrl.endsWith('info.json')) { return imageUrl; } let baseUrl = imageUrl.replace(/\.(jpg|jpeg|png|tif|tiff)$/i, ''); return `${baseUrl}/info.json`; } const viewer = OpenSeadragon({ id: "viewer", tileSources: imageUrl.startsWith('http') ? getIIIFInfoUrl(imageUrl) : imageUrl, showNavigationControl: true, showNavigator: true }); .tifや.jpgなどの拡張子を自動的に処理し、IIIF Image API 2.0に準拠したinfo.jsonをリクエストします。 ...

IIIF画像に対する多角形アノテーション支援ツールの改修

IIIF画像に対する多角形アノテーション支援ツールの改修

概要 IIIF画像に対する多角形アノテーション支援ツール「IIIF Annotator」の改修を行いました。具体的には、以下の2点に取り組みました。 Image Server未使用のマニフェストファイルへの対応 アノテーション付きIIIFマニフェストファイルのエクスポート機能 TEI/XMLファイルのエクスポート機能 以下、これらの改修について説明します。 背景 以下の記事で、アノテーション付与ツールを新規に作成した理由等を説明しました。 今回追加した機能は他のツールでも提供されている機能群になりますが、利便性向上のため追加実装しました。 Image Server未使用のマニフェストファイルへの対応 以下の記事で紹介しているように、IIIFマニフェストファイルにおいて、Image API(Image Server)を使用しないオプションを取ることができます。デメリットもありますが、Cantaloupe Image Serverなどのソフトウェアを導入せずに使用できる点に利点があります。 IIIF Annotatorについて、これまではImage Serverの使用を前提として実装していましたが、今回の改修により、Image Server未使用のマニフェストファイルも読み込めるようにしました。 具体的には以下のように、serviceの有無に応じて、OpenSeadragonに渡すtileSourcesを調整しました。 const tileSources = canvases .map((canvas: Canvas) => { const annotationPage = canvas.items?.[0]; const annotation = annotationPage?.items?.[0]; if (!annotation) return null; const body = annotation.body as { id: string; service?: { "@id": string }[]; }; if (body.service && body.service.length > 0) { return body.service[0]["@id"] + "/info.json"; } else { return { type: "image", url: body.id, }; } }) .filter( (tileSource: string | { type: string; url: string } | null) => tileSource !== null ); エクスポート機能 アノテーション付きIIIFマニフェストファイル、およびTEI/XMLファイルとしてエクスポートする機能を追加しました。エクスポートボタンを押すと、以下のような選択肢が表示されます。 アノテーション付きIIIFマニフェストファイルの用途としては、ダウンロードしたファイルをMirador等に読み込ませることで、アノテーション結果を確認することができます。 またTEI/XMLファイルについては、Oxygen XML Editorの作者モード等を使って、アノテーション結果を確認することができます。 まとめ IIIFのアノテーション結果の活用にあたり、参考になりましたら幸いです。

Mirador 4で、初期読み込み時に、画像の回転や範囲指定を行う

Mirador 4で、初期読み込み時に、画像の回転や範囲指定を行う

概要 Mirador 4で、初期読み込み時に、画像の回転や範囲指定を行う方法を紹介します。 背景 2025年3月現在、Mirador 4の開発が進められています。alpha版を以下で確認することができます。 https://github.com/ProjectMirador/mirador/releases おそらくMirador 4からの機能かと思いますが、以下のFAQで初期設定の方法が記述されています。 https://github.com/ProjectMirador/mirador/wiki/Frequently-Asked-Questions#q-how-do-i-change-the-view-of-an-image-to-zoom-to-a-certain-area 具体的には、以下のように、initialViewerConfigを用いることで、初期設定ができました。 https://github.com/ProjectMirador/mirador/blob/main/__tests__/integration/mirador/mirador-configs/initial-viewer-config.js export default { id: 'mirador', windows: [{ canvasId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174892', initialViewerConfig: { thumbnailNavigationPosition: 'far-bottom', x: 934, y: 782, // you need to specify zoom for this to look good zoom: 0.0007, }, manifestId: 'https://iiif.harvardartmuseums.org/manifests/object/299843', }], }; 応用 上記を応用して、以下のような初期設定を行ってみました。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <title>Mirador - Table of contents</title> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"> </head> <body> <div id="mirador" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0;"></div> <script type="module"> import Mirador from '../../../src'; // import config from './mirador-configs/initial-viewer-config.js'; const xywh = '9554.0,8213.0,1000,1000'; const spl = xywh.split(','); // Box to zoom to const boxToZoom = { height: Number(spl[3]), width: Number(spl[2]), x: Number(spl[0]), y: Number(spl[1]) }; const zoomCenter = { x: boxToZoom.x + boxToZoom.width / 2, y: boxToZoom.y + boxToZoom.height / 2 }; const config = { id: 'mirador', windows: [{ canvasId: "https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/187cc82d-11e6-9912-9dd4-b4cca9b10970/canvas/p2", initialViewerConfig: { rotation: 180, x: zoomCenter.x, y: zoomCenter.y, zoom: 1 / Math.max(boxToZoom.width, boxToZoom.height) }, // manifestId: 'https://purl.stanford.edu/sn904cj3429/iiif/manifest', manifestId: "https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/187cc82d-11e6-9912-9dd4-b4cca9b10970/manifest", }], }; Mirador.viewer(config); </script> </body> </html> これにより、わかりにくいですが、以下のように、180度回転しつつ、xywhにフォーカスした形で初期読み込みできました。 ...

Annotorious OpenSeadragon Pluginを使ったサンプルプログラム

Annotorious OpenSeadragon Pluginを使ったサンプルプログラム

概要 Annotorious OpenSeadragon Pluginを使って、IIIFマニフェストファイルからロードした複数画像に対するアノテーション付与を行うサンプルプログラムを作成しました。以下からお試しいただけます。 https://nakamura196.github.io/nuxt3-demo/annotorious ソースコード 以下を参考にしてください。 https://github.com/nakamura196/nuxt3-demo/blob/main/pages/annotorious/index.vue ポイント npm install –force ライブラリ@recogito/annotorious-openseadragonはopenseadragonのv5に非対応のようで、強制的にインストールする必要がありました。 npm error Could not resolve dependency: npm error peer openseadragon@"^3.0.0 || ^4.0.0" from @recogito/annotorious-openseadragon@2.7.18 npm error node_modules/@recogito/annotorious-openseadragon npm error @recogito/annotorious-openseadragon@"^2.7.18" from the root project plugins プラグインとして、Annotoriousを読み込みました。 https://github.com/nakamura196/nuxt3-demo/blob/main/plugins/osd.client.js ページ切り替え ページを切り替えた際、一旦アノテーションをクリアして、該当ページのアノテーションをロードする必要がありました。 ... // Reactive object to store annotations for each page const annotationsMap = ref<{ [key: number]: Annotation[]; }>({}); ... // Add handler to clear and display annotations on page navigation viewer.addHandler("page", () => { anno.clearAnnotations(); showCurrentCanvasAnnotations(); }); // Function to display annotations for the current canvas const showCurrentCanvasAnnotations = () => { const index = viewer.currentPage(); const annotationsMap_ = annotationsMap.value; if (annotationsMap_[index]) { annotationsMap_[index].forEach((annotation: Annotation) => { anno.addAnnotation(annotation); }); } }; ... まとめ 本プログラムを応用して、他のアプリケーションとの接続も可能かと思います。参考になりましたら幸いです。 ...

Mirador 4の拡大・縮小・回転の挙動を確認する

Mirador 4の拡大・縮小・回転の挙動を確認する

概要 Mirador 4の拡大・縮小・回転の挙動を変更する必要があり、その変更方法に関する備忘録です。 セットアップ 以下により、ローカルでMirador 4を起動します。 git clone https://github.com/projectmirador/mirador cd mirador pnpm i pnpm start ポート4444で起動します。 zoomIn時の処理のカスタマイズ 一例ですが、zoomInボタンをクリックした際の処理を以下のように変更してみます。 ... handleZoomInClick() { const { windowId, updateViewport, viewer } = this.props; updateViewport(windowId, { // zoom: viewer.zoom * 2, zoom: viewer.zoom * 1.1, // 追加 rotation: viewer.rotation + 5, // 追加 x: viewer.x * 1.1, // 追加 y: viewer.y * 1.1, // 追加 }); } ... 結果、zoomInボタンを押した際に、中心が少しずれながら、拡大・回転が行われることがわかります。 https://youtu.be/wn1WxpTVpS4 これを応用することで、Mirador 3の拡大・縮小・回転等のカスタマイズを行うことができます。 immediateの設定 上記の例では、拡大や回転が完了するまで少し時間がかかっていました。これを即座に行いたい場合、以下のOpenSeadragonViewer.jsのcomponentDidUpdateをカスタマイズします。 viewerConfigオブジェクトのimmediatelyプロパティに基づき、拡大縮小や回転を即座に実施するかを設定できるようにします。 ... componentDidUpdate(prevProps, prevState) { const { viewerConfig, canvasWorld, } = this.props; const { viewer } = this.state; this.apiRef.current = viewer; if (prevState.viewer === undefined) { if (viewerConfig) { viewer.viewport.panTo(viewerConfig, true); viewer.viewport.zoomTo(viewerConfig.zoom, viewerConfig, true); viewerConfig.degrees !== undefined && viewer.viewport.setRotation(viewerConfig.degrees); viewerConfig.flip !== undefined && viewer.viewport.setFlip(viewerConfig.flip); } this.addAllImageSources(!(viewerConfig)); return; } if (!this.infoResponsesMatch(prevProps.infoResponses) || !this.nonTiledImagedMatch(prevProps.nonTiledImages) ) { viewer.close(); const canvasesChanged = !(isEqual(canvasWorld.canvasIds, prevProps.canvasWorld.canvasIds)); this.addAllImageSources((canvasesChanged || !viewerConfig)); } else if (!isEqual(canvasWorld.layers, prevProps.canvasWorld.layers)) { this.refreshTileProperties(); } else if (viewerConfig && !this.osdUpdating) { const { viewport } = viewer; const immediately = viewerConfig.immediately || false; if (viewerConfig.x !== viewport.centerSpringX.target.value || viewerConfig.y !== viewport.centerSpringY.target.value) { viewport.panTo(viewerConfig, immediately); } if (viewerConfig.zoom !== viewport.zoomSpring.target.value) { viewport.zoomTo(viewerConfig.zoom, viewerConfig, immediately); } if (viewerConfig.rotation !== viewport.getRotation()) { viewport.setRotation(viewerConfig.rotation, immediately); } if (viewerConfig.flip !== viewport.getFlip()) { viewport.setFlip(viewerConfig.flip); } } } ... そして、先のZoomControls.jsにおいて、immediately: trueを追加します。 ...

OpenSeadragonでビューポートが設定した制約を満たすようにzoomToを行う

OpenSeadragonでビューポートが設定した制約を満たすようにzoomToを行う

OpenSeadragonのzoomToメソッドを使用した後に、viewport.applyConstraints()を呼び出すことで、ビューポートが設定した制約を満たすように調整されます。これは、ズームやパンの操作がビューポートの制約を超えた場合に有用です。 以下にその例を示します: // `viewer`はOpenSeadragonのインスタンス const zoomLevel = 2.0; viewer.viewport.zoomTo(zoomLevel); viewer.viewport.applyConstraints(); 上記のコードでは、まずビューポートのズームレベルを指定した値に設定します。その後、applyConstraintsメソッドを呼び出すことでビューポートがその制約を満たすように調整されます。つまり、もし指定したズームレベルが設定された制約を超えていた場合、ズームレベルはその制約に合うように調整されます。 この方法は、指定したズームレベルや位置が制約を超えていた場合でも、ビューポートが常に有効な状態を維持できるようにするために有用です。

OpenSeadragon(OSD)の`fitBounds`と`fitBoundsWithConstraints`の違い

OpenSeadragon(OSD)の`fitBounds`と`fitBoundsWithConstraints`の違い

(以下、ChatGPTによる回答です。参考になりましたら幸いです。) OpenSeadragon(OSD)のfitBoundsとfitBoundsWithConstraintsの違いは、制約を適用するかどうかにあります。 OSDは高度なズーム機能とパニング機能を持つJavaScriptライブラリで、深くズーム可能な画像やコンテンツを扱う際に使われます。その中のfitBoundsとfitBoundsWithConstraintsは、ビューポート(表示領域)を特定の境界に合わせるメソッドです。 fitBounds(rectangle, immediately): ビューポートを指定した矩形に合わせます。immediatelyパラメータがtrueの場合、アニメーションなしで即座にビューポートをフィットさせます。falseの場合、アニメーションを伴ってビューポートをフィットさせます。 fitBoundsWithConstraints(rectangle, immediately): fitBoundsと同じ動作をしますが、ビューポートのズームとパンの制約を考慮します。つまり、指定した矩形にフィットさせる前に、最小ズームレベル、最大ズームレベル、画像のパン制約などを確認します。これにより、ユーザーが画像をズームやパンしても、設定した制約を超えることがありません。 つまり、主な違いはfitBoundsWithConstraintsがビューポートの制約を適用することで、その制約を超える動作を防ぎます。これは特に、ユーザーが画像をズームイン/ズームアウトしたり、画像をパン(スクロール)する際の振る舞いを制御するのに重要です。

Nuxt3でOpenSeadragonとOpenSeadragon SVG Overlayを使う

Nuxt3でOpenSeadragonとOpenSeadragon SVG Overlayを使う

概要 Nuxt3でOpenSeadragonとOpenSeadragon SVG Overlayを使う例を作成しました。(鯰に御札を貼る要石)「国立国会図書館 所蔵」の画像を利用しています。 OpenSeadragon https://nuxt3-demo-nine.vercel.app/osd OpenSeadragon SVG Overlay https://nuxt3-demo-nine.vercel.app/osd-svg 方法 ポイントとして、以下のようなプラグインファイルを用意しました。これにより、SSR時に生じる不具合を解消できました。 https://github.com/nakamura196/nuxt3-demo/blob/main/plugins/osd.client.js またsvg overlayに関する記述は以下を参考にしました。 https://github.com/openseadragon/svg-overlay/blob/master/openseadragon-svg-overlay.js まとめ よりよい記述の方法があるかと思いますが、Nuxt3でのOpenSeadragonの利用にあたり、参考になりましたら幸いです。

TEIビューアでの利用を想定したCustom OpenSegDragon Viewerを作成しました。

TEIビューアでの利用を想定したCustom OpenSegDragon Viewerを作成しました。

概要 TEIビューアでの利用を想定したCustom OpenSegDragon Viewerを作成しました。 背景 以下のようなTEIとIIIFを対応させたビューア開発において、次に示す機能を持ったビューアが必要でした。 https://www.hi.u-tokyo.ac.jp/collection/digitalgallery/wakozukan/tei/ IIIFのマニフェストファイルを読み込むことができる。 ビューアコンポーネント側でのコマ送りを、コンポーネント外で把握することができる。 画像の部分領域をハイライトすることができる。 上記の要件を全てを満たす既存のIIIF対応ビューアを見つけることができなかったため、独自のビューアの開発を試みました。合わせて、npmパッケージとして公開することも試みました。 開発したビューア ドキュメンテーション等がまだ不十分ですが、以下のページで公開しています。このページで、ソースコードへのリンクも掲載しています。 https://www.npmjs.com/package/@nakamura196/osd-custom-viewer vue3とviteを使ったコンポーネントの開発およびnpmでの公開にあたっては、以下のサイトを参考にしました。 https://blog.egmond.dev/vue-component-to-npm-package 使用例 以下のページで導入例をご確認いただけます。 https://nakamura196.github.io/nuxt3-iiif-viewer/custom-osd コンポーネント内外からのコマ送りが可能です。これにより、例えばIIIF画像とTEIテキストの並列表示を行った際、TEIテキスト側からのコマ送りや、画像のコマ送りによる当該テキストへのスクロールなどを行うことができます。 またハイライト機能用いることで、あるテキスト行に対応した画像の部分領域をハイライトさせる、といったことが可能です。 使用例のソースコードは以下です。 https://github.com/nakamura196/nuxt3-iiif-viewer/blob/main/pages/custom-osd/index.vue ssrでの公開にあたり、pluginsフォルダに以下を追加しています。 https://github.com/nakamura196/nuxt3-iiif-viewer/blob/main/plugins/custom-osd.client.js まとめ ドキュメンテーションの充実や、IIIF v3への対応など、多くのTODOが残っていますが、参考になりましたら幸いです。

Vue3でOpenSeadragonを使用するサンプルリポジトリを作成しました。

Vue3でOpenSeadragonを使用するサンプルリポジトリを作成しました。

Vue3でOpenSeadragonを使用するサンプルリポジトリを作成しました。 以下が動作例です。 https://static.ldas.jp/vue3-osd/ ソースコードは以下です。 https://github.com/ldasjp8/vue3-osd Vue3初学者のため、誤りなどがあるかもしれませんが、参考になりましたら幸いです。