ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English

最新の記事

3D Gaussian Splatting Viewer の開発 - Spark.jsを使ったブラウザ実装

3D Gaussian Splatting Viewer の開発 - Spark.jsを使ったブラウザ実装

3D Gaussian Splatting(3DGS)ファイルをブラウザで閲覧できるビューアを開発しました。本記事では、3DGSの概要と、通常のPLY Viewerでは表示できない理由、そして専用ビューアの実装について解説します。 デモ: https://3dtiles-viewer.vercel.app/3dgs-viewer.html?manifest=https://3dtiles-viewer.vercel.app/iiif/ply/manifest.json なぜ通常のPLY Viewerでは3DGSを表示できないのか 3DGSファイルは拡張子が.plyであるため、一見すると通常のPLYファイルと同じように扱えそうに見えます。しかし、Three.jsのPLYLoaderで読み込んでも正しく表示されません。 通常のPLYファイルと3DGS PLYファイルの違い 通常のPLY(メッシュ/点群): element vertex 1000 property float x property float y property float z property uchar red property uchar green property uchar blue element face 500 property list uchar int vertex_indices 3DGS用PLY: element vertex 142000 property float x property float y property float z property float f_dc_0 # 球面調和関数(色) property float f_dc_1 property float f_dc_2 property float opacity # 不透明度 property float scale_0 # スケール(楕円体サイズ) property float scale_1 property float scale_2 property float rot_0 # 回転(クォータニオン) property float rot_1 property float rot_2 property float rot_3 PLYLoaderで読み込むとどうなるか Three.jsのPLYLoaderは3DGS用のプロパティを理解できません。読み込むと以下のような問題が発生します: ...

3D点群データの世界:PLY、ガウシアンスプラッティング、Potreeの関係を整理する

3D点群データの世界:PLY、ガウシアンスプラッティング、Potreeの関係を整理する

! 本記事はAI(Claude)との対話をもとに構成・執筆しています。内容の正確性には注意を払っていますが、誤りや不正確な記述が含まれている可能性があります。お気づきの点があれば、コメントでご指摘いただけると助かります。 3D点群データを扱う場面が増えています。文化財のデジタルアーカイブ、都市の3Dスキャン、自動運転のためのLiDAR計測など、応用分野は広がる一方です。しかし、PLY、LAS、ガウシアンスプラッティング、Potreeといった関連する用語が多く、それぞれの位置づけや関係性が掴みにくいと感じる方も多いのではないでしょうか。 本記事では、これらの技術やフォーマットがどのようにつながっているのかを整理してみます。 点群(Point Cloud)とは 点群とは、3D空間中の点の集合によって物体や空間の形状を表現するデータ形式です。各点は最低限の位置情報(x, y, z)を持ち、それに加えて色(r, g, b)、法線ベクトル、反射強度などの属性を付与できます。 点群の取得方法は主に以下のようなものがあります。 LiDAR(Light Detection and Ranging) :レーザー光を照射し、反射光の往復時間から距離を計測します。航空測量、自動運転、地形調査などで広く利用され、1回のスキャンで数億〜数十億点のデータが得られることもあります。 SfM(Structure from Motion) :複数の写真から3D構造を復元する手法です。カメラ位置の推定と三角測量を組み合わせて密な点群を生成します。比較的安価な機材で実施でき、文化財のデジタル記録などで活用が広がっています。 3Dスキャナ :構造光やレーザーを用いて対象物の表面形状を直接計測します。建築物の現況調査や製造業での品質管理に用いられます。 取得方法によって点群の密度、精度、付随する属性が異なり、それが後段のファイル形式選択にも影響します。 PLY(Polygon File Format) 汎用的な3Dデータの器 PLYはスタンフォード大学で3Dスキャンデータの保存用に開発されたフォーマットです。正式名称は「Polygon File Format」で、もともとはポリゴン(メッシュ)データの保存を主な目的としていました。 PLYの最大の特徴は汎用性 にあります。ヘッダ部に属性の定義を記述し、データ部に頂点ごとの値を格納するシンプルな構造で、ASCII形式とバイナリ形式の両方をサポートしています。そして重要なのは、PLYは点群専用の形式ではない ということです。同じ .ply という拡張子であっても、中身はまったく異なるデータを格納できます。 PLYが格納できる3種類のデータ PLYファイルは、ヘッダの内容によって大きく3種類のデータを表現します。 ① メッシュ(Mesh) 頂点(vertex)に加えて面(face)の情報を持ちます。面は通常、三角形の頂点インデックスのリストとして記述されます。3Dスキャナの出力やCGモデルの保存に用いられます。 ply format ascii 1.0 element vertex 678866 property float x property float y property float z element face 1357728 ← faceがある → メッシュ property list uchar int vertex_indices end_header このようなファイルは135万以上の三角形で構成されたメッシュデータであり、ビューアで開くと滑らかな表面として描画されます。 ...

KAKEN OpenSearch API の使い方

KAKEN OpenSearch API の使い方

