[React] OpenCV で画像の HITMISS(Hit or Miss) をしてみる | 心を無にして始める React
この記事は、たぶん優先度が低いです。
物体検出なら別の関数使いそうだし…、にわかには使いどころが、思いつかない (。´・ω・)
準備
React で OpenCV.js を使えるようにしておきます。
今回も、形態を変化させるモルフォロジー処理を使っていきます。
OpenCVで定義されるタイプは、膨張、収縮、オープニング、クロージング、勾配、ブラックハット、トップハット、Hit or Miss があります。
https://docs.opencv.org/5.x/d4/d86/group__imgproc__filter.html#ga7be549266bad7b2e6a04db49827f9f32
今回は、用途のよくわからない Hit or Miss を使ってみます。
(2値画像から特定パターンを探せるけど、それを使うシーンがまだ浮かばない…)
Hit or Miss
2値画像 から、指定したパターンを探すことができます。
https://docs.opencv.org/5.x/db/d06/tutorial_hitOrMiss.html
cv.MORPH_HITMISS を指定して morphologyEx を呼びます。
今回は、白い十字型のパターンを指定して探してみます。
イメージ
局所的なサンプル
const kernelSize = cv.matFromArray(3, 3, cv.CV_32S, [
-1, 1, -1,
1, 1, 1,
-1, 1, -1,
]);
cv.morphologyEx(src, dst, cv.MORPH_HITMISS, kernelSize);
使ってみた
イメージを出すときに書いた App.js です。
import React, { useEffect } from 'react';
import './App.css';
const cv = window.cv;
function App() {
useEffect(() => {
hundleHitmiss();
}, []);
const hundleHitmiss = () => {
if (!cv.Mat) {
setTimeout(hundleHitmiss, 1000);
return;
}
const src = cv.matFromArray(6, 8, cv.CV_8UC1, [
0, 0, 0, 0, 0, 255, 0, 0,
0, 255, 0, 255, 255, 0, 255, 0,
255, 255, 255, 0, 255, 255, 0, 255,
0, 255, 0, 255, 0, 255, 0, 0,
255, 0, 0, 0, 255, 255, 255, 255,
255, 255, 0, 0, 0, 255, 0, 255,
]);
const kernelSize = cv.matFromArray(3, 3, cv.CV_32S, [
-1, 1, -1,
1, 1, 1,
-1, 1, -1,
]);
cv.imshow('canvas-0', src);
const dst = new cv.Mat();
cv.morphologyEx(src, dst, cv.MORPH_HITMISS, kernelSize);
cv.imshow('canvas-1', dst);
kernelSize.delete();
dst.delete();
src.delete();
}
const titles = [
'オリジナル',
'HIT MISS',
];
return (
<>
<div className="bg-dark p-5" style={{ minHeight: '100vh', height: '100%' }}>
<div className="d-flex flex-column justify-content-center align-items-center p-5 bg-light">
{
[0, 1].map(i => (
<div key={i} className="m-2">
<div className="fw-bold">
{titles[i]}
</div>
<canvas
id={`canvas-${i}`}
width="320"
height="240"
className="border border-dark bg-light"
style={{ width: 320, height: 240, imageRendering: 'pixelated' }}
/>
</div>
))
}
</div>
</div>
</>
);
}
export default App;
はい、できました。
グレースケールではどうなるの?
エラーとはならない。
ただし、意味のない値になります。
(もしかすると画期的な使い方があるかもしれませんが、想定されていない使い方だと思います。)
Hit or Miss の演算
A ⊛ B = ( A ⊖ B1 ) ∩ ( Ac ⊖ B2 )
A:元画像
B:カーネル
AとBのHITMISS = AをB1で収縮 & Aの補集合(白黒反転)をB2で収縮
カーネルについて
この3つのカーネルは B1 + B2 = B の並びになっています。
それでどうなるの?
数式を少し読みやすくすると、次のようになります。
AとBのHITMISS =( AをB1で収縮) &( Aの補集合(白黒反転)をB2で収縮)
数式の通り、HITMISSでは2つの収縮画像について、画素ごとに AND をとります。
2値画像であれば 0, 255 を用いて 真偽値 のように機能しますが、
2値画像ではない様々な値をもつ画像であった場合、ANDの結果は意味のない値となります。
例えば、
( A ⊖ B1 ) で特定の画素の値が 151 で、( Ac ⊖ B2 ) では 101 だったとすると、この AND は 1 になってしまいます…。
つまり、指定したパターンにどの程度似ているかといった使い方はできません。
CV_8UC1 であれば正常に終了してしまいますが、あくまで、2値画像で特定パターンを探すもののようです。