株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。新規開発案件のご依頼をお待ちしております。

*

OpenCVで輪郭抽出から隣接領域の切り出し(その3)凸包の取得

      2014/12/28

OpenCVで画像内の輪郭抽出からその輪郭の隣接領域(四角形)を求めてその領域を切り出すという処理を作ってみました。前回までのプログラムとほぼ同じですが、前回までは輪郭抽出 → 直線近似 → 隣接領域 の流れでしたが、今回は、輪郭抽出 → 凸包の取得 → 隣接領域を試しました。以下の画像がその結果の例です。(※実画像サイズは大きめです。)

convexhull1

前回までの結果とほぼ同じですが結果の画像の緑の線が輪郭で、青い線が一定以上の面積の輪郭から取り出した凸包です。

「凸包」とはある図形を含む最小の凸図形のことです。以下の図形で青い線です。ここでは輪郭の凸包ですが点集合に対する凸包も定義出来ます。どうやら「輪ゴムで囲うようにぴったりと囲んだ線の図形」という表現をよく使うようです。今回のプログラムでは最終的にこの画面のように凸包に隣接する矩形を取得して切り出します。
0014

このペットボトルの画像で取り出した画像の一部です。
0003

0001

0009

0013

今回のプログラム全体は以下からダウンロード出来ます。(※必要な場合は用途に限らずご利用頂いて問題ありませんが、一切無保証です。弊社は一切の責任を負いません。)
ソース一式(※OpenCVを含むため61M程度のサイズです。)

今回の処理は以下です。ボタンの「凸包取得」での処理です。

/*------------------------------------------------
処理2
-------------------------------------------------*/
void func2(HWND hWnd)
{
	////MessageBox(hWnd, "func1", "debug", MB_OK);
	if (imgMatRead.rows == 0){
		MessageBox(hWnd, "画像ファイルが無効です", "エラー", MB_OK);
		return;
	}

	//入力画像、ここでは毎回ファイルから読み込む
	cv::Mat imgIn = cv::imread((const std::string&)szOpenFileName, 1); //3チャンネルカラー画像で読み込む;

	//グレースケール
	cv::Mat grayImage, binImage;
	cv::cvtColor(imgIn, grayImage, CV_BGR2GRAY);

	//2値化(※反転で結果が変わる、基本は背景が黒で物体が白)
	BOOL bInv = checkInv(hWnd);
	if (bInv){
		cv::threshold(grayImage, binImage, 0.0, 255.0, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
	}
	else{
		cv::threshold(grayImage, binImage, 0.0, 255.0, CV_THRESH_BINARY | CV_THRESH_OTSU);
	}

	//輪郭の座標リスト
	std::vector< std::vector< cv::Point > > contours;

	//輪郭の取得
	////cv::findContours(binImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
	cv::findContours(binImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

	// 検出された輪郭線を緑で描画
	for (auto contour = contours.begin(); contour != contours.end(); contour++){
		cv::polylines(imgIn, *contour, true, cv::Scalar(0, 255, 0), 2);
	}	

	//矩形の数
	int roiCnt = 0;

	//輪郭のカウント
	int i = 0;

	for (auto contour = contours.begin(); contour != contours.end(); contour++){

		std::vector< cv::Point > approx;

		//凸包の取得(頂点はデフォルトの反時計回り)
		cv::convexHull(*contour, approx);

		//凸包の取得面積が一定以上なら取得
		double area = cv::contourArea(approx);

		if (area > 1000.0){
			//青で囲む場合			
			cv::polylines(imgIn, approx, true, cv::Scalar(255, 0, 0), 2);
			std::stringstream sst;
			sst << "area : " << area;
			cv::putText(imgIn, sst.str(), approx[0], CV_FONT_HERSHEY_PLAIN, 1.0, cv::Scalar(0, 128, 0));

			//輪郭に隣接する矩形の取得
			cv::Rect brect = cv::boundingRect(cv::Mat(approx).reshape(2));
			roi[roiCnt] = cv::Mat(imgIn, brect);

			//表示
			cv::imshow("label" + std::to_string(roiCnt + 1), roi[roiCnt]);

			roiCnt++;

			//念のため矩形の数をチェック
			if (roiCnt == 99)
			{
				break;
			}
		}

		i++;
	}

	//全体を表示する場合
	///cv::imshow("coun", imgIn);

	//必要に応じて保存したい画像を設定する
	imgMatWrite = imgIn;
}

今回のポイントの凸包の取得についてだけ書きます。その他は前回までを参照して下さい。

以下が凸包を取得する処理です。
//凸包の取得(頂点はデフォルトの反時計回り)
cv::convexHull(*contour, approx);

convexHullで凸包を取得しますが、ここでは省略してデフォルトになっている3番目のパラメータで頂点の順序を指定します。デフォルトが反時計回りで、3番目にtrueを指定すると時計回りになります。最終的にはこの凸包に隣接する矩形を取得して切り出しています。このあたりは前回と同様です。

このconvexHullでの頂点の回りですが、座標を取得する場合に便利な場合があります。例えば以下のように四角形という前提で座標を取り出す場合、以下のように取り出せました。この処理はプログラムの「凸包で四角形取得」ボタンでの処理です。四角形が認識できる画像で四角形が取得出来ます。
Mat roi= cv::Mat(imgIn, cv::Rect(approx[2].x, approx[2].y, approx[3].x – approx[2].x, approx[0].y – approx[3].y));

最後にまとめ的にですが、前回の輪郭抽出から直線近似、今回の輪郭抽出から凸包取得それぞれ場合によって使いこなしていければというところです。

今回でこのシリーズは終了です。OpenCVについては今後も書きたいと思います。

関連書籍
(※OpenCV 2 プログラミングブックは私も持っています。)

(※ここからはKindle版で英語ですが最新の情報もあるようです。また価格的にはいいかもしれないです。)


 - OpenCV

AdSense

AdSense

  関連記事

OpenCVをWin32ベースで利用する(その5)GUIコントロールの追加

OpenCVをWin32ベースで利用するの5回目です。前回の4回目で一度終了した …

OpenCVをWin32ベースで利用する(その3)カメラ入力からの画像処理

OpenCVをWin32ベースで利用するの3回目です。前回は画像ファイルを入力に …

OpenCVでのORBによる特徴点抽出とマッチング(その1)基本的な使い方

OpenCVでのORBアルゴリズムによる特徴点抽出とマッチングの処理についてです …

OpenCVで背景差分とテスト的な動体検知

OpenCVで背景差分を試してみました。あとテスト的な動体検知も試してみました。 …

NuGetでOpenCVを導入する

Visual Studio Express 2013 for Windows D …

OpenCVで輪郭抽出から隣接領域の切り出し(その2)輪郭の直線近似と切り出し

OpenCVで画像内の輪郭抽出からその輪郭の隣接領域(四角形)を求めてその領域を …

Visual Studio Community 2013のVisual C++でOpenCVを使う

Visual Studio Community 2013のVisual C++で …

OpenCVをWin32ベースで利用する(その1)ダイアログベースアプリ

OpenCVをWin32ベースのアプリケーションで利用してみます。今回はまず、W …

Tesseract-OCRの導入(その3)OpenCVの出力を認識する

Tesseract-OCRの導入の3回目です。前回はvc++のコンソールアプリか …

OpenCVでのORBによる特徴点抽出とマッチング(その2)GUIの利用

OpenCVでのORBアルゴリズムによる特徴点抽出とマッチングの処理についての2 …