科研費データベース(KAKEN)の情報をプログラムから取得する方法を解説します。 1. はじめに KAKENは、国立情報学研究所(NII)が提供する科学研究費助成事業データベースです。OpenSearch APIを利用することで、研究課題の情報をプログラムから取得できます。 2. 事前準備:アプリケーションIDの取得 KAKEN APIを利用するには、CiNiiでアプリケーションIDを取得する必要があります。 CiNii API利用登録にアクセス 必要事項を入力して登録申請 承認後、メールでApplication ID(appid)が届く 注意 : 登録から承認まで時間がかかる場合があります。 3. APIエンドポイント 研究課題をさがす https://kaken.nii.ac.jp/opensearch/ 研究者をさがす https://nrid.nii.ac.jp/opensearch/ 4. 主要パラメータ(研究課題をさがす) パラメータ 説明 必須 例 appid アプリケーションID ○ 82RKpPlZiIjbqKwFDO3D qb 研究課題番号で検索 △ 19K20626 kw フリーワード検索 △ IIIF qa 研究課題名で検索 △ デジタルアーカイブ qg 研究者の姓名で検索 △ 中村覚 qm 研究者番号で検索 △ 80802743 format レスポンス形式 - xml(デフォルト: html5) rw 1ページの件数 - 20, 50, 100, 200, 500 lang 言語 - ja, en △: いずれか1つ以上が必要 ...

Three.js + React Three Fiber で GLTF モデルのテクスチャが荒く表示される問題と解決策

Three.js + React Three Fiber で GLTF モデルのテクスチャが荒く表示される問題と解決策

概要 React Three Fiber を使用して GLTF モデルを表示した際、テクスチャがぼやけて見える、または荒く表示される問題に遭遇しました。本記事では、その原因と解決策を解説します。 症状 GLTF モデルのテクスチャがぼやけて表示される 他の 3D ビューアでは正常に表示される同じモデルが、自作のビューアでは荒く見える dpr(デバイスピクセル比)や antialias を設定しても改善しない 原因 Three.js r152 以降、デフォルトの出力カラースペースが変更されました。 GLTF モデルのテクスチャは通常 sRGB 色空間 で保存されています。しかし、Three.js のデフォルト設定では出力が Linear 色空間 になっているため、以下の問題が発生します: テクスチャの補間処理が Linear 空間で行われる ミップマップの生成が正しい色空間で行われない 結果として、テクスチャがぼやけたり、色がおかしくなる 解決策 Canvas の onCreated コールバックで outputColorSpace を設定します。 Before(問題のあるコード) import { Canvas } from '@react-three/fiber'; <Canvas camera={{ position: [5, 5, 5], fov: 50 }} dpr={[1, 2]} gl={{ antialias: true }} > <Scene /> </Canvas> After(修正後のコード) import { Canvas } from '@react-three/fiber'; import * as THREE from 'three'; <Canvas camera={{ position: [5, 5, 5], fov: 50 }} dpr={Math.min(window.devicePixelRatio, 2)} gl={{ antialias: true, preserveDrawingBuffer: true, powerPreference: 'high-performance', toneMapping: THREE.ACESFilmicToneMapping, toneMappingExposure: 1, }} onCreated={({ gl }) => { gl.outputColorSpace = THREE.SRGBColorSpace; }} > <Scene /> </Canvas> 各設定の説明 outputColorSpace: THREE.SRGBColorSpace 最も重要な設定 。出力カラースペースを sRGB に設定することで、テクスチャが正しく表示されます。 ...

Nuxt Content + trailingSlash設定で静的ファイルへのリンクが404になる問題と解決策

Nuxt Content + trailingSlash設定で静的ファイルへのリンクが404になる問題と解決策

概要 Nuxt 3/4 + Nuxt Content の環境で trailingSlash: "append" を設定している場合、コンテンツ内のPDFや画像などの静的ファイルへのリンクが404エラーになることがあります。 発生条件 以下の条件がすべて揃った場合に発生します: Nuxt 3/4 + Nuxt Content を使用 nuxt.config.ts で trailingSlash: "append" を設定 Markdownやコンテンツ内に静的ファイル(PDF、画像など)へのリンクがある 問題の詳細 症状 コンテンツ内で以下のようなリンクを記述した場合: <a href="/uploads/document.pdf">資料をダウンロード</a> 生成されるHTMLでは、リンクが以下のように変換されてしまいます: /uploads/document.pdf/ 末尾に / が追加されるため、静的ファイルにアクセスできず404エラーになります。 原因 Nuxt Content では、Markdown内の <a> タグは ProseA コンポーネントに変換されます。 デフォルトの ProseA コンポーネント(@nuxtjs/mdc パッケージ内)は以下のような実装になっています: <template> <NuxtLink :href="props.href" :target="props.target"> <slot /> </NuxtLink> </template> NuxtLink を使用しているため、nuxt.config.ts の trailingSlash 設定の影響を受けます。 // nuxt.config.ts export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { trailingSlash: "append", // この設定が原因 }, }, }, }); 解決策 カスタムの ProseA コンポーネントを作成し、静的ファイルへのリンクの場合は通常の <a> タグを使用するようにします。 ...

