このチュートリアルでは、ウェブカメラで撮影した画像からカラーパレットを抽出する方法を、Node.js、GridDB、OpenAIを使用して解説します。Node.jsをサーバーサイドスクリプトに、GridDBを効率的なデータストレージに、OpenAIを高度な画像処理に活用することで、画像のキャプチャ、分析、ダイナミックなカラーパレットの生成をシームレスに連携させたパイプラインを構築します。このガイドでは、環境のセットアップ、ウェブカメラからの画像のキャプチャ、AIを使用して色データを抽出・保存する方法をステップバイステップで説明します。
事前準備
始める前に、以下のソフトウェアがマシンにインストールされていることを確認してください:
- Node.js
- GridDB
- OpenAI API アクセス
- ウェブカメラにアクセス可能なブラウザ
プロジェクトの実行
ソースコードをここからクローンしてください: GitHub repository.
git clone https://github.com/griddbnet/Blogs.git --branch color-extraction
このプロジェクトを実行するには、Node.js と GridDB をインストールする必要があります。ソフトウェア要件がインストールされている場合、ディレクトリを apps
プロジェクトディレクトリに変更し、すべての依存関係をインストールします:
cd color-detection-openai
cd apps
npm install
.env
ファイルを作成し、.env.example
ファイルからすべての環境変数をコピーしてください。このプロジェクトには OpenAI キーが必要です。開始するには「Getting Started」セクションを参照してください。
OPENAI_API_KEY=sk-proj-secret
VITE_APP_URL=http://localhost:3000
VITE_APP_URL
を必要に応じて変更し、以下のコマンドを実行してプロジェクトを実行できます:
npm run start:build
ブラウザを開き、VITE_APP_URL
に設定されたURL(この場合はhttp://localhost:3000
)を入力します。ブラウザでウェブカメラを有効にし、Capture ボタンをクリックしてウェブカメラで写真を撮影します。
環境のセットアップ
1. Node.js のインストール
このプロジェクトは Node.js プラットフォーム上で実行されます。 こちら からインストールしてください。このプロジェクトでは、nvm
パッケージマネージャーと Node.js v16.20.2 LTS バージョンを使用します。
# installs nvm (Node Version Manager)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# download and install Node.js
nvm install 16
# verifies the right Node.js version is in the environment
node -v # should print `v16.20.2`
# verifies the right NPM version is in the environment
npm -v # should print `8.19.4``
Node.jsとGridDBデータベースを接続するには、GridDB C ClientとNode addon APIを使用して開発されたNode.jsバインディングであるgridb-node-api npmパッケージが必要です。
2. GridDB の設定
GridDB データベースを使用してレシピと栄養分析を保存します。詳細なインストール手順はガイドをご確認ください。ここでは Ubuntu 20.04 LTS を使用します。
GridDB を実行し、サービスが動作しているか確認します。次のコマンドを実行してください:
sudo systemctl status gridstore
実行されていない場合は、次のコマンドでデータベースを実行してみてください:
sudo systemctl start gridstore
3. OpenAI キーを取得する
OpenAI キーを取得するには、まずプロジェクトを作成し、その後 キーを作成] します。重要な点は、OpenAI キーを .env
ファイルに保存し、.gitignore
に追加してバージョン管理に含めないようにすることです。
OPENAI_API_KEY=sk-proj-secret
もう1つの重要な要因は、プロジェクトに適したモデルを選択することです。このプロジェクトでは、画像認識と画像からの色抽出のためにgpt-4o
モデルを利用します。
AIモデルの応答は非決定論的であり、つまり、応答が必ずしも私たちの期待するものと一致しない場合があります。このプロジェクトではデフォルトでgpt-4o-mini
モデルを使用していますが、応答が適切でない場合は、より高性能なモデル(例:gpt-4o
モデル)に変更できます。
メディアストリームを使用した画像のキャプチャ
画像のキャプチャにはMediaStream APIを使用できます。これはWebRTCに関連するAPIで、オーディオとビデオデータのストリーミングをサポートします。ウェブカメラから画像を取得する前に、まずウェブカメラを初期化する必要があります:
const initializeWebcam = () => {
navigator.mediaDevices.getUserMedia({
video: true
})
.then(stream => {
videoRef.current.srcObject = stream
})
.catch(error => {
console.error('getUserMedia error:', error)
})
}
次に、動画から画像をキャプチャするには、drawImage()
関数を使用できます:
const captureImage = () => {
const context = canvasRef.current.getContext('2d')
context.drawImage(videoRef.current, 0, 0, canvasRef.current.width, canvasRef.current.height)
const base64Image = canvasRef.current.toDataURL('image/jpeg')
processImage(base64Image)
}
drawImage()
関数は、動画ストリームから現在のフレームをキャプチャし、キャンバスに描画します。これにより、画像データのさらなる操作、処理、または変換が可能になります。提供されたコードでは、キャンバスに描画された画像は toDataURL()
関数を使用して base64 エンコードされた文字列に変換され、その後サーバーに送信されて処理されます。
OpenAI を使用した画像処理
サーバーでの画像処理は比較的簡単です。ウェブアプリは、base64 エンコードされた画像を /process-image
ルートに送信します。
app.post('/process-image', async (req, res) => {
const {
image
} = req.body
if (!image) {
return res.status(400).json({
error: 'No image provided'
})
}
// eslint-disable-next-line no-undef
const result = await getColorAnalysis(image)
res.json(result.choices[0])
})
次に、画像から色分析を取得するために、OpenAIのgpt-4o-mini
モデルを使用します。getColorAnalysis()
関数は、Base64エンコードされた画像を受け取り、処理を行います。
async function getColorAnalysis(base64Image) {
const response = await openai.chat.completions.create({
model: "gpt-4o-mini-2024-07-18",
messages: [{
role: "system",
content: systemPrompt
},
{
role: "user",
content: [{
type: "image_url",
image_url: {
url: base64Image
}
},
{
type: "text",
text: userPrompt
}
]
}
],
temperature: 0.51,
max_tokens: 3000,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
});
return response;
}
OpenAIのモデル応答は、与えられたプロンプトによって決定されます。色分析を行う場合は、以下の特定のプロンプトを使用してください:
const userPrompt = "Extract the seven most prominent colors from the provided image. Use color clustering techniques to identify and present these colors in Hex values. Answer with the raw array values ONLY. DO NOT FORMAT IT.";
OpenAIモデルにシステムプロンプトを追加することで、より良い結果を得ることができます。このシステムプロンプトは、OpenAIモデルが特定のペルソナ(プロフェッショナルなカラーアナリスト)として行動するように指示するコマンドのような役割を果たします。
const systemPrompt = `You are an AI specialized in colorimetry, the science and technology of color detection and measurement. You possess deep knowledge of the principles of color science, including color spaces, color matching functions, and the use of devices such as spectrophotometers and colorimeters. You provide accurate and detailed analyses of color properties, offer solutions for color consistency issues, and assist in applications ranging from imaging and printing to manufacturing and display technologies. Use your expertise to answer questions, solve problems, and provide color detection and measurement guidance.`;
プロンプトでは、モデルの出力形式を指定することもできます。このプロジェクトでは、画像の色分析から得られた色の配列を出力したいと考えています。OpenAIモデルの出力形式は、以下の形式である必要があります:
['#2A2C9B', '#F08A7D', '#8E5DB2', '#E8A1A3', '#4D3B9E', '#7F3C8F', '#B57AB3']
配列の各要素が16進数形式の色を表しています。
GridDBへのデータ格納
データ格納にはGridDBデータベースを利用しています。以下に主なデータフィールドとその説明を記載します:
列名 | タイプ | 説明 |
---|---|---|
ID | 整数 | 各行の固有識別子。 |
写真 | ブロブ | Base64画像エンコード。 |
色 | 文字列 | ヘックス形式の色一覧。 |
saveData()
関数は、libs\griddb.cjs
ファイル内の insert()
関数のラッパーです。この関数は、データをデータベースに保存する役割を担っています。データベースに保存される主なフィールドは2つだけです。
export async function saveData({ image, genColors }) {
const id = generateRandomID()
const picture = Buffer(image)
const colors = String(genColors)
const packetInfo = [parseInt(id), picture, colors]
const saveStatus = await GridDB.insert(packetInfo, collectionDb)
return saveStatus
}
画像の色分析が完了した後、サーバーのルート /process-image
で保存データ機能が実行されます。ユーザーが画像をキャプチャするたびに、その画像は自動的にサーバーに送信され、その結果のデータがデータベースに保存されます。
app.post('/process-image', async (req, res) => {
const { image } = req.body
if (!image) {
return res.status(400).json({ error: 'No image provided' })
}
// eslint-disable-next-line no-undef
const result = await getColorAnalysis(image)
const colorsArray = result.choices[0].message.content
// save data to the database
const saveStatus = await saveData(image, colorsArray)
console.log(saveStatus)
res.json(result.choices[0])
})
ユーザーインターフェースの構築
UIは2つの主要なユーザーインターフェースから構成されています:画像キャプチャとカラーパレット。このプロジェクトでは、コンポーネント管理の改善のためにReact.jsが採用されています。
画像キャプチャ
画像キャプチャのユーザーインターフェースは、単純なHTML5ビデオビューです。以下は、主要なHTMLタグを示すスニペットコードです:
// WebcamContainer.js
const WebcamContainer = ({ onColorsExtracted }) => {
const captureImage = () => {
const context = canvasRef.current.getContext('2d')
context.drawImage(videoRef.current, 0, 0, canvasRef.current.width, canvasRef.current.height)
const base64Image = canvasRef.current.toDataURL('image/jpeg')
processImage(base64Image)
}
// code processing here
return (
<div id="webcam-container">
<video id="webcam" ref={videoRef} autoPlay playsInline width="640" height="480"></video>
<canvas id="canvas" ref={canvasRef} width="640" height="480" style={{ display: 'none' }}></canvas>
<button id="capture" onClick={captureImage}>Capture</button>
<button id="switch-camera" onClick={switchCamera}>Switch Camera</button>
</div>
)
}
export default WebcamContainer
Capture ボタンをクリックすると、captureImage()
関数が指定された動画フレームのイメージをキャプチャし、さらに処理のために送信します。イメージキャプチャのユーザーインターフェースの完全なソースコードは WebcamContainer.jsx
ファイルにあります。
カラーパレット
カラーパレットのユーザーインターフェースは、動的に色付けされた SVG 矩形を連続して配置することで作成できます。
// eslint-disable-next-line react/prop-types
const ColorRectangles = ({ colors }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 700 100"
className="mx-auto">
{colors.map((color, index) => (
<rect
key={index}
x={index * 100}
y="0"
width="100"
height="100"
fill={color}></rect>
))}
</svg>
)
}
export default ColorRectangles
例えば、colors 配列のデータが次のような場合:
['#4B8B3B', '#C4B600', '#7D7D7D', '#E3D4A0', '#2E2E2E', '#F6F1D3', '#A6A6A6']
その後、色はウェブ上で以下のスクリーンショットのように表示されます:
サーバー ルート
クライアントのリクエストを処理するための4つのサーバー ルートがあります。
POST /process-image
画像を色分析のために処理します。
GET /colors
/colors
ルートはデータベースからすべてのデータを取得します。
GET /colors/:id
IDに基づいて保存された色データを取得します。
The data response for the picture
field is a Buffer
type so to process it in the browser, we need to change it into a readable format first.
/**
* Extracting the buffer data
* Assume the result data name is jsonData
*/
const bufferData = jsonData[0][1].data;
// Converting buffer data to Uint8Array object
const uint8Array = new Uint8Array(bufferData);
// Converting Uint8Array to UTF-8 string
const utf8String = new TextDecoder('utf-8').decode(uint8Array);
console.log(utf8String);
GET /delete/:id
データベース内の特定のデータをIDで削除します。例えば、IDが8900
のデータを削除するには:
http://localhost:3000/delete/8900
Tools like PostmaPostman のようなツールを使用して API をテストできます。
SQL データテスト
データベース内のデータを検証するには、CLI コマンドを使用できます。このプロジェクトでは、Ubuntu 20.04 LTS を使用しています。
GridDB ユーザーにログインします:
sudo su gsadm
次に、このコマンドを入力してGridDBシェルに入ります:
gs_sh
このシェルでは、すべてのコンテナを一覧表示し、任意のSQLクエリを実行できます。
gs[public]> showcontainer
gs[public]> select * from ColorPalettes;
1 results (38ms)
gs[public]> delete from ColorPalettes where id=6609;
ブログの内容について疑問や質問がある場合は Q&A サイトである Stack Overflow に質問を投稿しましょう。 GridDB 開発者やエンジニアから速やかな回答が得られるようにするためにも "griddb" タグをつけることをお忘れなく。 https://stackoverflow.com/questions/ask?tags=griddb