OpenCV 4.13.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 4.13.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
画像に対する基本操作

目標

  • 画像のプロパティへのアクセス方法を学ぶ
  • Matの構築方法を学ぶ
  • Matのコピー方法を学ぶ
  • Matの型の変換方法を学ぶ
  • MatVectorの使い方を学ぶ
  • ピクセル値へのアクセス方法とその変更方法を学ぶ
  • 関心領域 (ROI) の設定方法を学ぶ
  • 画像の分割と結合の方法を学ぶ

画像プロパティへのアクセス

画像のプロパティには、行数、列数とサイズ、ビット深度、チャンネル、画像データの型が含まれる。

let src = cv.imread("canvasInput");
console.log('image width: ' + src.cols + '\n' +
'image height: ' + src.rows + '\n' +
'image size: ' + src.size().width + '*' + src.size().height + '\n' +
'image depth: ' + src.depth() + '\n' +
'image channels ' + src.channels() + '\n' +
'image type: ' + src.type() + '\n');
覚え書き
OpenCV.jsコードの多くのエラーは無効なデータ型が原因となるため、デバッグ時にsrc.type()は非常に重要である。

Matの構築方法

4つの基本的なコンストラクタがある:

// 1. default constructor
let mat = new cv.Mat();
// 2. two-dimensional arrays by size and type
let mat = new cv.Mat(size, type);
// 3. two-dimensional arrays by rows, cols, and type
let mat = new cv.Mat(rows, cols, type);
// 4. two-dimensional arrays by rows, cols, and type with initialization value
let mat = new cv.Mat(rows, cols, type, new cv.Scalar());

3つの静的関数がある:

// 1. Create a Mat which is full of zeros
let mat = cv.Mat.zeros(rows, cols, type);
// 2. Create a Mat which is full of ones
let mat = cv.Mat.ones(rows, cols, type);
// 3. Create a Mat which is an identity matrix
let mat = cv.Mat.eye(rows, cols, type);

2つのファクトリ関数がある:

// 1. Use JS array to construct a mat.
// For example: let mat = cv.matFromArray(2, 2, cv.CV_8UC1, [1, 2, 3, 4]);
let mat = cv.matFromArray(rows, cols, type, array);
// 2. Use imgData to construct a mat
let ctx = canvas.getContext("2d");
let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
let mat = cv.matFromImageData(imgData);
覚え書き
cv.Mat を使わなくなったら削除するのを忘れないこと。

Matのコピー方法

Matをコピーする方法は2つある:

// 1. Clone
let dst = src.clone();
// 2. CopyTo(only entries indicated in the mask are copied)
src.copyTo(dst, mask);

Matの型の変換方法

次の関数を使う: convertTo(m, rtype, alpha = 1, beta = 0)

引数
m出力行列。操作前に適切なサイズや型を持っていない場合は再確保される。
rtype出力行列に求める型、あるいは正確にはビット深度。チャンネル数は入力と同じであるためである。rtypeが負の場合、出力行列は入力と同じ型になる。
alpha省略可能なスケール係数。
betaスケーリングされた値に加算する省略可能なデルタ。
src.convertTo(dst, rtype);

MatVectorの使い方

let mat = new cv.Mat();
// Initialise a MatVector
let matVec = new cv.MatVector();
// Push a Mat back into MatVector
matVec.push_back(mat);
// Get a Mat fom MatVector
let cnt = matVec.get(0);
mat.delete(); matVec.delete(); cnt.delete();
覚え書き
cv.Mat、cv.MatVector、cnt(MatVectorから取得したMat)を使わなくなったら削除するのを忘れないこと。

ピクセル値へのアクセスと変更

まず、次の型の対応関係を知っておくべきである:

データプロパティC++ 型JavaScript 型付き配列Mat 型
dataucharUint8ArrayCV_8U
data8ScharInt8ArrayCV_8S
data16UushortUint16ArrayCV_16U
data16SshortInt16ArrayCV_16S
data32SintInt32ArrayCV_32S
data32FfloatFloat32ArrayCV_32F
data64FdoubleFloat64ArrayCV_64F

1. data