IIIF Georeference ViewerへのLinked Places Format対応

IIIF Georeference ViewerへのLinked Places Format対応

概要 IIIF Georeference Viewerにおいて、地理空間データの相互運用性を向上させるため、Linked Places Format (LPF) に準拠したデータ構造をサポートしました。本記事では、LPFの概要と実装の詳細について説明します。 Linked Places Format (LPF) とは Linked Places Format は、Pelagios Network が策定した地名辞典データの相互運用フォーマットです。GeoJSONを拡張し、Linked Data (JSON-LD) の概念を取り入れることで、異なるデータセット間での場所情報の共有・連携を可能にします。 LPFの特徴 JSON-LD互換 : @id や @context を使用したセマンティックWeb対応 GeoJSON拡張 : 標準的なGeoJSON構造を維持しつつ、メタデータを追加 リンク機能 : 外部データセットへの参照を links 配列で表現 時間情報 : when プロパティによる時間的な情報の記述 公式仕様 GitHub: https://github.com/LinkedPasts/linked-places-format JSON-LD Context: https://raw.githubusercontent.com/LinkedPasts/linked-places/master/linkedplaces-context-v1.1.jsonld 従来のフォーマットとの比較 従来のフォーマット(metadata オブジェクト) { "type": "Feature", "properties": { "resourceCoords": [6690, 7517] }, "geometry": { "type": "Point", "coordinates": [139.7623182, 35.7151233] }, "metadata": { "id": "http://example.org/place/123", "label": "電気実験室", "tags": ["工学部"], "url": "https://maps.app.goo.gl/dJdXXQEA8dWSptgt8", "xywh": "5936,6344,976,1384" } } 従来のフォーマットでは、metadata オブジェクト内に全てのメタデータを格納していました。これはシンプルですが、以下の課題がありました: 標準的なフォーマットではないため、他のツールとの相互運用性が低い Linked Dataとしての活用が困難 外部リソースへのリンクの種類(同一、類似など)を表現できない 新しい推奨フォーマット(LPF準拠) { "type": "Feature", "@id": "https://example.org/places/denki-jikkenshitsu", "properties": { "resourceCoords": [6690, 7517], "title": "電気実験室", "tags": ["工学部"], "xywh": "5936,6344,976,1384" }, "links": [ { "type": "primaryTopicOf", "identifier": "https://maps.app.goo.gl/dJdXXQEA8dWSptgt8" }, { "type": "closeMatch", "identifier": "http://www.wikidata.org/entity/Q123456" } ], "geometry": { "type": "Point", "coordinates": [139.7623182, 35.7151233] } } フォーマット設計の詳細 @id の配置場所 GeoJSON標準 (RFC 7946) とLinked Places Formatでは、識別子の配置場所が異なります: ...

Mirador 4用回転プラグインの開発とnpm公開

Mirador 4用回転プラグインの開発とnpm公開

はじめに IIIFビューアであるMiradorの最新版(Mirador 4)に対応した回転プラグイン「mirador-rotation」を開発し、npmで公開しました。本記事では、プラグインの開発から公開、そして実際に利用するための統合方法について解説します。 背景 Mirador 3からMirador 4へのメジャーアップデートに伴い、以下の変更がありました: React 16 → React 18 Material-UI v4 → MUI v7 その他多数の依存関係の更新 これにより、既存のMirador 3用プラグインはそのままでは動作しなくなりました。 mirador-rotation-pluginの開発 リポジトリ https://github.com/nakamura196/mirador-rotation-plugin 主な機能 画像の回転機能 Mirador 4のプラグインメニューへの統合 npmへの公開 開発したプラグインはnpmで公開しています: npm install mirador-rotation mirador-integrationの更新 公式のmirador-integrationリポジトリを参考に、Mirador 4対応の統合環境を構築しました。 主な変更点 項目 旧 新 Mirador 3.x 4.0.0 React 16.14.0 18.x ビルドツール Webpack Parcel UI Material-UI v4 MUI v7 package.json 最小限の依存関係で構成しています: { "dependencies": { "mirador": "^4.0.0", "mirador-rotation": "^4.0.0", "parcel": "^2.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" } } 外部から利用するための工夫 問題 公式のmirador-integrationをそのままビルドすると、ESモジュール形式で出力されます。しかし、別のHTMLページから<script>タグで読み込んで使いたい場合、グローバル変数としてMiradorが定義されないという問題がありました。 script src="mirador.js">script> script> Mirador.viewer({...}); // Mirador is not defined script> 解決策 1. ライブラリ用エントリーポイントの作成 index.jsでグローバル変数として明示的にエクスポートします: ...

静的サイトでIIIF Content Search APIを実現する - Service Workerによるクライアントサイド検索

静的サイトでIIIF Content Search APIを実現する - Service Workerによるクライアントサイド検索

