我正在尝试编写在二维数组上实现median filtering的代码。 这是一张图片来说明:
程序从数组的开头开始。最大数组大小为100.我知道我可以使用如下数组:
int a[100][100];
存储输入,我可以使用两个for
循环迭代这个数组的一部分,如下所示:
for(i=0;i<size_filter;i++)
for(j=0;j<size_filter;j++)
temp[i][j]=a[i][j] // not so sure
但是如何让这个代码循环遍历数组中每个元素的邻居,计算它们的中位数,并用中位数替换中心元素?
对于我正在尝试做的一些例子,假设输入是5x5矩阵,因此输入大小为5.我想在其上运行3x3中值滤波器,即每个元素都应该被替换通过围绕它的3x3元素的中位数。
程序从角落索引(0,0)开始。对于此索引,它会扫描其周围的3x3区域(其中只有四个索引实际位于输入数组中),其中包含值0,0,1和0.这些值的中位数为0,因此这就是代码应输出此数组索引。
在下图中, 粗体斜体 中的数字是中心单元格,而纯粗体数字是3x3中的邻居它周围的区域:
0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0
这是另一个例子,这次是中心索引(0,1):
0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0
这次,3x3区域中的元素(不包括输入数组之外的元素)的值为0,0,0,1,0和0,因此它们的中位数为0。
这是另一个例子,这次是从输入的中间开始,在中心索引(3,2):
0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0
这次,3x3区域内的元素的值为1,0,0,1,1,0,0,1和1,因此它们的中位数为1。
最后的例子:
<size of array><size filter> <data>
8
3
0 0 0 0 0 0 0 0
0 5 0 0 6 0 0 0
0 0 0 0 0 7 0 0
0 0 0 0 5 0 0 0
0 0 0 5 6 0 0 0
0 0 8 5 5 0 0 0
0 0 0 7 0 0 9 0
0 0 0 0 0 0 0 0
Output:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 5 5 0 0 0
0 0 0 5 5 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
答案 0 :(得分:1)
您似乎正在尝试实施二维median filter。实现这种过滤器的直接方法是使用四个嵌套循环:在整个图像的x和y坐标上有两个外环,在中心像素的邻域上有两个内环。
在代码中比在文本中描述它可能更容易,所以这里有一些Python式的伪代码来说明:
# assumptions:
# * image is a height x width array containing source pixel values
# * filtered is a height x width array to store result pixel values in
# * size is an odd number giving the diameter of the filter region
radius = (size - 1) / 2 # size = 3 -> radius = 1
for y from 0 to height-1:
top = max(y - radius, 0)
bottom = min(y + radius, height-1)
for x from 0 to width-1:
left = max(x - radius, 0)
right = min(x + radius, width-1)
values = new list
for v from top to bottom:
for u from left to right:
add image[v][u] to values
filtered[y][x] = median(values)
将此代码翻译成C作为练习。
还可以通过注意到相邻阵列单元的邻域显着重叠来优化该代码,从而可以在外环的连续迭代中重用这些相邻单元的值。由于此算法在现代CPU上的性能基本上受到RAM访问延迟的限制,因此这种重用可以提供显着的加速,特别是对于大型过滤器大小。
答案 1 :(得分:0)
这样:
for(i=0;i<size_filter;i++)
for(j=0;j<size_filter;j++)
temp[i][j]=a[i][j];
是一个很好的起点。
您只需迭代输入数组的每个像素,确定邻域的中位数并将其写入输出数组。
因此,您需要temp[i][j]=a[i][j];
函数来代替WhatEverType calcMedianAt(const WhatEverType a[100][100], int r, int c, int size);
。
所以你可以致电temp[i][j]=calcMedianAt(a, i,j, 3);
函数本身必须将值提取到列表中(进行适当的边界处理)并找到该列表中的中位数(例如通过调用某个中值函数WhatEverType calcMedian(const WhatEverType* data, int len);
并返回它。