見出し画像

画像処理、ノイズの除去

画像処理の勉強の為、画像処理の書籍資料を参考にして、実際にソフトウエアを作成し実験してみた。今回は画像に混入したノイズの除去を行う。

①9画素の平均化でノイズ除去(移動平均フィルタ)
以下の書籍を参考にさせていただいた。
・はじめてのデジタル画像処理 P49
・インターフェース2017/05 P58
下の図の様に元画像を計算して新しく作成した画像の画素の濃度を決める。
新しい画像の画素E'は、元画像Eとその周辺の画素との平均値から求める。

計算方法

画像の素材はここからダウンロードさせていただいた。
これをグレースケールに変換した物が以下の画像。

画像1 ダウンロードさせていただいた画像をグレースケールに変換

このサイトにてノイズを混入させていただいた。

画像2 ノイズを混入させた画像

これを平均化処理をするソフトウエアを作成して加工を行った。
加工したのが以下の画像。濁った様な画像になってしまった。

画像3 平均化処理を加えた画像

以下が平均化処理行ったソフトウエアです。
C++で記述、画像を扱う為OpenCVを使用。
平均化処理は画像処理の勉強の為、資料を参考にして記述している。
ファイルのパスの指定は自分の環境のままですので、参考にされる場合は書き換えて下さい。

#include <opencv2/opencv.hpp>

int main()
{
  // 加工前の画像読み込み
  cv::Mat image = cv::imread("D:/PROG_WK/VisualStudio2022_WK/Project/100_OpenCV/11_NOISE_CUT_01/NOISE_GRY.jpg", cv::IMREAD_COLOR);  // グレースケールファイルを用意カラーで読む
  int x_max = image.cols;
  int y_max = image.rows;

  //空の画像生成
  cv::Mat image2 = cv::Mat::zeros(cv::Size(x_max, y_max), CV_8UC3);

  // 元画像の平均化して加工画像へ代入(9画素平均)
  for (int y = 0; y_max > y; y++) {               // y方向のループ
    cv::Vec3b* dst = image2.ptr<cv::Vec3b>(y);      // 加工画像y行目の先頭画素のポインタを取得
    for (int x = 0; x_max > x; x++) {               // x方向のループ
      int cnt = 0, dt = 0;
      for (int y0 = y - 1; y0 <= y + 1; y0++) {
        for (int x0 = x - 1; x0 <= x + 1; x0++) {
          if (0 <= y0 && y0 < y_max && 0 <= x0 && x0 < x_max) {
            cv::Vec3b* src = image.ptr<cv::Vec3b>(y0);
            cv::Vec3b pix = src[x0];
            dt += pix[1];  cnt++;
          }
        }
      }
      int gray_dt = dt / cnt;
      dst[x] = cv::Vec3b(gray_dt, gray_dt, gray_dt);                  // B, G, R
    }
  }
  // 表示、保存
  cv::imshow("", image2);
  cv::imwrite("D:/PROG_WK/VisualStudio2022_WK/Project/100_OpenCV/11_NOISE_CUT_01/NOISE_CUT_01_GRY.jpg", image2);   // JPEGフォーマットで保存

  cv::waitKey(0);  // グラフィック表示ウィンドウ上でキークリック
  cv::destroyAllWindows();
}

②9画素の中央の値を選択してノイズ除去(メディアンフィルタ)
以下の書籍を参考にさせていただいた。
・はじめてのデジタル画像処理 P51
・インターフェース2017/05 P59
下の図の様に元画像を計算して新しく作成した画像の画素の濃度を決める。
新しい画像の画素E'は、元画像Eとその周辺の画素との全て参照して濃度順に並べて列の中央の値をE'に採用する。

計算方法

画像2のノイズを混入した画像を中央値選択処理をするソフトウエアを作成して加工を行った。加工したのが以下の画像。ノイズは残ってしまった。

画像4 中央値選択処理を加えた画像

以下が中央値選択処理行ったソフトウエアです。
C++で記述、画像を扱う為OpenCVを使用。
中央値選択処理は画像処理の勉強の為、資料を参考にして記述している。
C++のソート機能を使っていますが、今回は、ソートの勉強では無い為使用した。
ファイルのパスの指定は自分の環境のままですので、参考にされる場合は書き換えて下さい。

#include <opencv2/opencv.hpp>
#include<algorithm>             // sort()

int main()
{
  // 加工前の画像読み込み
  cv::Mat image = cv::imread("D:/PROG_WK/VisualStudio2022_WK/Project/100_OpenCV/12_NOISE_CUT_02/NOISE_GRY.jpg", cv::IMREAD_COLOR);  // グレースケールファイルを用意カラーで読む
  int x_max = image.cols;
  int y_max = image.rows;

  //空の画像生成
  cv::Mat image2 = cv::Mat::zeros(cv::Size(x_max, y_max), CV_8UC3);

  // 9画素の中央の値を選択してノイズ除去(メディアンフィルタ)
  for (int y = 0; y_max > y; y++) {               // y方向のループ
    cv::Vec3b* dst = image2.ptr<cv::Vec3b>(y);      // 加工画像y行目の先頭画素のポインタを取得
    for (int x = 0; x_max > x; x++) {               // x方向のループ
      int cnt = 0;
      int arr[9];
      for (int y0 = y - 1; y0 <= y + 1; y0++) {
        for (int x0 = x - 1; x0 <= x + 1; x0++) {
          if (0 <= y0 && y0 < y_max && 0 <= x0 && x0 < x_max) {
            cv::Vec3b* src = image.ptr<cv::Vec3b>(y0);
            cv::Vec3b pix = src[x0];
            arr[cnt++]= pix[1];
          }
        }
      }
      std::sort(arr, arr + cnt);                      // 配列のソート
      int gray_dt = arr[cnt / 2 + cnt % 2];           // 中間くらいの値を読み取り
      dst[x] = cv::Vec3b(gray_dt, gray_dt, gray_dt);  // B, G, R
    }
  }
  // 表示、保存
  cv::imshow("", image2);
  cv::imwrite("D:/PROG_WK/VisualStudio2022_WK/Project/100_OpenCV/12_NOISE_CUT_02/NOISE_CUT_02_GRY.jpg", image2);   // JPEGフォーマットで保存

  cv::waitKey(0);  // グラフィック表示ウィンドウ上でキークリック
  cv::destroyAllWindows();
}

今回は以上です。

この記事が気に入ったらサポートをしてみませんか?