はじめに IIIF (International Image Interoperability Framework) は、デジタルアーカイブや美術館のコレクションで広く使われている画像配信の国際規格です。IIIF Content Search API を使うと、マニフェスト内のアノテーション(注釈やタグ)を検索できます。 しかし、IIIF Content Search API は通常、サーバーサイドでの実装が前提となっており、静的サイト(GitHub Pages、Vercel、Netlify など)では実現が難しいとされてきました。 本記事では、Service Worker を使ってクライアントサイドで IIIF Content Search API を実装する方法 を紹介します。この手法により、静的サイトでも Mirador などの IIIF ビューアで検索機能を利用できるようになります。 課題 従来のIIIF Search APIの仕組み [Mirador] → GET /search?q=keyword → [サーバー] → 検索処理 → JSON応答 IIIF Content Search API は、クエリパラメータ(?q=検索語)を受け取り、検索結果を JSON で返すエンドポイントを必要とします。これは動的なサーバー処理を前提としています。 静的サイトの制約 静的サイトでは: クエリパラメータに応じた動的なレスポンスを返せない サーバーサイドの検索処理を実行できない 静的 JSON ファイルしか配信できない 解決策:Service Worker によるリクエストインターセプト Service Worker は、ブラウザとネットワークの間に位置するプロキシとして機能します。これを活用して、検索リクエストをインターセプトし、クライアントサイドで検索処理を行います。 アーキテクチャ [Mirador] │ │ GET /iiif/site/search/index.json?q=keyword ↓ [Service Worker] ← インターセプト │ ├─ 静的な index.json を fetch(初回のみ) │ ├─ JavaScript で検索を実行 │ └─ IIIF Content Search API 形式で応答 ↓ [Mirador] ← 検索結果を表示 実装 1. 検索インデックスの生成(ビルド時) まず、アノテーションデータから検索インデックスを生成します。 ...

JavaScriptの演算子優先順位の罠 - Vercelビルドエラーの原因を探る

JavaScriptの演算子優先順位の罠 - Vercelビルドエラーの原因を探る

はじめに Next.jsアプリケーションをVercelにデプロイしようとしたところ、ローカルでは成功するのにVercelでは失敗するという問題に遭遇しました。エラーメッセージは曖昧で、原因の特定に苦労しました。 この記事では、問題の発見から解決までの過程を共有し、JavaScriptの演算子優先順位について学んだことをまとめます。 問題の症状 エラーメッセージ Error occurred prerendering page "/en/smells/22-03" [Error: An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details.] 特徴的な現象 ローカルビルドは成功 するが、Vercelでは失敗 毎回異なるページ でエラーが発生(22-03、24-03、25-04など) エラーの詳細が本番ビルドでは隠される 原因の発見 複数のファイルを調査する中で、以下のコードパターンを発見しました: const origin = process.env.NEXT_PUBLIC_SITE_URL || '' + process.env.NEXT_PUBLIC_BASE_PATH || ''; 一見問題なさそうに見えますが、ここに演算子優先順位の罠 が潜んでいました。 演算子優先順位とは JavaScriptでは、演算子には優先順位があります。数学で「掛け算は足し算より先に計算する」のと同じです。 優先順位の例 // 数学と同じ 2 + 3 * 4 // → 2 + 12 → 14(3 * 4 が先) // 文字列連結 (+) と論理和 (||) の場合 // + の優先順位: 13 // || の優先順位: 5 // → + が先に評価される! 問題のコードを分解 const origin = process.env.NEXT_PUBLIC_SITE_URL || '' + process.env.NEXT_PUBLIC_BASE_PATH || ''; このコードは以下のように解釈されます: ...

Sketchfab APIでGLBファイルをダウンロード・表示するWebアプリを作る

Sketchfab APIでGLBファイルをダウンロード・表示するWebアプリを作る

Sketchfab APIを使って3DモデルをGLBファイルとしてダウンロードし、ブラウザ上でThree.jsで表示するWebアプリを作成しました。本記事では、セキュリティを考慮したアーキテクチャ設計から実装まで解説します。 やりたかったこと Sketchfab上の3DモデルをGLB形式でダウンロードしたい ダウンロードしたGLBをブラウザ上で3D表示したい APIトークンを安全に管理したい 技術スタック Next.js 16(App Router) React Three Fiber / @react-three/drei TypeScript 最初に試したこと:クライアントサイドのみで実装 最初はシンプルにHTML + JavaScriptだけで実装しようとしました。 // Sketchfab APIからダウンロードURLを取得 const response = await fetch( `https://api.sketchfab.com/v3/models/${modelUid}/download`, { headers: { 'Authorization': `Token ${apiToken}` } } ); const data = await response.json(); console.log(data.glb.url); // 署名付きS3 URL これ自体は動作しましたが、2つの問題がありました。 問題1: APIトークンの露出 クライアントサイドでAPIトークンを使用すると、ブラウザの開発者ツールから簡単に確認できてしまいます。APIトークンが漏洩すると、他人があなたのアカウントでAPIを利用できてしまうため、これは避けるべきです。 問題2: CORSエラー(場合による) ブラウザのセキュリティ制限により、異なるオリジンへのリクエストが制限されることがあります。今回のケースでは、Sketchfab APIへのリクエスト自体はCORSが許可されていましたが、環境によっては問題になる可能性があります。 解決策:サーバーサイドAPIを経由する設計 Next.jsのAPI Routesを使って、サーバーサイドでSketchfab APIと通信する設計にしました。 ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ │ │ Client │────▶│ Next.js API │────▶│ Sketchfab API │ │ (Browser) │ │ (Server) │ │ │ │ │◀────│ │◀────│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ ┌─────────────────┐ │ │ │ └──────────▶│ S3 (GLB) │ │ 署名付きURL │ └─────────────────┘ ポイント:署名付きURLの活用 Sketchfab APIは、GLBファイルの実体ではなく「署名付きS3 URL」を返します。 ...

