【问题标题】:Sharp transition at borders when doing Gaussian Convolution (2d)进行高斯卷积(2d)时边界处的急剧过渡
【发布时间】:2015-08-04 20:49:00
【问题描述】:

我正在尝试使用高斯 2D 卷积来模糊矩阵。 但我在边界元素处出现了急剧的过渡。

这是我正在运行的一段代码:

// create 1D Kernel
void createGaussianKerenel_1D() {
    unsigned kernelSize = 2 * kernelRad_ + 1;
    gaussian1Dkernel_ = vector<double>(kernelSize);
    double sigma = (double)kernelRad_;

    double sum = 0.0;
    for(unsigned i = 0; i < kernelSize; ++i) {
        gaussian1Dkernel_[i] = gaussian(i, sigma);
        sum += gaussian1Dkernel_[i];
    }

    // normalize
    for(unsigned i = 0; i < kernelSize; ++i) {
        gaussian1Dkernel_[i] /= sum;
        cout << gaussian1Dkernel_[i] << endl;
    }
}

// gaussian function
double gaussian(unsigned int i, double sigma) const {
    double x = ((double)i - (double)kernelRad_) / sigma;

    return exp(-x * x / 2);
}

// do Separable 2D Convolution (in place)
// my initialMatrix_ is of yn_ x xn_ size
void getBlurredThermalMap() {
    assert(!gaussian1Dkernel_.empty());
    vector<vector<double> > tmpMatrix(yn_);
    unsigned kernelSize = 2 * kernelRad_ + 1;

    // in x direction
    for(unsigned i = 0; i < yn_; ++i) {
        for(unsigned j = 0; j < xn_; ++j) {
            double approxVal = 0.0;
            for(unsigned row = 0; row < kernelSize; ++row) {
                unsigned neighbor_j = j + row - kernelRad_;
                // ignore values that are out of bound
                if(neighbor_j >= 0 && neighbor_j < xn_) {
                    approxVal += initialMatrix_[i][neighbor_j] * gaussian1Dkernel_[row];
                }
            }
            tmpMatrix[i].push_back(approxVal);
        }
    }

    // in y direction
    for(unsigned j = 0; j < xn_; ++j) {
        for(unsigned i = 0; i < yn_; ++i) {
            double approxVal = 0.0;
            for(unsigned col = 0; col < kernelSize; ++col) {
                unsigned neighbor_i = i + col - kernelRad_;
                if(neighbor_i >= 0 && neighbor_i < yn_) {
                    approxVal += tmpMatrix[neighbor_i][j] * gaussian1Dkernel_[col];
                }
            }
            initialMatrix_[i][j] = approxVal;
        }
    }
}

即,我对边界元素使用相同的内核。 我已经在 100x100 矩阵和 2 半径的内核上测试了这段代码。 而且,例如,我在 1,97 和 2,97 的元素之间有很大的差异,尽管在那个位置的初始矩阵中没有明显的过渡。

在计算边界元素的近似值时,也许我需要更改内核?

提前致谢。

【问题讨论】:

    标签: c++ gaussian convolution


    【解决方案1】:

    这可能是因为您没有正确处理边界条件。在你的测试中:

    if(neighbor_i >= 0 && neighbor_i < yn_)
    

    第一部分总是正确的,因为neighbor_iunsigned,因此总是正数。您可能希望将其更改为有符号值,稍微修改其声明。您的编译器可以使用适当的警告标志为您检查此类错误(尝试-Wall -Wextra)。

    编辑: 实际上,测试可能不是您的问题的原因,因为您使用的图像相对较小,因此在尝试存储时neighbor_i 的值大于yn_里面有一个负值。

    另外,请使用库来进行卷积。特别是对高斯模糊有非常好的和有效的近似(Canny-Deriche,傅里叶域中的乘积,...)。

    【讨论】:

      【解决方案2】:

      我解决了这个问题如下:

      不要在 createGaussianKerenel_1D() 函数中规范化内核。 相反,请在 getBlurredThermalMap() 函数中执行,如下所示:

      void getBlurredThermalMap() {
          assert(!gaussian1Dkernel_.empty());
          vector<vector<double> > tmpMatrix(yn_);
          unsigned kernelSize = 2 * kernelRad_ + 1;
      
          // in x direction
          for(unsigned i = 0; i < yn_; ++i) {
              for(unsigned j = 0; j < xn_; ++j) {
                  double approxVal = 0.0;
                  double sumNorm = 0.0;
                  for(unsigned row = 0; row < kernelSize; ++row) {
                      unsigned neighbor_j = j + row - kernelRad_;
                      // ignore values that are out of bound
                      if(neighbor_j >= 0 && neighbor_j < xn_) {
                          approxVal += initialMatrix_[i][neighbor_j] * gaussian1Dkernel_[row];
                          sumNorm += gaussian1Dkernel_[row];
                      }
                  }
                  approxVal /= sumNorm;
                  tmpMatrix[i].push_back(approxVal);
              }
          }
      
          // in y direction
          for(unsigned j = 0; j < xn_; ++j) {
              for(unsigned i = 0; i < yn_; ++i) {
                  double approxVal = 0.0;
                  double sumNorm = 0.0;
                  for(unsigned col = 0; col < kernelSize; ++col) {
                      unsigned neighbor_i = i + col - kernelRad_;
                      if(neighbor_i >= 0 && neighbor_i < yn_) {
                          approxVal += tmpMatrix[neighbor_i][j] * gaussian1Dkernel_[col];
                          sumNorm += gaussian1Dkernel_[row];
                      }
                  }
                  approxVal /= sumNorm;
                  initialMatrix_[i][j] = approxVal;
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-09-29
        • 2017-08-04
        • 2018-10-03
        • 1970-01-01
        • 1970-01-01
        • 2015-04-25
        • 1970-01-01
        • 2011-03-22
        相关资源
        最近更新 更多