使用OpenCV进行平均过滤

时间:2018-01-24 00:47:37

标签: c++ opencv

我试图用5x5内核实现一个Averaging过滤器,虽然在OpenCV中有一个功能,但我需要在没有它的情况下完成它。 有一些错误,我认为这是变量uchar,但我尝试了int,float和double,图像导致它不正确。我使用填充为7的图像。

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include "filter.h"
#include <iostream>
#include <fstream>

using namespace std;
using namespace cv;

cv::Mat filter::mean_filter(cv::Mat& image_in){
    int centro = 7;
    float total = 0.0;
    double window[25];
    double mean= 0.0;
    int final=0;
    int nlines, ncols;


    cv::Mat kernel = cv::Mat::ones(5, 5, CV_32S);
    nlines=image_in.size().height;
    ncols=image_in.size().width;

    cv::Mat image_out = cv::Mat::zeros(nlines,ncols,CV_32S);

    for (unsigned int j=centro; j<nlines - centro; j++){
        for (unsigned int z=centro; z<ncols - centro; z++){
            window[0]=image_in.at<uchar>(j-2,z-2);
            window[1]=image_in.at<uchar>(j-1,z-2);
            window[2]=image_in.at<uchar>(j  ,z-2);
            window[3]=image_in.at<uchar>(j+1,z-2);
            window[4]=image_in.at<uchar>(j+2,z-2);
            window[5]=image_in.at<uchar>(j-2,z-1);
            window[6]=image_in.at<uchar>(j-1,z-1);
            window[7]=image_in.at<uchar>(j  ,z-1);
            window[8]=image_in.at<uchar>(j+1,z-1);
            window[9]=image_in.at<uchar>(j+2,z-1);
            window[10]=image_in.at<uchar>(j-2,z);
            window[11]=image_in.at<uchar>(j-1,z);
            window[12]=image_in.at<uchar>(j  ,z);
            window[13]=image_in.at<uchar>(j+1,z);
            window[14]=image_in.at<uchar>(j+2,z);
            window[15]=image_in.at<uchar>(j-2,z+2);
            window[16]=image_in.at<uchar>(j-1,z+2);
            window[17]=image_in.at<uchar>(j  ,z+2);
            window[18]=image_in.at<uchar>(j+1,z+2);
            window[19]=image_in.at<uchar>(j+2,z+2);
            window[20]=image_in.at<uchar>(j-2,z+1);
            window[21]=image_in.at<uchar>(j-1,z+1);
            window[22]=image_in.at<uchar>(j  ,z+1);
            window[23]=image_in.at<uchar>(j+1,z+1);
            window[24]=image_in.at<uchar>(j+2,z+1);
            mean=0.0;
            final=0;

            for (unsigned int k=0; k<25; k++){      
                mean+=window[k];    
            }
            mean=mean/25;   
            final=round(mean);
            image_out.at<int>(j,z)=final;
        }
    }
return image_out;
}

1 个答案:

答案 0 :(得分:1)

我稍微改变了你的代码,并找到了一个有效的解决方案。这是一种非常原始的方法,但它有效。

可能的改进可能是通过跟踪哪些像素离开内核区域以及哪些像素进入它来重用一些已经累积的像素值。 另一种改进的可能性是将循环并行化在图像上。

cv::Mat mean_filter(cv::Mat& image_in, int kernel)
{
  // Make sure you get a grayscale image.
  assert(image_in.type() == CV_8UC1);
  // Make sure your kernel is an uneven number
  assert(kernel % 2 == 1);
  // Make sure your kernel is bigger than 1
  assert(kernel >= 1);

  // for padding calculate the border needed
  int padding = (kernel - 1) / 2;

  int mean = 0.0;
  int final = 0;
  int nlines, ncols;
  cv::Mat img_temp;

  nlines = image_in.size().height;
  ncols = image_in.size().width;

  // Make propper padding. Here it is done with 0. Padding describes the adding of a border to the image in order to avoid a cropping by applying a filter-mask.
  copyMakeBorder(image_in, img_temp, padding, padding, padding, padding, BORDER_CONSTANT, 0);

  // allocate the output image as grayscale as the input is grayscale as well
  cv::Mat image_out = cv::Mat::zeros(nlines, ncols, CV_8UC1);

  // loop over whole image
  for (unsigned int j = padding; j<nlines + padding; j++){
    for (unsigned int z = padding; z<ncols + padding; z++){
      mean = 0.0;
      // loop over kernel area
      for (int x = -padding; x <= padding; x++){
        for (int y = -padding; y <= padding; y++){
          // accumulate all pixel-values
          mean += img_temp.at<uchar>(j + x, z + y);
        }
      }

      mean = mean / (kernel * kernel);
      final = round(mean);
      // cast result to uchar and set pixel in output image
      image_out.at<uchar>(j - padding, z - padding) = (uchar)final;
    }
  }

  return image_out;
}