ODD編集Tips:その1

ODD編集Tips:その1

要素の属性を特定のものだけに制限する TEIのデフォルトでは、要素は多くの属性クラス(att.global、att.datableなど)を継承しており、多数の属性が使用可能です。特定の属性のみを許可したい場合は、以下のように設定します。 例: persNameでxml:idとcorrespのみを許可 <elementSpec ident="persName" mode="change"> <classes mode="change"> <!-- 属性クラスを削除(モデルクラスは維持) --> <memberOf key="att.global" mode="delete"/> <memberOf key="att.cmc" mode="delete"/> <memberOf key="att.datable" mode="delete"/> <memberOf key="att.editLike" mode="delete"/> <memberOf key="att.personal" mode="delete"/> <memberOf key="att.typed" mode="delete"/> </classes> <attList> <attDef ident="xml:id" mode="add" usage="opt"> <desc>要素の一意な識別子</desc> <datatype> <dataRef name="ID"/> </datatype> </attDef> <attDef ident="corresp" mode="add" usage="opt"> <desc>関連する人物情報へのリンク</desc> <datatype> <dataRef key="teidata.pointer"/> </datatype> </attDef> </attList> </elementSpec> ポイント <classes mode="change">を使用: mode="replace"で空にすると、モデルクラスも削除され要素自体が使えなくなる 属性クラスを個別に削除 : <memberOf key="att.xxx" mode="delete"/>で不要な属性クラスを削除 必要な属性を追加 : <attDef ident="xxx" mode="add">で許可したい属性を定義 注意点 要素がどの属性クラスに属しているかは、TEI Guidelinesで確認できる att.globalを削除するとxml:id、xml:langなども使えなくなるため、必要に応じて個別に追加する 要素に属性を追加する 既存の属性クラスを維持したまま、新しい属性を追加する場合: <elementSpec ident="pb" mode="change"> <attList> <attDef ident="facs" mode="add" usage="opt"> <desc>原本画像へのリンク</desc> <datatype> <dataRef key="teidata.pointer"/> </datatype> </attDef> </attList> </elementSpec> この場合、既存の属性クラスはそのまま維持され、facs属性が追加されます。

Next Auth (Auth.js v5) の本番環境で AUTH_URL が必須な理由

Next Auth (Auth.js v5) の本番環境で AUTH_URL が必須な理由

概要 Next Auth (Auth.js v5) を使用したアプリケーションを Docker コンテナや本番環境にデプロイする際、AUTH_URL 環境変数を設定しないと GitHub OAuth 認証で以下のエラーが発生します: Be careful! The redirect_uri is not associated with this application. 開発環境 vs 本番環境 開発環境(npm run dev) 開発環境では Next.js が自動的にホスト情報を検出するため、AUTH_URL の設定は不要 です。 # これだけで動作する npm run dev 本番環境(Docker / npm run build && npm start) 本番環境では Next Auth がホスト情報を自動検出できないため、AUTH_URL の設定が必須 です。 # .env.local または環境変数に追加 AUTH_URL=http://localhost:3000 # または https://your-domain.com AUTH_TRUST_HOST=true Docker での設定例 docker run の場合 docker run -d --name myapp -p 3000:3000 \ --env-file .env.local \ -e AUTH_TRUST_HOST=true \ myapp:latest docker-compose.yml の場合 services: app: image: myapp:latest ports: - "3000:3000" environment: - AUTH_URL=https://your-domain.com - AUTH_TRUST_HOST=true env_file: - .env.local 必要な環境変数一覧 変数名 開発環境 本番環境 説明 AUTH_SECRET 必須 必須 セッション暗号化キー AUTH_GITHUB_ID 必須 必須 GitHub OAuth Client ID AUTH_GITHUB_SECRET 必須 必須 GitHub OAuth Client Secret AUTH_URL 不要 必須 アプリケーションのベースURL AUTH_TRUST_HOST 不要 必須 ホストを信頼する設定 .env.local の例 # NextAuth.js Configuration AUTH_SECRET=your-secret-key-here # GitHub OAuth App Credentials AUTH_GITHUB_ID=your-client-id AUTH_GITHUB_SECRET=your-client-secret # Production only (Docker / deployed environments) AUTH_URL=http://localhost:3000 なぜこの問題が起きるのか 開発環境 : Next.js の開発サーバーがリクエストヘッダーから正確なホスト情報を取得できる 本番環境 : Docker コンテナ内では 0.0.0.0:3000 として起動するため、外部からアクセスする際の実際のURLがわからない OAuth の仕組み : GitHub は登録された redirect_uri と完全一致するURLにのみリダイレクトを許可する トラブルシューティング エラー: “redirect_uri is not associated with this application” 原因 : AUTH_URL が未設定、または GitHub OAuth App の Callback URL と一致しない ...

