開発者ドキュメント

OpenCV.jsを使用したJavaScriptでのコンピュータービジョンの紹介

序章

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 次のテンプレートを使用したファイル:

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> 鬼ごっこ:

index.html
  <script type="text/javascript">
    // Our JavaScript code will go here
  </script>
  <script async src="opencv.js" type="text/javascript"></script>

OpenCV.jsはファイルサイズが原因ですぐに準備ができていない可能性があるため、コンテンツが読み込まれていることを示すことで、より優れたユーザーエクスペリエンスを提供できます。 ページに読み込みスピナーを追加できます(StackOverflowSampsonへのクレジット)。

まず、を追加します <div> エレメント <body>:

index.html
<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;):

index.html
/* 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>.

index.html
document.body.classList.add('loading');

OpenCV.jsが読み込まれると、読み込み中のgifを非表示にする必要があります。 を変更します <script> ローカルを参照するタグ opencv.js 追加するファイル onload イベントリスナー:

index.html
<script async src="opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>

それから加えて onOpenCvReady 他に <script> の削除を処理するタグ "loading" クラス:

index.html
// previous code is here

function onOpenCvReady() {
  document.body.classList.remove('loading');
}

ブラウザでHTMLページを開き、OpenCV.jsが期待どおりに読み込まれることを確認します。

注:ブラウザの開発ツールを使用して、コンソールタブにエラーメッセージが表示されていないこと、およびネットワークタブにエラーメッセージが表示されていることを確認する必要があります。 opencv.js ファイルが正しく参照されています。 最新の変更を表示するために、ブラウザでこのページを定期的に更新します。

プロジェクトを設定したので、画像アップロード機能を構築する準備が整いました。

ステップ2—画像をアップロードする

アップロード機能を作成するには、まず、 <input> 要素に index.html:

index.html
<input type="file" id="fileInput" name="file" />

ソース画像だけを表示したい場合は、 <img> 要素とイベントリスナー。変更に応答します。 <input> エレメント。 次のタグをコピーして、 <input> 鬼ごっこ:

index.html
<img id="imageSrc" alt="No Image" />

両方を取得します <img> 要素と <input> それらを使用する要素 id 値:

index.html
// previous code is here

let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');

次に、イベントリスナーを追加します。これは、 <input> 変更(つまり、ファイルがアップロードされたとき)。 変更イベントから、アップロードされたファイルにアクセスすることができます(event.target.files[0])、 URL.createObjectURL )を使用してURLに変換します。 画像 src 属性は次のURLに更新できます。

index.html
// previous code is here

inputElement.onchange = function() {
  imgElement.src = URL.createObjectURL(event.target.files[0]);
};

元の画像の横に、検出された円を示す2番目の画像を表示できます。 画像はで表示されます <canvas> JavaScriptでグラフィックを描画するために使用される要素:

index.html
<canvas id="imageCanvas"></canvas>

を更新する別のイベントリスナーを追加できます <canvas> アップロードされた画像で:

index.html
// previous code is here

imgElement.onload = function() {
  let image = cv.imread(imgElement);
  cv.imshow('imageCanvas', image);
  image.delete();
};

このステップでは、画像のアップロードと表示の機能を設定しました。 次のステップでは、OpenCVを使用して円を検出する方法を探ります。

ステップ3—サークルの検出

円の検出は組み込みのタスクであるため、ここでOpenCVの能力が明らかになります。 ユーザーがボタンをクリックしたときに円を見つけたいので、ボタンとイベントリスナーを追加する必要があります。

index.html
<button type="button" id="circlesButton" class="btn btn-primary">Circle Detection</button>
index.html
// previous code is here

document.getElementById('circlesButton').onclick = function() {
  // circle detection code
};

画像によっては、円の検出に時間がかかる場合がありますので、ボタンを無効にして、ユーザーが何度もボタンを押さないようにすることをお勧めします。 ボタンにローディングスピナーを表示すると便利な場合もあります。 最初のスクリプトロードからロードgifを再利用できます。

index.html
// 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オブジェクトが必要です。

決勝戦 Mat、を使用して最初のコピーを作成できます clone 関数:

index.html
// circle detection code
let srcMat = cv.imread('imageCanvas');
let displayMat = srcMat.clone();
let circlesMat = new cv.Mat();

The srcMat グレースケールに変換する必要があります。 これにより、画像が単純化され、円の検出が高速化されます。 使用できます cvtColor これを行うための関数。

この関数には次のものが必要です。

index.html
cv.cvtColor(srcMat, srcMat, cv.COLOR_RGBA2GRAY);

The cvtColor 関数は、他のOpenCV.js関数と同様に、より多くのパラメーターを受け入れます。 これらは必須ではないため、デフォルトに設定されます。 より良いカスタマイズについては、ドキュメントを参照してください。

画像がグレースケールに変換されると、 HoughCircles 円を検出する機能。

この関数には次のものが必要です。

より多くのパラメータ、アルゴリズムのしきい値があります(7540)、画像の精度を向上させるために再生できます。

最小値を設定することにより、検出する円の範囲を制限することもできます(0)および最大半径(0).

index.html
cv.HoughCircles(srcMat, circlesMat, cv.HOUGH_GRADIENT, 1, 45, 75, 40, 0, 0);

今、私たちは持っている必要があります Mat 円が検出されたオブジェクト。

次に、円を描きます <canvas>.

ステップ4—円を描く

これで、検出されたすべての円を強調表示できます。 各円の周りに輪郭を描き、ユーザーに見せたいと思います。 OpenCV.jsで円を描くには、中心点と半径が必要です。 これらの値は内部に保存されます circlesMat、したがって、マトリックスの列をループすることで取得できます。

index.html
for (let i = 0; i < circlesMat.cols; ++i) {
  // draw circles
}

The circlesMat を保存します xy 中心点と半径の値を順番に。

たとえば、最初の円の場合、次のように値を取得できます。

let x = circlesMat.data32F[0];
let y = circlesMat.data32F[1];
let radius = circlesMat.data32F[2];

各円のすべての値を取得するには、次のようにします。

index.html
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で円を描くには、次のものが必要です。

に渡すことができる追加のパラメータもあります circles、線の太さなど、この例では 3:

index.html
let center = new cv.Point(x, y);
cv.circle(displayMat, center, radius, [0, 0, 0, 255], 3);

円を描くためのすべてのコードは次のとおりです。

index.html
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、ユーザーに表示できます。

index.html
cv.imshow('imageCanvas', displayMat);

最後に、クリーンアップすることをお勧めします Mat 不要になったオブジェクト。 これは、メモリの問題を防ぐために行われます。

index.html
srcMat.delete();
displayMat.delete();
circlesMat.delete();

すべてをまとめると、円の検出と描画のコードは次のようになります。

index.html
// 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 ファイル:

index.html
<a href="#" id="downloadButton">Download Image</a>

設定します href 画像のURLと download 画像ファイル名の属性。 の設定 download 属性は、リソースに移動するのではなく、リソースをダウンロードする必要があることをブラウザに示します。 から画像のURLを作成できます <canvas> 関数toDataURL()を使用します。

次のJavaScriptを下部に追加します <script>:

index.html
// 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サイトで、顔認識やテンプレートマッチングなど、その他のチュートリアルを見つけることができます。 機械学習トピックページにアクセスして、コンピュータービジョンの詳細を読むこともできます。

モバイルバージョンを終了