null product's blog

Androidアプリ開発のノウハウ集

【Androidアプリ開発】OpenCVで画像から四角形を抽出するコツ

上記の記事では、Bitmap形式画像から四角形を認識し、その4点の座標数値を抽出する手法を説明しました。

今回の記事では、画像から四角形を抽出するコツを説明します。

今回のコツを取り入れることで、次の結果のように、綺麗に四角形を抽出できるようになります。

f:id:null-product:20170507203431p:plain

 

今回も、Androidアプリ【付箋カメラ】で使用している、実際の手法となります。

 

前準備

割愛します。(下記参照)

【Androidアプリ開発】OpenCVでBitmapから四角形を抽出するサンプル - null product's blog

 

ソースコード

割愛します。(下記参照)

【Androidアプリ開発】OpenCVでBitmapから四角形を抽出するサンプル - null product's blog

 

説明

今回は、ソースコード中の以下の関数の処理について説明します。

 ・getContour()

輪郭抽出の核となる関数です。

サンプルのソースコードでは、各チャネルに分離した二値画像と、最終的に合成した二値画像に対してこの関数を実行し、それぞれの輪郭情報を抽出していきます。

 

/* 二値画像中の輪郭を検出 */
List tmp_contours = new ArrayList();
Mat hierarchy = Mat.zeros(new Size(5, 5), CvType.CV_8UC1);
Imgproc.findContours(mat, tmp_contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_TC89_L1);

関数の引数となる二値画像データ(mat)から輪郭情報を抽出します。

輪郭の抽出には、OpenCVライブラリの「Imgproc.findContours()」関数を使用します。

 

if (Imgproc.contourArea(tmp_contours.get(i)) < mat.size().area() / (100 * 1)) {
    /* サイズが小さいエリアは無視 */
    continue;
}

輪郭のサイズが小さいエリアは無視することで、ノイズとなるデータを破棄します。

輪郭のサイズを取得するには、OpenCVライブラリの「Imgproc.contourArea()」関数を使用します。

上記の「100 * 1」は調整値なので、それぞれのアプリで変更すると良いでしょう。

上記を実施しない場合は、次の結果のようにノイズが残った状態となります。

f:id:null-product:20170507234707p:plain

 

/* 輪郭線の周囲長を取得 */
double arclen = Imgproc.arcLength(ptmat2, true);
/* 直線近似 */
Imgproc.approxPolyDP(ptmat2, approx, 0.02 * arclen, true);

 輪郭データの凸凹を無くす(頂点数を減らす)為に、OpenCVライブラリの「Imgproc.approxPolyDP()」関数を使用します。

また、近似精度として輪郭の周囲長を使用する為に、「Imgproc.arcLength()」関数を使用します。

なお、「0.02」は調整値なので、それぞれのアプリで変更すると良いでしょう。

 

if (approxf1.size().area() != 4) {
    /* 四角形以外は無視 */
    continue;
}

四角形(頂点数が4)以外のデータを無視するようにします。

上記を実施しない場合は、次の結果のように四角形以外のデータまで抽出してしまいます。

もし、四角形以外の輪郭を抽出したい場合は、「!= 4」部分を変更すると良いでしょう。

f:id:null-product:20170508001616p:plain

 

/* 輪郭情報を登録 */
contour.add(approxf1);

最後に、戻り値用の配列データに輪郭情報を登録します。