高斯模糊,均值滤波,卷积

时间:2013-10-16 20:37:44

标签: c image-processing filtering gaussian convolution

我想实现一个卷积函数用于均值滤波器和高斯滤波器,我需要实现这两个滤波器以应用于pgm文件。 我有

typedef struct _PGM{
int row;
int col;
int max_value;
int **matrix;
}PGM;

struct和

int convolution(int ** kernel,int ksize, PGM * image, PGM * output){

   int i, j, x, y;
   int sum;
   int data;
   int scale =ksize*ksize;
   int coeff;

 for (x=ksize/2; x<image->row-ksize/2;++x) {
  for (y=ksize/2; y<image->col-ksize/2; ++y){
     sum = 0;
    for (i=-ksize/2; i<=ksize/2; ++i){
      for (j=-ksize/2; j<=ksize/2; ++j){
        data = image->matrix[x +i][y +j];
        coeff = kernel[i+ksize/2][j+ksize/2];
        sum += data * coeff;
    }
  }
  output->matrix[x][y] = sum / scale; 
 }
}

return sum/scale;
}

卷积函数,但我在卷积函数中得到错误(实际上它终止),所以我无法进行过滤 你能帮我实现吗?

谢谢。

1 个答案:

答案 0 :(得分:3)

在你的卷积中有两个错误,可能导致崩溃。第一种是样式:您使用x迭代图像的行,我将其更多地视为y位移,反之亦然。第二个是当你计算总和时,在评估每个像素的内核(内部两个循环)之前,你没有重置变量sum = 0。相反,您在所有像素上累积sum,可能最终导致整数溢出。虽然严格来说这是UB并且可能导致崩溃,但这不是你所面临的问题。

如果您确实在第一个像素(x = ksize/2y = ksize/2)上发生了崩溃,那么由于崩溃发生在从内核读取的第一个系数上,我怀疑您可能已经通过kernel的“错误的东西”。如上所述,kernelint**。对于3x3的内核大小,这意味着要正确调用此函数,您必须在堆上分配或堆栈int*数组,其中存储3个指向int数组的指针,每个数组包含3个系数。如果您改为传递int[3][3]数组,则卷积函数将尝试将数组中的前一个或两个int解释为指向int的指针,如果不是,请尝试取消引用它来引入系数。这很可能会导致段错误。

我也不知道你为什么要归还累计金额。这不是卷积的“传统”输出,但我猜测你对输出图像的平均亮度感兴趣,这是合法的;在这种情况下,您应该使用单独且更宽的整数累加器(longlong long),并在最后将其除以输出中的像素数。

您可能从互联网上找到了PGM数据结构,比如here。请允许我参加这个最佳实践建议。在我的领域(计算机视觉)中,首选的计算机视觉库OpenCV 将矩阵表示为row指向col元素缓冲区的数组。相反,会分配一大块内存,在这种情况下,最小大小为image->row * image->col * sizeof(int),但image->row * image->step * sizeof(int) image->step image->col/* Includes */ #include <stdlib.h> /* Defines */ #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) /* Structure */ /** * Mat structure. * * Stores the number of rows and columns in the matrix, the step size * (number of elements to jump from one row to the next; must be larger than or * equal to the number of columns), and a pointer to the first element. */ typedef struct Mat{ int rows; int cols; int step; int* data; } Mat; /* Functions */ /** * Allocation. Allocates a matrix big enough to hold rows * cols elements. * * If a custom step size is wanted, it can be given. Otherwise, an invalid one * can be given (such as 0 or -1), and the step size will be chosen * automatically. * * If a pointer to existing data is provided, don't bother allocating fresh * memory. However, in that case, rows, cols and step must all be provided and * must be correct. * * @param [in] rows The number of rows of the new Mat. * @param [in] cols The number of columns of the new Mat. * @param [in] step The step size of the new Mat. For newly-allocated * images (existingData == NULL), can be <= 0, in * which case a default step size is chosen; For * pre-existing data (existingData != NULL), must be * provided. * @param [in] existingData A pointer to existing data. If NULL, a fresh buffer * is allocated; Otherwise the given data is used as * the base pointer. * @return An allocated Mat structure. */ Mat allocMat(int rows, int cols, int step, int* existingData){ Mat M; M.rows = max(rows, 0); M.cols = max(cols, 0); M.step = max(step, M.cols); if(rows <= 0 || cols <= 0){ M.data = 0; }else if(existingData == 0){ M.data = malloc(M.rows * M.step * sizeof(*M.data)); }else{ M.data = existingData; } return M; } /** * Convolution. Convolves input by the given kernel (centered) and stores * to output. Does not handle boundaries (i.e., in locations near the border, * leaves output unchanged). * * @param [in] input The input image. * @param [in] kern The kernel. Both width and height must be odd. * @param [out] output The output image. * @return Average brightness of output. * * Note: None of the image buffers may overlap with each other. */ int convolution(const Mat* input, const Mat* kern, Mat* output){ int i, j, x, y; int coeff, data; int sum; int avg; long long acc = 0; /* Short forms of the image dimensions */ const int iw = input ->cols, ih = input ->rows, is = input ->step; const int kw = kern ->cols, kh = kern ->rows, ks = kern ->step; const int ow = output->cols, oh = output->rows, os = output->step; /* Kernel half-sizes and number of elements */ const int kw2 = kw/2, kh2 = kh/2; const int kelem = kw*kh; /* Left, right, top and bottom limits */ const int l = kw2, r = max(min(iw-kw2, ow-kw2), l), t = kh2, b = max(min(ih-kh2, oh-kh2), t); /* Total number of pixels */ const int totalPixels = (r-l)*(b-t); /* Input, kernel and output base pointers */ const int* iPtr = input ->data; const int* kPtr = kern ->data + kw2 + ks*kh2; int* oPtr = output->data; /* Iterate over pixels of image */ for(y=t; y<b; y++){ for(x=l; x<r; x++){ sum = 0; /* Iterate over elements of kernel */ for(i=-kh2; i<=kh2; i++){ for(j=-kw2; j<=kw2; j++){ data = iPtr[j + is*i + x]; coeff = kPtr[j + ks*i ]; sum += data * coeff; } } /* Compute average. Add to accumulator and store as output. */ avg = sum / kelem; acc += avg; oPtr[x] = avg; } /* Bump pointers by one row step. */ iPtr += is; oPtr += os; } /* Compute average brightness over entire output */ if(totalPixels == 0){ avg = 0; }else{ avg = acc/totalPixels; } /* Return average brightness */ return avg; } /** * Main */ int main(int argc, char* argv[]){ /** * Coefficients of K. Binomial 3x3, separable. Unnormalized (weight = 16). * Step = 3. */ int Kcoeff[3][3] = {{1, 2, 1}, {2, 4, 2}, {1, 2, 1}}; Mat I = allocMat(1920, 1080, 0, 0);/* FullHD 1080p: 1920x1080 */ Mat O = allocMat(1920, 1080, 0, 0);/* FullHD 1080p: 1920x1080 */ Mat K = allocMat( 3, 3, 3, &Kcoeff[0][0]); /* Fill Mat I with something.... */ /* Convolve with K... */ int avg = convolution(&I, &K, &O); /* Do something with O... */ /* Return */ return 0; } 四舍五入到下一个倍数然后,只保留一个指针,指向整个图像底部的指针,但如果图像不连续,则必须保留一个额外的字段(步骤)。

因此我会修改你的代码:

{{1}}

参考资料:多年的计算机视觉经验。