序章
OpenCV 、またはオープンソースコンピュータビジョンライブラリは、画像処理と画像認識に使用される強力なライブラリです。 ライブラリには大規模なコミュニティがあり、顔検出からインタラクティブアートまで、多くの分野で広く使用されています。 最初はC++で構築されましたが、PythonやJavaなどのさまざまな言語用にバインディングが作成されています。 JavaScriptではOpenCV.jsとしても利用できます。これは、このチュートリアルで使用するものです。
このプロジェクトでは、ユーザーが画像をアップロードして、そこに含まれるすべての円を検出できるWebページを作成します。 黒い輪郭で円を強調表示し、ユーザーは変更された画像をダウンロードできるようになります。
このプロジェクトのコードは、このGitHubリポジトリで入手できます。
前提条件
このチュートリアルを完了するには、OpenCV.jsライブラリをプルする必要があります。 3.3.1バージョンはここから入手できます。
https://docs.opencv.org/3.3.1/opencv.js
このファイルを次のようにローカルに保存します opencv.js
簡単に見つけられる場所に。
ステップ1—プロジェクトの設定
開始するには、最初にプロジェクト用のスペースを作成する必要があります。 という名前のディレクトリを作成します opencvjs-project
:
mkdir opencvjs-project
のローカルコピーを移動します opencv.js
このディレクトリに。
次に、 index.html
次のテンプレートを使用したファイル:
<!DOCTYPE html>
<html>
<head>
<title>OpenCV.js</title>
</head>
<body>
<!-- Our HTML will go here-->
<script type="text/javascript">
// Our JavaScript code will go here
</script>
</body>
</html>
既存の空に加えて <script>
このファイルにタグを付け、新しいタグを追加します <script>
ローカルを参照するタグ opencv.js
ファイル。 スクリプトは非常に大きく、ロードに少し時間がかかるため、非同期でロードすることをお勧めします。 これは、追加することで実行できます async
に <script>
鬼ごっこ:
<script type="text/javascript">
// Our JavaScript code will go here
</script>
<script async src="opencv.js" type="text/javascript"></script>
OpenCV.jsはファイルサイズが原因ですぐに準備ができていない可能性があるため、コンテンツが読み込まれていることを示すことで、より優れたユーザーエクスペリエンスを提供できます。 ページに読み込みスピナーを追加できます(StackOverflowのSampsonへのクレジット)。
まず、を追加します <div>
エレメント <body>
:
<body>
<!-- Our HTML will go here-->
<div class="modal"></div>
<script type="text/javascript">
// Our JavaScript code will go here
</script>
<script async src="opencv.js" type="text/javascript"></script>
</body>
次に、次のCSSを別のCSSに追加します <style>
のタグ <head>
の index.html
. スピナーはデフォルトでは表示されません( display: none;
):
/* display loading gif and hide webpage */
.modal {
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba( 255, 255, 255, .8)
url('http://i.stack.imgur.com/FhHRx.gif')
50% 50%
no-repeat;
}
/* prevent scrollbar from display during load */
body.loading {
overflow: hidden;
}
/* display the modal when loading class is added to body */
body.loading .modal {
display: block;
}
読み込み中のgifを表示するために、 "loading"
体へのクラス。 空に以下を追加します <script>
.
document.body.classList.add('loading');
OpenCV.jsが読み込まれると、読み込み中のgifを非表示にする必要があります。 を変更します <script>
ローカルを参照するタグ opencv.js
追加するファイル onload
イベントリスナー:
<script async src="opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>
それから加えて onOpenCvReady
他に <script>
の削除を処理するタグ "loading"
クラス:
// previous code is here
function onOpenCvReady() {
document.body.classList.remove('loading');
}
ブラウザでHTMLページを開き、OpenCV.jsが期待どおりに読み込まれることを確認します。
注:ブラウザの開発ツールを使用して、コンソールタブにエラーメッセージが表示されていないこと、およびネットワークタブにエラーメッセージが表示されていることを確認する必要があります。 opencv.js
ファイルが正しく参照されています。 最新の変更を表示するために、ブラウザでこのページを定期的に更新します。
プロジェクトを設定したので、画像アップロード機能を構築する準備が整いました。
ステップ2—画像をアップロードする
アップロード機能を作成するには、まず、 <input>
要素に index.html
:
<input type="file" id="fileInput" name="file" />
ソース画像だけを表示したい場合は、 <img>
要素とイベントリスナー。変更に応答します。 <input>
エレメント。 次のタグをコピーして、 <input>
鬼ごっこ:
<img id="imageSrc" alt="No Image" />
両方を取得します <img>
要素と <input>
それらを使用する要素 id
値:
// previous code is here
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
次に、イベントリスナーを追加します。これは、 <input>
変更(つまり、ファイルがアップロードされたとき)。 変更イベントから、アップロードされたファイルにアクセスすることができます(event.target.files[0]
)、 URL.createObjectURL )を使用してURLに変換します。 画像 src
属性は次のURLに更新できます。
// previous code is here
inputElement.onchange = function() {
imgElement.src = URL.createObjectURL(event.target.files[0]);
};
元の画像の横に、検出された円を示す2番目の画像を表示できます。 画像はで表示されます <canvas>
JavaScriptでグラフィックを描画するために使用される要素:
<canvas id="imageCanvas"></canvas>
を更新する別のイベントリスナーを追加できます <canvas>
アップロードされた画像で:
// previous code is here
imgElement.onload = function() {
let image = cv.imread(imgElement);
cv.imshow('imageCanvas', image);
image.delete();
};
このステップでは、画像のアップロードと表示の機能を設定しました。 次のステップでは、OpenCVを使用して円を検出する方法を探ります。
ステップ3—サークルの検出
円の検出は組み込みのタスクであるため、ここでOpenCVの能力が明らかになります。 ユーザーがボタンをクリックしたときに円を見つけたいので、ボタンとイベントリスナーを追加する必要があります。
<button type="button" id="circlesButton" class="btn btn-primary">Circle Detection</button>
// previous code is here
document.getElementById('circlesButton').onclick = function() {
// circle detection code
};
画像によっては、円の検出に時間がかかる場合がありますので、ボタンを無効にして、ユーザーが何度もボタンを押さないようにすることをお勧めします。 ボタンにローディングスピナーを表示すると便利な場合もあります。 最初のスクリプトロードからロードgifを再利用できます。
// previous code is here
document.getElementById('circlesButton').onclick = function() {
this.disabled = true;
document.body.classList.add('loading');
// circle detection code
this.disabled = false;
document.body.classList.remove('loading');
};
円を検出するための最初のステップは、画像を読み取ることです。 <canvas>
.
OpenCVでは、画像は次のように保存および操作されます Mat
オブジェクト。 これらは基本的に、画像の各ピクセルの値を保持する行列です。
円を検出するには、3つのMatオブジェクトが必要です。
srcMat
-ソース画像(円が検出される元)を保持しますcirclesMat
-検出した円を保存しますdisplayMatOne
-ユーザーに表示します(強調表示された円を描画します)
決勝戦 Mat
、を使用して最初のコピーを作成できます clone
関数:
// circle detection code
let srcMat = cv.imread('imageCanvas');
let displayMat = srcMat.clone();
let circlesMat = new cv.Mat();
The srcMat
グレースケールに変換する必要があります。 これにより、画像が単純化され、円の検出が高速化されます。 使用できます cvtColor
これを行うための関数。
この関数には次のものが必要です。
- 起源
Mat
(srcMat
) - 目的地
Mat
(この場合、ソースと宛先のマットは同じになりますsrcMat
) - 色変換を参照する値。
cv.COLOR_RGBA2GRAY
はグレースケールの定数です。
cv.cvtColor(srcMat, srcMat, cv.COLOR_RGBA2GRAY);
The cvtColor
関数は、他のOpenCV.js関数と同様に、より多くのパラメーターを受け入れます。 これらは必須ではないため、デフォルトに設定されます。 より良いカスタマイズについては、ドキュメントを参照してください。
画像がグレースケールに変換されると、 HoughCircles
円を検出する機能。
この関数には次のものが必要です。
- ソース
Mat
サークルが見つかる場所から(srcMat
) - 目的地
Mat
サークルを保存する場所(circlesMat
) - 円を検出する方法(
cv.HOUGH_GRADIENT
) - アキュムレータ分解能の逆比(
1
) - 円の中心点間の最小距離(
45
)
より多くのパラメータ、アルゴリズムのしきい値があります(75
と 40
)、画像の精度を向上させるために再生できます。
最小値を設定することにより、検出する円の範囲を制限することもできます(0
)および最大半径(0
).
cv.HoughCircles(srcMat, circlesMat, cv.HOUGH_GRADIENT, 1, 45, 75, 40, 0, 0);
今、私たちは持っている必要があります Mat
円が検出されたオブジェクト。
次に、円を描きます <canvas>
.
ステップ4—円を描く
これで、検出されたすべての円を強調表示できます。 各円の周りに輪郭を描き、ユーザーに見せたいと思います。 OpenCV.jsで円を描くには、中心点と半径が必要です。 これらの値は内部に保存されます circlesMat
、したがって、マトリックスの列をループすることで取得できます。
for (let i = 0; i < circlesMat.cols; ++i) {
// draw circles
}
The circlesMat
を保存します x
と y
中心点と半径の値を順番に。
たとえば、最初の円の場合、次のように値を取得できます。
let x = circlesMat.data32F[0];
let y = circlesMat.data32F[1];
let radius = circlesMat.data32F[2];
各円のすべての値を取得するには、次のようにします。
for (let i = 0; i < circlesMat.cols; ++i) {
let x = circlesMat.data32F[i * 3];
let y = circlesMat.data32F[i * 3 + 1];
let radius = circlesMat.data32F[i * 3 + 2];
// draw circles
}
最後に、これらすべての値を使用して、円の周りに輪郭を描くことができます。
OpenCV.jsで円を描くには、次のものが必要です。
- 目的地
Mat
(ユーザーに表示する画像-displayMat
) - センター
Point
(x値とy値を使用) - 半径値
- スカラー(RGB値の配列)
に渡すことができる追加のパラメータもあります circles
、線の太さなど、この例では 3
:
let center = new cv.Point(x, y);
cv.circle(displayMat, center, radius, [0, 0, 0, 255], 3);
円を描くためのすべてのコードは次のとおりです。
for (let i = 0; i < circlesMat.cols; ++i) {
let x = circlesMat.data32F[i * 3];
let y = circlesMat.data32F[i * 3 + 1];
let radius = circlesMat.data32F[i * 3 + 2];
let center = new cv.Point(x, y);
// draw circles
cv.circle(displayMat, center, radius, [0, 0, 0, 255], 3);
}
すべての円の描画が完了したら displayMat
、ユーザーに表示できます。
cv.imshow('imageCanvas', displayMat);
最後に、クリーンアップすることをお勧めします Mat
不要になったオブジェクト。 これは、メモリの問題を防ぐために行われます。
srcMat.delete();
displayMat.delete();
circlesMat.delete();
すべてをまとめると、円の検出と描画のコードは次のようになります。
// previous code is here
document.getElementById('circlesButton').onclick = function() {
this.disabled = true;
document.body.classList.add('loading');
let srcMat = cv.imread('imageCanvas');
let displayMat = srcMat.clone();
let circlesMat = new cv.Mat();
cv.cvtColor(srcMat, srcMat, cv.COLOR_RGBA2GRAY);
cv.HoughCircles(srcMat, circlesMat, cv.HOUGH_GRADIENT, 1, 45, 75, 40, 0, 0);
for (let i = 0; i < circlesMat.cols; ++i) {
let x = circlesMat.data32F[i * 3];
let y = circlesMat.data32F[i * 3 + 1];
let radius = circlesMat.data32F[i * 3 + 2];
let center = new cv.Point(x, y);
// draw circles
cv.circle(displayMat, center, radius, [0, 0, 0, 255], 3);
}
cv.imshow('imageCanvas', displayMat);
srcMat.delete();
displayMat.delete();
circlesMat.delete();
this.disabled = false;
document.body.classList.remove('loading');
};
これで、画像内の円の周りに円を検出して描画するロジックが追加されました。
ステップ5—画像をダウンロードする
画像が変更された後、ユーザーはそれをダウンロードしたいかもしれません。 これを行うには、ハイパーリンクを index.html
ファイル:
<a href="#" id="downloadButton">Download Image</a>
設定します href
画像のURLと download
画像ファイル名の属性。 の設定 download
属性は、リソースに移動するのではなく、リソースをダウンロードする必要があることをブラウザに示します。 から画像のURLを作成できます <canvas>
関数toDataURL()を使用します。
次のJavaScriptを下部に追加します <script>
:
// previous code is here
document.getElementById('downloadButton').onclick = function() {
this.href = document.getElementById('imageCanvas').toDataURL();
this.download = 'image.png';
};
これで、ユーザーは変更された画像を簡単にダウンロードできます。
結論
円の検出はOpenCVで可能です。 画像の操作に慣れたら、 Mat
オブジェクト、あなたができることはたくさんあります。 The HoughCircles
アルゴリズムは、画像処理と画像認識をはるかに簡単にするためにOpenCVによって提供される多くのアルゴリズムの1つです。
OpenCV Webサイトで、顔認識やテンプレートマッチングなど、その他のチュートリアルを見つけることができます。 機械学習トピックページにアクセスして、コンピュータービジョンの詳細を読むこともできます。