目次
1. ImageData オブジェクトの取得または作成
まずは、Canvas 上から ImageData オブジェクトを取得または作成します。
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const context = canvas.getContext("2d");
// 座標(10, 10)の位置に、widthが200、heightが100のイメージを描画
context.drawImage(image, 10, 10, 200, 100);
// 座標(10, 10)の位置から、widthが200、heightが100のイメージを取得
const imageData1 = context.getImageData(0, 0, 200, 100);
// widthが200、heightが100のイメージを作成
const imageData2 = context.createImageData(200, 100);
2. ImageData から cv.Mat に変換
ImageData.data には、Uint8ClampedArray 型のバイナリ配列が格納されています。 その配列は、RGBA カラー(32bit)になっていますので、OpenCV 用に RGB カラーに変換します。
const src = cv.matFromImageData(imageData.data);
cv.cvtColor(src, src, cv.COLOR_RGBA2RGB);
3. OpenCV.js で画像処理
cv.Mat になってしまえば、あとは自由に OpenCV の画像処理が出来ます。 cv.Mat のプロパティには、以下があります。
- rows: 画像の高さ
- cols: 画像の幅
- step: 画像一行あたりのバイト数
- data: 画像データのポインタ
- channels(): チャンネル数
- type(): 画像の種類
- depth(): 1ピクセルあたりのビット数
OpenCV.js での注意事項は、自分で new した cv.Mat は必ず delete すること!
// 線を引く
let start = new cv.Point(0, 0);
let end = new cv.Point(200, 200);
cv.line(src, start, end, new cv.Scalar(0, 0, 255), 2, cv.LINE_AA, 0);
// 四角を描く
let p1 = new cv.Point(10, 10);
let p2 = new cv.Point(200, 200);
cv.rectangle(src, p1, p2, cv.Scalar(0, 0, 255), cv.FILLED);
// 丸を描く
let p1 = new cv.Point(100, 100);
cv.circle(dst, p1, 80, cv.Scalar(0, 0, 255), cv.FILLED);
4. cv.Mat から ImageData に変換
ImageData に戻すために、OpenCV で扱ったデータの型から RGBA カラー(32bit)に変換します。
function imageDataFromMat(mat) {
// converts the mat type to cv.CV_8U
const img = new cv.Mat();
const depth = mat.type() % 8;
const scale =
depth <= cv.CV_8S ? 1.0 : depth <= cv.CV_32S ? 1.0 / 256.0 : 255.0;
const shift = depth === cv.CV_8S || depth === cv.CV_16S ? 128.0 : 0.0;
mat.convertTo(img, cv.CV_8U, scale, shift);
mat.delete();
// converts the img type to cv.CV_8UC4
switch (img.type()) {
case cv.CV_8UC1:
cv.cvtColor(img, img, cv.COLOR_GRAY2RGBA);
break;
case cv.CV_8UC3:
cv.cvtColor(img, img, cv.COLOR_RGB2RGBA);
break;
case cv.CV_8UC4:
break;
default:
throw new Error(
"Bad number of channels (Source image must have 1, 3 or 4 channels)"
);
}
const clampedArray = new ImageData(
new Uint8ClampedArray(img.data),
img.cols,
img.rows
);
img.delete();
return clampedArray;
}
5. 画像処理した結果を Canvas に描画
const img_converted = imageDataFromMat(mat);
//座標(50, 50)の位置に、取得したImageDataオブジェクトを描画
context.putImageData(img_converted, 50, 50);