《数字图像处理》笔记代码

11 篇文章 0 订阅

做了以下几部分:

  1. 根据比特位进行图像的分层;
  2. 灰度图的均衡化;
  3. 平滑滤波;
  4. 中值滤波;
  5. Laplace锐化;
  6. Soble滤波。
  7. 形态学操作:
并实现了通常的掩模滤波的类,参考平滑滤波、中值滤波、Laplace、Sobel可以轻易的使用其它类型的滤波器。



以下为代码:
//============================================================================
// Name        : Test.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <string>
#include <vector>
#include <iostream>
#include <iterator>
#include <sstream>
#include <ctime>
using namespace std;

#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>
#include <opencv2/legacy/legacy.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
using namespace cv;


/*!
 * 通过对灰度值根据某一比特位上的值进行分层
 */
void ReadBook3_2_4() {
  cv::Mat img = cv::imread("/home/chuanqi/13.jpg", 0);
  cv::imshow("origin", img);
  cv::Mat img_splited[8];
  for (int i = 0; i < 8; ++i) {
    img_splited[i] = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
  }
  for (int i = 0; i < img.rows; ++i) {
    for (int j = 0; j < img.cols; ++j) {
      char value = img.at<uchar>(i, j);
      for (int k = 0; k < 8; ++k) {
        if (value & (1 << k)) {
          img_splited[k].at<uchar>(i, j) = 255;
        } else {
          img_splited[k].at<uchar>(i, j) = 0;
        }
      }
    }
  }

  for (int i = 0; i < 8; ++i) {
    cv::imshow("channel_" + boost::lexical_cast<string>(i), img_splited[i]);
    cout << i << ",";
  }
  cv::waitKey();
}

/*!
 * 灰度图的均衡化
 */
void ReadBook3_3_1() {
  cv::Mat img = cv::imread("/home/chuanqi/13.jpg", 0);
  cv::imshow("origin", img);
  cv::Mat img2 = img.clone();
  cv::equalizeHist(img2, img2);
  cv::imshow("equalized by opencv", img2);

  double hist[256];
  for (int i = 0; i < 256; ++i) {
    hist[i] = 0;
  }
  for (int i = 0; i < img.rows; ++i) {
    for (int j = 0; j < img.cols; ++j) {
      ++hist[img.at<uchar>(i, j)];
    }
  }
  for (int i = 0; i < 256; ++i) {
    hist[i] /= (img.rows * img.cols);
    hist[i] *= 255;
  }

  for (int i = 0; i < img.rows; ++i) {
    for (int j = 0; j < img.cols; ++j) {
      uchar &value = img.at<uchar>(i, j);
      double sum = 0;
      for (int i = 0; i < value; ++i) {
        sum += hist[i];
      }
      value = sum;
    }
  }

  cv::imshow("equalized by self", img);
  cv::waitKey();
}



/*!
 * 空间域滤波器
 */
class SpaceFilter {
public:
  /*!
   * 响应计算算法的抽象基类
   */
  class ResponseCalculatorBase {
  public:
    virtual ~ResponseCalculatorBase() {}
    virtual int CalculateResponse(vector<vector<int> > const &filter, vector<vector<int> > const &f) const = 0;
  };
  /*!
   * 普通模板滤波器的响应计算算法
   */
  class CommonResponseCaclulator: public ResponseCalculatorBase {
  public:
    explicit CommonResponseCaclulator(double divider) : divider_(divider) {
      if (divider_ == 0) {
        throw runtime_error("divider cannot be 0!");
      }
    }

    virtual int CalculateResponse(vector<vector<int> > const &filter, vector<vector<int> > const &f) const {
      int sum = 0;
      for (size_t i = 0; i < f.size(); ++i) {
        for (size_t j = 0; j < f[0].size(); ++j) {
          sum += (filter[i][j] * f[i][j]);
        }
      }
      sum /= divider_;
      //必须归一化到0-255之间去
      if(sum < 0) sum = 0;
      if(sum > 255) sum = 255;
      return  sum;
    }

  private:
    double divider_;
  };

  SpaceFilter(cv::Mat &image, vector<vector<int> > const &filter, ResponseCalculatorBase const &valuer)
      : image_(image), filter_(filter), valuer_(valuer) {
    if (filter_.size() % 2 != 1 || filter_[0].size() % 2 != 1) {
      throw runtime_error("filter must be odd!");
    }
  }

  cv::Mat DoFilte() {
    cv::Mat filted_image = image_.clone();
    int filter_m = filter_.size();
    int filter_n = filter_[0].size();
    vector<vector<int> > v(filter_m, vector<int>(filter_n));

    for (int i = 0; i < image_.rows; ++i) {
      for (int j = 0; j < image_.cols; ++j) {
        for (int m = 0; m < filter_m; ++m) {
          int indexi = i - filter_m / 2 + m;
          indexi = indexi > 0 ? indexi : 0;
          indexi = indexi < image_.rows ? indexi : image_.rows;

          for (int n = 0; n < filter_n; ++n) {
            int indexj = j - filter_n / 2 + n;
            indexj = indexj > 0 ? indexj : 0;
            indexj = indexj < image_.cols ? indexj : image_.cols;

            v[m][n] = image_.at<uchar>(indexi, indexj);
          }
        }
        filted_image.at<uchar>(i, j) = valuer_.CalculateResponse(filter_, v);
      }
    }
    return filted_image;
  }

private:
  cv::Mat                     &image_;
  vector<vector<int> > const  &filter_;
  ResponseCalculatorBase const      &valuer_;
};

/*!
 * 平滑滤波
 */