YOLOv11xモデルをHugging Faceに公開する

YOLOv11xモデルをHugging Faceに公開する

日本古典籍くずし字データセットで学習したYOLOv11xモデルをHugging Faceに公開し、Gradio Spacesでデモを作成する手順を紹介します。 概要 モデル : YOLOv11x(くずし字検出用) データセット : 日本古典籍くずし字データセット 公開先 : Hugging Face Models + Spaces 1. Hugging Face Modelsにモデルを登録 1.1 huggingface_hubのインストール pip install huggingface_hub 1.2 ログイン huggingface-cli login または Python から: from huggingface_hub import login login() トークンは https://huggingface.co/settings/tokens から取得できます(Write権限が必要)。 1.3 モデルのアップロード from huggingface_hub import HfApi, create_repo api = HfApi() repo_id = "your-username/yolov11x-codh-char" # リポジトリ作成 create_repo(repo_id, repo_type="model", exist_ok=True) # モデルファイルをアップロード api.upload_file( path_or_fileobj="best.pt", path_in_repo="best.pt", repo_id=repo_id, repo_type="model" ) 1.4 Model Card (README.md) の作成 モデルの使い方やライセンス情報を記載したREADME.mdを作成してアップロードします。 2. Hugging Face Spacesでデモを公開 2.1 Spacesの設定 (README.md) --- title: YOLOv11x Character emoji: 👁 colorFrom: pink colorTo: green sdk: gradio sdk_version: 5.49.1 app_file: app.py pinned: false --- ポイント : ...

IIIF画像をWeb Tile Map Serviceで配信する

IIIF画像をWeb Tile Map Serviceで配信する

IIIF Georeference Extension JSONからXYZタイルを生成し、TileServer GLで配信、MapLibre GL JSで表示するまでの手順をまとめます。 OSM上に東京大学鳥瞰図をオーバーレイ表示 概要 IIIF Georeference JSON │ ▼ ┌───────────────────────┐ │ iiif-georef-tiles │ │ (XYZタイル生成) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ mb-util │ │ (mbtiles変換) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ TileServer GL │ │ (タイル配信) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ MapLibre GL JS │ │ (地図表示) │ └───────────────────────┘ 必要環境 Docker / Docker Compose Python 3.x GDAL (gdal_translate, gdalwarp, gdal2tiles.py) Pillow (pip3 install pillow) mb-util GDALのインストール # macOS (Homebrew) brew install gdal # Ubuntu/Debian sudo apt install gdal-bin python3-gdal mb-utilのインストール pip3 install mbutil 1. プロジェクト構成 wtms/ ├── docker-compose.yml ├── data/ # mbtilesファイル ├── styles/ # カスタムスタイル(オプション) ├── frontend/ # MapLibreビューア └── docs/ 2. Docker Compose設定 docker-compose.yml: ...

Nuxt 3 プロジェクトのパッケージ更新まとめ

Nuxt 3 プロジェクトのパッケージ更新まとめ

概要 Nuxt 3.2.3 から 3.20.2 へのメジャーアップデートを含む、依存パッケージの大規模更新を実施しました。 主要なパッケージ更新 パッケージ 更新前 更新後 nuxt 3.2.3 3.20.2 @nuxt/content 2.5.2 3.11.0 @nuxtjs/i18n 8.0.0-beta.10 10.2.1 vuetify 3.1.8 3.7.6 sass 1.58.3 1.83.4 @mdi/js 7.1.96 7.4.47 新規追加パッケージ better-sqlite3: ^12.5.0 - @nuxt/content v3 の依存 vue-i18n: ^11.0.0 - i18n モジュールの依存 対応が必要だった変更点 1. @nuxt/content v3 への移行 content.config.ts の新規作成が必要になりました。 // content.config.ts import { defineContentConfig, defineCollection } from '@nuxt/content' export default defineContentConfig({ collections: { content: defineCollection({ type: 'page', source: '**/*.md' }) } }) 2. @nuxtjs/i18n v10 への移行 nuxt.config.ts の変更点 // Before i18n: { locales: [ { code: "ja", iso: "ja_JP", file: "ja.js" }, { code: "en", iso: "en-US", file: "en.js" }, ], langDir: "locales/", vueI18n: { fallbackLocale: lang, }, } // After i18n: { locales: [ { code: "ja", language: "ja-JP", file: "ja.js" }, // iso → language { code: "en", language: "en-US", file: "en.js" }, ], bundle: { optimizeTranslationDirective: false, runtimeOnly: true, }, langDir: "locales", // 末尾スラッシュ削除 vueI18n: "./i18n.config.ts", // 外部ファイル化 } i18n.config.ts の新規作成 export default defineI18nConfig(() => ({ legacy: false, fallbackLocale: "ja", })); localesフォルダの移動 locales/ → i18n/locales/ ...

