ツナドーナツ・技術メモ帳

色々なものを作る過程で分からなかったことなどを書いていきます

OpenCVできのこの輪郭を取る

OpenCVを使ってキノコのエッジを取っていきます。

OpenCVのバージョン:2.4.13

使う言語:C++

f:id:iwanax:20180113133122j:plainf:id:iwanax:20180113133051j:plain

こんな感じできれいにキノコのエッジを取りたいと思います。

やり方は簡単で、

  1. 画像を読み込む
  2. オープニング処理をする
  3. ガウシアンフィルタをかける
  4. RGBチャンネルごとにCannyでエッジを取る
  5. チャンネルの論理和を取る
  6. 白黒反転(完成!)

やり方は簡単ですが、これを見つけるまでに結構苦労しました(笑)

ソースコード

#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#pragma comment(lib, "opencv_world300d.lib")

int main(int argc, char *argy[]){
	//画像の読み込み
	cv::Mat src_img = cv::imread("C:\\file\\pos\\t_kinoko\\画像ファイル名.jpg");
	
	if (src_img.empty()){
		std::cout << "cannot open file" << std::endl;
		return -1;
	}

	for (int i = 0; i < 2; i++){
		//オープニング
		cv::erode(src_img, src_img, cv::Mat(), cv::Point(-1, -1), 2);
		cv::dilate(src_img, src_img, cv::Mat(), cv::Point(-1, -1), 2);
                //ガウシアンフィルタ
		cv::GaussianBlur(src_img, src_img, cv::Size(9, 7), 10, 10);
	}
	cv::namedWindow("image", CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO);
	cv::imshow("image", src_img);
	cv::waitKey(0);

	cv::Mat channels[3];
        //RGBチャンネルを分割
	cv::split(src_img, channels);
	for (int i = 0; i < 3; i++){
                //Canny処理
		cv::Canny(channels[i], channels[i], 60, 180, 3);
	}
	cv::Mat canny_img;
        //論理和を取る
	cv::bitwise_or(channels[0], channels[1], canny_img);
	cv::bitwise_or(channels[2], canny_img, canny_img);
        //白黒反転
	canny_img = ~canny_img;

	cv::imshow("image", canny_img);
	cv::waitKey(0);

	cv::imwrite("C:\\file\\result\\kinoko1\\保存名.jpg", canny_img);
	return 0;
}

これだけできのこのエッジが取れます。しかし、背景やキノコの種類によってはうまく検出できないことがあります。

なので、ヒストグラムなどを使って収縮・膨張の回数やCannyの閾値の調節ができるような関数を考えないとダメっぽいです。

出来たらブログに書きます。