let row = 3, col = 4;
let src = cv.imread("canvasInput");
if (src.isContinuous()) {
let R = src.data[row * src.cols * src.channels() + col * src.channels()];
let G = src.data[row * src.cols * src.channels() + col * src.channels() + 1];
let B = src.data[row * src.cols * src.channels() + col * src.channels() + 2];
let A = src.data[row * src.cols * src.channels() + col * src.channels() + 3];
}
覚え書き
データの操作は連続したMatに対してのみ有効である。まずisContinuous()を使って確認すべきである。

2. at

Mat 型At 操作
CV_8UucharAt
CV_8ScharAt
CV_16UushortAt
CV_16SshortAt
CV_32SintAt
CV_32FfloatAt
CV_64FdoubleAt
let row = 3, col = 4;
let src = cv.imread("canvasInput");
let R = src.ucharAt(row, col * src.channels());
let G = src.ucharAt(row, col * src.channels() + 1);
let B = src.ucharAt(row, col * src.channels() + 2);
let A = src.ucharAt(row, col * src.channels() + 3);
覚え書き
atによる操作はシングルチャンネルへのアクセス専用であり、値を変更することはできない。

3. ptr

Mat 型Ptr 操作JavaScript 型付き配列
CV_8UucharPtrUint8Array
CV_8ScharPtrInt8Array
CV_16UushortPtrUint16Array
CV_16SshortPtrInt16Array
CV_32SintPtrInt32Array
CV_32FfloatPtrFloat32Array
CV_64FdoublePtrFloat64Array
let row = 3, col = 4;
let src = cv.imread("canvasInput");
let pixel = src.ucharPtr(row, col);
let R = pixel[0];
let G = pixel[1];
let B = pixel[2];
let A = pixel[3];

mat.ucharPtr(k) はmatのk行目を取得する。mat.ucharPtr(i, j) はmatのi行目j列目を取得する。

画像のROI

時には、画像の特定の領域を扱う必要がある。画像内での目の検出では、まず画像全体に対して顔検出を行い、顔が得られたら、その顔の領域だけを選択して、画像全体を探索する代わりにその中で目を探索する。これにより精度(目は常に顔の上にあるため)と性能(小さな領域を探索するため)が向上する

次の関数を使う: roi (rect)

引数
rect矩形の関心領域 (Region of Interest)。

試してみよう

画像チャンネルの分割と結合

画像のR,G,Bチャンネルを個別に処理する必要が生じることがある。その場合はRGB画像をシングルプレーンに分割する必要がある。あるいは逆に、個々のチャンネルをRGB画像に結合する必要がある場合もある。

let src = cv.imread("canvasInput");
let rgbaPlanes = new cv.MatVector();
// Split the Mat
cv.split(src, rgbaPlanes);
// Get R channel
let R = rgbaPlanes.get(0);
// Merge all channels
cv.merge(rgbaPlanes, src);
src.delete(); rgbaPlanes.delete(); R.delete();
覚え書き
cv.Mat、cv.MatVector、R(MatVectorから取得したMat)は、使用しなくなったら削除することを忘れないこと。

画像に境界を付ける (パディング)

写真フレームのような境界を画像の周囲に作りたい場合は、cv.copyMakeBorder() 関数を使用できる。ただしこの関数は畳み込み演算やゼロパディングなど、より多くの用途を持つ。この関数は以下の引数を取る。

  • src - 入力画像
  • top, bottom, left, right - 対応する方向のピクセル数で表した境界の幅
  • borderType - Flag defining what kind of border to be added. It can be following types:
    • cv.BORDER_CONSTANT - Adds a constant colored border. The value should be given as next argument.
      • cv.BORDER_REFLECT - 境界が境界要素の鏡像反射になる。次のような形: fedcba|abcdefgh|hgfedcb
      • cv.BORDER_REFLECT_101 または cv.BORDER_DEFAULT - 上記と同じだが、わずかに変化する。次のような形: gfedcb|abcdefgh|gfedcba
      • cv.BORDER_REPLICATE - 最後の要素が全体に複製される。次のような形: aaaaaa|abcdefgh|hhhhhhh
      • cv.BORDER_WRAP - 説明しにくいが、次のような形になる: cdefgh|abcdefgh|abcdefg
  • value - 境界の種類が cv.BORDER_CONSTANT の場合の境界の色

試してみよう