RobotVision勉強会6:ノイズ除去

RobotVision勉強会第6回の内容メモです。開発環境はUbuntu16.04、OpenCV3.2.0です。第6回は膨張、収縮を使ったノイズ除去です。これはとても良く使います。C++言語とOpenCV APIで実装しましょう。

以下のサンプルプログラムは「OpenCVによる画像処理入門、小枝、上田、中村著、講談社」のサンプルコードを参考に作成しました。

1.サンプルコード

/ Robot Vision勉強会 sample6.cpp
// 2017-11-30
// フィルタ処理のサンプルプログラム 

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

// 膨張(4近傍)
void myDilate(cv::Mat img_src, cv::Mat& img_dst)
{
  int height = img_src.rows;       // 画像の高さ[pixel]
  int width  = img_src.cols;       // 画像の幅[pixel] 
  
  for (int y =1; y < height-1; y++) {
    for (int x = 1; x < width-1; x++) {
      if ((img_src.data[y * width + x] == 255)
	  || (img_src.data[y * width + (x-1)] == 255)
	  || (img_src.data[y * width + (x+1)] == 255)
	  || (img_src.data[(y-1) * width + x] == 255) 
	  || (img_src.data[(y+1) * width + x] == 255)) {
	img_dst.data[y * width + x] = 255;
      }
      else {
	img_dst.data[y * width + x] = 0;
      }
    }
  }
}


// 収縮(4近傍)
void myErode(cv::Mat img_src, cv::Mat& img_dst)
{
  int height = img_src.rows;       // 画像の高さ[pixel]
  int width  = img_src.cols;       // 画像の幅[pixel]

  for (int y =1; y < height-1; y++) {
    for (int x = 1; x < width-1; x++) {
      if ((img_src.data[y * width + x] == 0)
	  || (img_src.data[y * width + (x-1)] == 0)
	  || (img_src.data[y * width + (x+1)] == 0)
	  || (img_src.data[(y-1) * width + x] == 0)
	  || (img_src.data[(y+1) * width + x] == 0)) {
	img_dst.data[y * width + x] = 0;
      }
      else {
	img_dst.data[y * width + x] = 255;
      }
    }
  }
}

int main()
{
  cv::Mat src;

  std::string WINDOW_NAME_ORG        = "Original image";
  std::string WINDOW_NAME_BINARY     = "Binary image";
  std::string WINDOW_NAME_DILATE     = "Dilate";
  std::string WINDOW_NAME_ERODE      = "Erode";
  std::string WINDOW_NAME_MY_DILATE  = "My Dilate";
  std::string WINDOW_NAME_MY_ERODE   = "My Erode";
  
  
  // 画像のロード
  src = cv::imread("winkit2.jpg", cv::IMREAD_COLOR);
  if(src.empty()) {
    std::cerr << "Failed to open image file." << std::endl;
    return -1;
  }

  int height = src.rows;       // 画像の高さ[pixel]
  int width  = src.cols;       // 画像の幅[pixel]
  int step   = src.step;       // 1行のチャンネル総数
  int c      = src.channels(); // チャンネル数   

  cv::Mat tmp = src.clone();
  cv::Mat gray_img, binary_img;
  
  // ウィンドウの生成
  cv::namedWindow(WINDOW_NAME_ORG,       CV_WINDOW_AUTOSIZE);
  cv::namedWindow(WINDOW_NAME_BINARY,    CV_WINDOW_AUTOSIZE);
  cv::namedWindow(WINDOW_NAME_DILATE,    CV_WINDOW_AUTOSIZE);
  cv::namedWindow(WINDOW_NAME_MY_DILATE, CV_WINDOW_AUTOSIZE);
  cv::namedWindow(WINDOW_NAME_ERODE,     CV_WINDOW_AUTOSIZE);
  cv::namedWindow(WINDOW_NAME_MY_ERODE,  CV_WINDOW_AUTOSIZE);

  
  while (true){
    src.copyTo(tmp);
    cvtColor(tmp, gray_img, CV_BGR2GRAY);

    // 2値化
    int thresh = 200;
    //cv::threshold(gray_img, binary_img, thresh, 255, cv::THRESH_BINARY);
    cv::threshold(gray_img, binary_img, 0, 255, cv::THRESH_BINARY| cv::THRESH_OTSU);
    cv::imshow(WINDOW_NAME_BINARY, binary_img);

    cv::Mat dilate_img;
    cv::Mat erode_img;  
    cv::Mat my_dilate_img  = cv::Mat::zeros(height, width, CV_8U);
    cv::Mat my_erode_img   = cv::Mat::zeros(height, width, CV_8U);
    cv::Mat element4 = (cv::Mat_<uchar>(3,3) << 0,1,0,1,1,1,0,1,0);
    cv::dilate(binary_img, dilate_img, element4, cv::Point(-1,-1), 1);
    cv::erode(binary_img,  erode_img,  element4, cv::Point(-1,-1), 1);
    
    myDilate(binary_img, my_dilate_img);
    myErode(binary_img, my_erode_img);

    cv::imshow(WINDOW_NAME_ORG, tmp);
    cv::imshow(WINDOW_NAME_DILATE,    dilate_img);
    cv::imshow(WINDOW_NAME_MY_DILATE, my_dilate_img);
    cv::imshow(WINDOW_NAME_ERODE,     erode_img);
    cv::imshow(WINDOW_NAME_MY_ERODE,  my_erode_img);
    
    cv::waitKey(1);
  }
  return 0;
}

2.ハンズオン

(1) このソースコードsample6.tgzをダウンロードして次のコマンドで解凍、コンパイルして実行しよう。

$ tar xvzf sample6.tgz
$ cd sample6
$ cmake .
$ make
./sample6

(2) 膨張を何回か繰り返したあとで、収縮をその回数だけ繰り返す処理をクロージング、収縮を何回か繰り返したあとで、膨張をその回数だけ繰り返す処理をオープニングといいます。それぞれ実装してみよう。

(3) 白黒画像を入手して、それにノイズをランダムに1000点加えるプログラムを作り、ノイズの載った画像にオープニングとクロージングの処理を適用してノイズを除去してみよう。

コメントを残す

メールアドレスが公開されることはありません。