IIIF Georeference to XYZ Tiles

IIIF Georeference to XYZ Tiles

IIIF Georeference Extension JSONからXYZタイルを生成し、MapLibre GL JSで表示するツール。 リポジトリ : https://github.com/nakamura196/iiif-georef-tiles GitHub Pages : https://nakamura196.github.io/iiif-georef-tiles/ 必要環境 Python 3.x GDAL (gdal_translate, gdalwarp, gdal2tiles.py) GDALのインストール # macOS (Homebrew) brew install gdal # Ubuntu/Debian sudo apt install gdal-bin python3-gdal 使用方法 python3 scripts/iiif_georef_to_tiles.py <IIIF_GEOREF_JSON_URL> 例 python3 scripts/iiif_georef_to_tiles.py https://nakamura196.github.io/iiif_geo/canvas.json オプション オプション デフォルト 説明 --scale 0.25 画像の縮小率 --zoom 14-18 タイルのズームレベル範囲 --output-dir docs 出力ディレクトリ --name tiles タイルフォルダ名 --work-dir work 作業用ディレクトリ --keep-work - 作業用ファイルを削除しない 処理の流れ IIIF Georeference JSON │ ▼ ┌───────────────────────┐ │ 1. JSONを取得 │ │ (URLからfetch) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 2. 画像をダウンロード │ │ (IIIF Image API) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 3. GCPを埋め込み │ │ (gdal_translate) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 4. 座標変換 │ │ (gdalwarp) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 5. タイル生成 │ │ (gdal2tiles.py) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ 6. HTMLビューア生成 │ │ (MapLibre GL JS) │ └───────────────────────┘ 変換結果 元画像 地理参照後 出力ファイル docs/ ├── index.html # MapLibre GL JSビューア ├── source.json # 元のIIIF Georeference JSON └── tiles/ # XYZタイル ├── 14/ ├── 15/ ├── 16/ ├── 17/ └── 18/ ローカルで確認 cd docs && python3 -m http.server 8000 # http://localhost:8000/ を開く IIIF Georeference Extension IIIF Georeference Extensionは、IIIF画像に地理参照情報を付与するための拡張仕様です。 ...

Azure OpenAI Whisper + Speech Services で動画に英語字幕・音声を自動生成する

Azure OpenAI Whisper + Speech Services で動画に英語字幕・音声を自動生成する

日本語の動画に英語字幕と英語音声を自動で付与する方法をまとめました。Azure OpenAI ServiceのWhisperとSpeech Servicesを使用します。 概要 今回の目的は、日本語音声の動画を以下のように多言語対応させることです: 日本語版 : 元の動画(日本語音声、字幕なし) 英語版 : 英語音声 + 英語字幕 使用サービス サービス 用途 Azure OpenAI Service (Whisper) 日本語音声 → 英語テキストへの翻訳 Azure Speech Services (TTS) 英語テキスト → 英語音声の合成 FFmpeg 音声抽出・動画結合 手順 1. 環境準備 必要なツール # FFmpegのインストール(macOS) brew install ffmpeg # Pythonライブラリ pip install python-dotenv requests Azure設定(.env) AZURE_OPENAI_ENDPOINT=https://xxxxx.openai.azure.com AZURE_OPENAI_API_KEY=your-api-key AZURE_OPENAI_DEPLOYMENT_NAME=whisper AZURE_OPENAI_API_VERSION=2024-06-01 2. 動画から音声を抽出 Azure Whisper APIには25MBのファイルサイズ制限があるため、音声を圧縮して抽出します。 ffmpeg -i input.mp4 -vn -acodec libmp3lame -b:a 64k -ar 16000 audio.mp3 3. Whisperで英語字幕を生成 Azure OpenAI ServiceのWhisper APIを使用して、日本語音声を英語に翻訳しながら文字起こしします。 ...

Eclipse EDCを使ったデータスペース入門 - ローカル環境でデータ交換フローを体験する

Eclipse EDCを使ったデータスペース入門 - ローカル環境でデータ交換フローを体験する