void ReadBook3_6_1() {
  cv::Mat img = cv::imread("/home/chuanqi/Noise.jpg", 0);
  cv::imshow("origin", img);
  /* 滤波器模板如下:
   * 1 2 1
   * 2 4 2
   * 1 2 1
   */
  vector<vector<int> > templates(3, vector<int>(3, 1));
  templates[0][1] = templates[1][0] = templates[1][2] = templates[2][1] = 2;
  templates[1][1] = 4;
  SpaceFilter::CommonResponseCaclulator valuer(16);
  SpaceFilter filter(img, templates, valuer);
  cv::imshow("smooth filted", filter.DoFilte());
  cv::waitKey();
}

/*!
 * 中值滤波
 */
void ReadBook3_6_2() {
  /*!
   * 中值滤波器计算响应的算法,与普通的模板计算响应有些不同
   */
  class MedianFilterValuer: public SpaceFilter::ResponseCalculatorBase {
  public:
    virtual int CalculateResponse(vector<vector<int> > const &filter, vector<vector<int> > const &f) const {
      vector<int> values;
      for (size_t i = 0; i < f.size(); ++i) {
        for (size_t j = 0; j < f[0].size(); ++j) {
          values.push_back(f[i][j]);
        }
      }
      sort(values.begin(), values.end());
      return values[values.size() / 2];
    }
  };

  cv::Mat img = cv::imread("/home/chuanqi/Noise.jpg", 0);
  cv::imshow("origin", img);
  MedianFilterValuer valuer;
  vector<vector<int> > templates(3, vector<int>(3, 1));
  SpaceFilter filter(img, templates, valuer);
  cv::imshow("median filted", filter.DoFilte());
  cv::waitKey();
}

/*!
 * 拉普拉斯锐化
 */
void ReadBook3_7_2(){
  cv::Mat img = cv::imread("/home/chuanqi/moon.png", 0);
  cv::imshow("origin", img);
  /* 滤波器模板如下:
   * 0  -1   0
   * -1  5  -1
   * 0  -1   0
   */
  vector<vector<int> > templates(3, vector<int>(3, 0));
  templates[0][0] = 0; templates[0][1] = -1;  templates[0][2] = 0;
  templates[1][0] = -1; templates[1][1] = 5;  templates[1][2] = -1;
  templates[2][0] = 0;  templates[2][1] = -1;  templates[2][2] = 0;
  SpaceFilter::CommonResponseCaclulator valuer(1);
  SpaceFilter filter(img, templates, valuer);
  cv::imshow("Laplace filted", filter.DoFilte());
  cv::waitKey();
}
/*!
 * Sobel滤波
 */
void ReadBook3_7_3(){
  cv::Mat img = cv::imread("/home/chuanqi/moon.png", 0);
  cv::imshow("origin", img);
  /* 滤波器模板如下:
   * -1  -2  -1
   *  0   2   0
   *  1   2   1
   */
  vector<vector<int> > templates(3, vector<int>(3, 0));
  templates[0][0] = -1; templates[0][1] = -2;  templates[0][2] = -1;
  templates[1][0] = 0; templates[1][1] = 0;  templates[1][2] = 0;
  templates[2][0] = 1;  templates[2][1] = 2;  templates[2][2] = 1;
  SpaceFilter::CommonResponseCaclulator valuer(1);
  SpaceFilter filter(img, templates, valuer);
  cv::imshow("Sobel filted", filter.DoFilte());
  cv::waitKey();
}


以下为效果图:






  cv::Mat img = cv::imread("/home/chuanqi/ImageDataset/13.jpg");
  cv::imshow("origin", img);
  cv::cvtColor(img, img, CV_BGR2HSV);
  vector<cv::Mat> splited(3);
  splited[0] = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
  splited[1] = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
  splited[2] = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
  cv::split(img, splited);
  cv::equalizeHist(splited[0], splited[0]);
  cv::equalizeHist(splited[1], splited[1]);
  cv::equalizeHist(splited[2], splited[2]);
  cv::merge(splited, img);
  cv::cvtColor(img, img, CV_HSV2BGR);
  cv::imshow("abc", img);
  cv::waitKey();





/*
 * 形态学学习
 */
int main(){

  string const img_path = "/home/chuanqi/ImageDataset/13.jpg";
  cv::Mat const img = cv::imread(img_path, 0);
  cv::imshow("origin", img);

  //腐蚀
  cv::Mat img_erode;
  int  erosion_size = 1;
  cv::Mat erosion_element = cv::getStructuringElement( MORPH_RECT,
                                                       cv::Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                                       cv::Point( erosion_size, erosion_size ) );
  cv::erode(img, img_erode, erosion_element);
  cv::imshow("erode", img_erode);

  //膨胀
  cv::Mat img_dilate;
  int  dilation_size = 2;
  cv::Mat dilation_element = cv::getStructuringElement( MORPH_RECT,
                                                        cv::Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                                                        cv::Point( dilation_size, dilation_size ) );
  cv::dilate(img, img_dilate, dilation_element);
  cv::imshow("dilate", img_dilate);

  //基础形态学操作
  string morphology_operation_name[] = {"ERODE","DILATE","OPEN","CLOSE","GRADIENT","TOPHAT","BLACKHAT"};
  int morph_size = 1;   //采用 2×1+1=3 为大小的核
  Mat element = getStructuringElement( MORPH_RECT, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size));
  for (int operation = 0; operation < 7; ++operation) {
    cv::Mat img_morphology_result;
    cv::morphologyEx(img, img_morphology_result, operation, element);
    cv::imshow(morphology_operation_name[operation], img_morphology_result);
  }

  cv::waitKey();

}

因为在灰度图上操作时,形态学的两个基本操作膨胀和腐蚀采用了取最大最小值的方式,所以使得:
形态学操作在灰度图上结果的局部方块性太严重了,因此说形态学还是更适合于二值图像,对灰度图像起的效果并不是很明显。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值