【问题标题】:Fast image smoothing in CC中的快速图像平滑
【发布时间】:2020-10-23 12:00:13
【问题描述】:

问题:给定一个方阵 A,其维数 N 是 64 的除数,找到一种快速平滑 A 的方法,即让 3 x 3 网格在 A 上滑动,s.t.对于每个条目 A_{ij},我们将其替换为附近 8 个邻居的平均值。

我的解决方案:假设 A 是一个 4x4 矩阵,我们初始化为:

int A[NxN] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}

相当于:

在第一次迭代中,我们看到 A_ij 等价于 0,它位于 3x3 矩阵的中心。我们意识到 3x3 矩阵的索引 (0,0), (0,1), (0,2), (1,0), (1,3) 试图找到不存在的数字。因此,我们看到结果一定是,如果 $A_{ij}$ = 0,那么我们必须将其替换为 $0+1+4+5 = \frac{10}{4}$。

下一次迭代,我们看到 A_ij 等价于 1,现在是 3x3 矩阵的新中心,我们看到要包括在平均中的数字是:0,1,2,4,5,6 .

所以当我们在矩阵的一个角落A时,我们需要4个数字进行平均,在矩阵的顶部,我们需要6个数字,如果A_{ij} = 6,意味着在中间矩阵,我们需要 9 个数字。

我试图找到的是这些所需数字序列的一般模式,以便在单个 \texttt{for 循环} 中执行此操作。

我发现当 i % dim == 0 时,我们在矩阵的左侧,当 i % dim == 3 我们在左侧时,但我试图找到一个通用的索引模式来定义我的平均函数与我的 if 条件配对。

#include <stdio.h> 

int smooth(int dim);

int main() {

    smooth(4);
}


int smooth(int dim) {
    int A[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    int K[dim*dim]; // Replacement array, otherwise we average averages
    

    for (int i = 0; i < dim; i++) {
        for (int j = 0; j < dim; j++) 
        {
            // Corner cases
            if ((i % dim == 0 && j % dim == 0) || (i % dim == dim - 1 && j % dim == 0) || (i % dim == 0 && j % dim == dim -1) || (i % dim == dim -1 && j % dim == dim-1))
            { 
                // Average function on corners
            }

            // else if not corner and in "edge row", top/bottom {
                  // Average 6 numbers  

            }

        

        }

    }
    return 0;
}

【问题讨论】:

  • 您使用的“$”数字令人困惑。我猜是因为格式化尝试不成功。请edit 并使用此信息。 stackoverflow.com/editing-help
  • @Yunnosch 抱歉 - 这是 LaTeX 编写数学的方式,适用于其他堆栈交换站点。我马上更新。
  • 不使用通用公式处理边缘并使用四个边缘的规范如何?
  • 为了速度,单独处理角 (0,3,12,15),对非角边 (1-2, 4-8, 13-) 分别应用一个专用的边缘情况计算14, 7-11)并将一个无条件(即没有if inside)应用于中心休息(5-6-9-19)。或者将图片在 x 和 y 中放大 2 倍。用合理的值填充新添加的角落和边缘,然后将一个无条件公式应用于所有原始图片。
  • 另外:您必须构建一个单独的图像,而不是“替换”一个像素,否则您将获得平均值。

标签: c image optimization


【解决方案1】:

您的 mre 有点理论,我将把所有实际上不合理的部分都排除在外。它们显然只是为了快速提供 MRE。

将您的输入解释为 2D。

 0  1  2  3
 4  5  6  7
 8  9 10 11
12 13 14 15

更抽象为

 0              ...  (      0*dim + (dim-1))
(1       * dim) ...  (      1*dim + (dim-1))
(2       * dim) ...  (      2*dim + (dim-1))
                 .
                 .
                 .
((dim-1) * dim) ...  ((dim-1)*dim + (dim-1))

这是我为您的功能提出的结构

int smooth(int dim)
{
    int A[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; //obvious MRE weirdness, ignored
    int K[dim*dim]; // Replacement array, otherwise we average averages
    
    // Corner cases
    K[0]            = A[0];           /* dummy, to be calculated */
    K[dim-1]        = A[dim-1];       /* dummy, to be calculated */
    K[dim*(dim-1)]  = A[dim*(dim-1)]; /* dummy, to be calculated */
    K[dim*dim-1]    = A[dim*dim-1];   /* dummy, to be calculated */

    for (int i = 0; i < dim-2; i++)
    {
        // edge cases
        {
            K[1+i]             = A[1+i];             /* dummy, average to be calculated */
            K[dim*(1+i)]       = A[dim*(1+i)];       /* dummy, average to be calculated */
            K[dim*(1+i)+dim-1] = A[dim*(1+i)+dim-1]; /* dummy, average to be calculated */
            K[dim*(dim-1)+i+1] = A[dim*(dim-1)+i+1]; /* dummy, average to be calculated */ 
        }

        // center part
        for (int j = 0; j < dim-2; j++) 
        {
            K[(i+1)*dim+1+j] = A[(i+1)*dim+1+j]; /* dummy, average to be calculated */
        }
    }
    return 0;
}

对于A[...]; /* dummy, average to be calculated */ 的所有情况,您可以使用相同的索引来读取A 和写入K

  • 减 1 得到左边的像素
  • 加一个到右边的像素
  • 添加暗淡以到达下面的像素
  • 减去 dim 得到上面的像素
  • 对您决定使用的所有相邻像素执行此操作
  • 将这些值相加以确定平均值

在您需要相邻像素的所有情况下,您总是会得到一个有效像素,因为要么有一个,要么您不需要它。

(注意:我严格练习从 0 开始 for 循环并用 &lt;needed_length 向上计数。有一种替代方法可以从 1 开始并计数到所需长度 +1。在这种情况下,它将使索引计算读取更容易。这是一个习惯问题。我来自一个环境,你必须为不从 0 开始的循环准备强有力的推理。习惯很难摆脱。通过替代概念可能会为你提供一些有用的学习机会。)

【讨论】:

    猜你喜欢
    • 2016-12-30
    • 1970-01-01
    • 2010-10-22
    • 2019-02-17
    • 2020-02-16
    • 1970-01-01
    • 2014-10-31
    • 2018-07-16
    • 1970-01-01
    相关资源
    最近更新 更多