はじめに 近年、企業間でのデータ共有・流通の重要性が高まっています。しかし、単純にAPIを公開するだけでは、「誰が」「どんな条件で」「どのデータに」アクセスできるかを制御することが困難です。 データスペース(Dataspace) は、この課題を解決するための概念です。データの所有者が主権を持ちながら、信頼できる相手とデータを安全に共有できる仕組みを提供します。 本記事では、データスペースの実装基盤である Eclipse EDC(Eclipse Dataspace Components) を使って、ローカル環境でデータ交換フローを体験します。 目次 データスペースとは? Eclipse EDCの概要 環境構築 データ交換フローの実行 GUIダッシュボードの作成 まとめ データスペースとは? 従来のデータ共有の課題 従来のAPI連携では、以下のような課題がありました: アクセス制御が困難 : APIキーを渡すと、どんなデータでも取得できてしまう 利用条件の管理 : 「このデータは社内利用のみ」といった条件を技術的に強制できない 監査・追跡 : 誰がいつデータを取得したか追跡しづらい データスペースの解決策 データスペースは以下の仕組みで解決します: ┌─────────────────────────────────────────────────────────────┐ │ 従来のAPI連携 │ │ │ │ Consumer ─────APIキー────→ Provider API │ │ ←────データ──── │ │ │ │ 課題: 誰でもデータ取得可能、条件管理なし │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ データスペース │ │ │ │ 1. Consumer: 「〇〇のデータが欲しい」(カタログ確認) │ │ 2. Provider: 「この条件を満たせば提供する」(ポリシー提示) │ │ 3. 両者: 契約交渉・合意 │ │ 4. Consumer: 契約に基づきデータ取得 │ │ │ │ メリット: 条件付きアクセス、監査可能、主権維持 │ └─────────────────────────────────────────────────────────────┘ 主要な用語 用語 説明 Connector データスペースに参加するためのソフトウェア。ProviderとConsumerそれぞれが持つ Provider データを提供する側 Consumer データを取得する側 Catalog Providerが公開しているデータの一覧 Policy データアクセスの条件(誰が、いつ、どのように使えるか) Contract ProviderとConsumer間で結ばれる契約 EDR Endpoint Data Reference。データ取得用の一時的なアクセス情報 Eclipse EDCの概要 Eclipse EDC は、Eclipse Foundationが開発するオープンソースのデータスペース実装基盤です。 ...

@elastic/react-search-ui を React 19 + Next.js 15.5 で使う方法

@elastic/react-search-ui を React 19 + Next.js 15.5 で使う方法

はじめに React 19 と Next.js 15 を使用しているプロジェクトで @elastic/react-search-ui を使おうとすると、以下のような依存関係エラーに遭遇することがあります。 npm error ERESOLVE could not resolve npm error peer react@">= 16.8.0 < 19" from @elastic/react-search-ui@1.23.1 この記事では、この問題の原因と解決方法を詳しく解説します。 問題の原因 @elastic/react-search-ui@1.23.1 の peer dependency が react@">= 16.8.0 < 19" となっており、React 19 をサポートしていませんでした。 解決策 1. パッケージのアップグレード 2025年5月に PR #1162 がマージされ、React 19 がサポートされました。バージョン 1.24.2 以降を使用します。 // package.json { "dependencies": { - "@elastic/react-search-ui": "^1.23.1", - "@elastic/react-search-ui-views": "^1.23.1", - "@elastic/search-ui": "^1.23.1", + "@elastic/react-search-ui": "^1.24.2", + "@elastic/react-search-ui-views": "^1.24.2", + "@elastic/search-ui": "^1.24.2", - "next": "15.3.8", + "next": "15.5.9", } } 2. 型定義の変更への対応 1.24.2 では WithSearch コンポーネントの型定義が変更されました。SearchContextState の filters が Filter[] | undefined になっています。 ...

GLBファイルのDraco圧縮 - 87%のサイズ削減と精度への影響

GLBファイルのDraco圧縮 - 87%のサイズ削減と精度への影響

3DモデルをWebで配信する際、ファイルサイズは重要な課題です。本記事では、Draco圧縮 を使ってGLBファイルを87%削減した事例と、圧縮時の注意点(特にUV座標)について解説します。 https://3dtiles-viewer.vercel.app/glb-viewer.html 使用データ モデル : Rotunde Brunnen(噴水のある円形建築物) 出典 : Sketchfab 形式 : GLB (glTF 2.0 Binary) Draco圧縮とは DracoはGoogleが開発したオープンソースの3Dメッシュ圧縮ライブラリです。glTF 2.0ではKHR_draco_mesh_compression拡張として標準サポートされています。 圧縮の仕組み 量子化(Quantization) : 頂点座標やUV座標を指定ビット数に丸める 予測符号化 : 隣接頂点との差分を予測して符号化 エントロピー符号化 : 予測誤差を効率的に圧縮 圧縮コマンド # gltf-transformを使用 npx gltf-transform draco input.glb output-draco.glb # オプション付き(高品質設定) npx gltf-transform draco input.glb output-draco.glb \ --quantize-position 14 \ --quantize-normal 10 \ --quantize-texcoord 12 圧縮結果の比較 ファイルサイズ ファイル サイズ 削減率 rotunde-brunnen.glb(元) 94.7 MB - rotunde-brunnen-draco.glb 12.5 MB 87%削減 メッシュ構造 項目 元ファイル Draco圧縮後 メッシュ数 38 2(統合) 三角形数 約175万 約167万 テクスチャ 1024x1024 PNG 同一 バウンディングボックス ほぼ同一 ほぼ同一 精度 視覚的な精度低下はありません 。 ...