🎨

opencvjsで配列操作

2023/09/18に公開

jsでopencvを使うにはいくつか方法があるが、ここではopencv-tsを使う。

表示

import cv from "opencv-ts";

cv.onRuntimeInitialized = () => {
  const imgMat = cv.matFromArray(
    2,
    3,
    cv.CV_8UC3,
    [255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 127, 127, 127]
  );
  cv.imshow("canvas", imgMat); // 第一引数はcanvas要素のid
  // reactの場合は cv.imshow(canvasRef.current, imgMat);
};

  • ブラウザ上ではリソースの読み込みタイミングによってはエラーとなるのでcv.onRuntimeInitialized内で実行するのが確実
  • canvasで表示するならcv.MatはR, G, Bの順にする

縮小

const resized = new cv.Mat();
cv.resize(
  imgMat,
  resized,
  new cv.Size(Math.ceil(size[1] / 2), Math.ceil(size[0] / 2)),
  0,
  0,
  cv.INTER_AREA
);

cv.imshow("canvas", resized);

サイズを半分にする例

統計値

import cv from "opencv-ts";

const testMat = cv.matFromArray(
  2, 3, cv.CV_8UC2,
  [1, 10, 2, 20, 3, 30, 4, 40, 5, 50, 6, 60]
);
const mean = new cv.Mat();
const stddev = new cv.Mat();
cv.meanStdDev(testMat, mean, stddev);
for (let i = 0; i < mean.rows; i++) {
  for (let j = 0; j < mean.cols; j++) {
    console.log(`mean(${i}, ${j})`, mean.doubleAt(i, j));
  }
}
for (let i = 0; i < stddev.rows; i++) {
  for (let j = 0; j < stddev.cols; j++) {
    console.log(`stddev(${i}, ${j})`, stddev.doubleAt(i, j));
  }
}
mean(0, 0) 3.5
mean(1, 0) 35
stddev(0, 0) 1.707825127659933
stddev(1, 0) 17.078251276599325
  • レイヤーごと([1,2,3,4,5,6], [10,20,30,40,50,60])の統計値が計算される。
  • レイヤー数=rows
  • cv.Matの各値にはdoubleAtでアクセスできる。
  • 配列として扱いたい場合はdata64Fを参照する[1]

ヒストグラム

const imgMat = cv.matFromArray(
  3, 3, cv.CV_8UC3,
  [
    255, 0, 0, 0, 255, 0, 0, 0, 255, 
    255, 255, 255, 0, 0, 0, 127, 127,
    127, 1, 0, 0, 0, 10, 0, 0, 0, 100,
  ]
);
const imgVec = new cv.MatVector();
imgVec.push_back(imgMat);
const hist = new cv.Mat();
cv.calcHist(imgVec, [0], new cv.Mat(), hist, [256], [0, 256]);

console.log(hist.data32F);
console.log("0: ", hist.data32F[0]);
console.log("1: ", hist.data32F[1]);
console.log("10: ", hist.data32F[10]);
console.log("100: ", hist.data32F[100]);
console.log("255: ", hist.data32F[255]);
Float32Array(256) [5, 1, 0, 0, 0, …]
0:  5
1:  1
10:  0
100:  0
255:  2

ビン数を256、値の範囲を0~255でヒストグラム計算している例

  • 指定した1レイヤーのヒストグラム計算を行う[2]
  • 結果はdata32Fを参照する[3]
  • 入力Matのtypeは cv.CV_8U, cv.CV_16U, cv.CV_32F のいずれかでなければエラーになる。

サンプル

https://yonda-yonda.github.io/exmap/univar/

脚注
  1. 常にdata64Fなのかは、コードを追いきれなかったので確証が持てない。 ↩︎

  2. 第一引数はcv.Matでもいいはずだがエラーになるのでcv.MatVectorに変換してから渡す必要がある。その影響か、第二引数などは配列で渡せるので一度に複数レイヤーのヒストグラム計算ができるはずだがエラーが出る。 ↩︎

  3. 公式のサンプル, ソースで確認できる。 ↩︎

Discussion