是否有复制存储在二维数组中的相邻像素值的算法?

Posted

技术标签:

【中文标题】是否有复制存储在二维数组中的相邻像素值的算法?【英文标题】:Is there an algorithm for copying neighboring pixel values stored in a 2D-Array? 【发布时间】:2021-03-19 09:37:17 【问题描述】:

我有一个灰度像素值的二维数组,看起来像

255 250 250 250 235 251 255 201
255 250 250 250 235 251 255 151
255 250 250 250 235 251 255 151
255 250 250 250 235 251 255 151
255 250 250 250 235 251 255 151

在我在网上和其他帖子中看到的实现中,该程序将专门获取 3x3 窗口区域中的相邻像素。

例如,

for (row = 1; row <= numRows; ++row)

    for (col = 1; col <= numCols; ++col)
    
        //neighbor pixel values are stored in window including this pixel 
        window[0] = imageArr[row - 1][col - 1];
        window[1] = imageArr[row - 1][col];
        window[2] = imageArr[row - 1][col + 1];
        window[3] = imageArr[row][col - 1];
        window[4] = imageArr[row][col];
        window[5] = imageArr[row][col + 1];
        window[6] = imageArr[row + 1][col - 1];
        window[7] = imageArr[row + 1][col];
        window[8] = imageArr[row + 1][col + 1];
        
        // do something with window
    

我正在尝试实现更动态的窗口大小。 前任。如果用户想在 4x4 区域或 5x5 区域中查找相邻像素

【问题讨论】:

基本答案是肯定的:添加两个在窗口尺寸上起作用的额外循环并删除所有这些硬连线的重复代码。注意避免溢出。即使在您的示例中,底部和右侧边缘也将超出imageArr 的范围。我认为您打算测试&lt; numRows - 1 等。对于均匀大小的窗口,显然窗口的中心点不是对称的,因此需要特别注意定义您的有效操作空间。更清洁的解决方案可能只使用一个循环和std::copy_nmemcpy 甚至std::valarray 感谢您的回复。您能否通过添加另一个嵌套的 for 循环进一步详细说明您的意思? 有像 Eigen 这样的库,可以让您从更大的数组中提取任意子数组。对这样的东西很有用。或者,您可以使用模板函数从另一个给定中心行和列的数组中提取 std::array&lt;std::array&lt;int,N&gt;,N&gt; 之类的内容。 我认为是时候坐下来在纸上画一个网格,然后在顶部和左侧边缘写下数字(从 0 开始)来表示列和行索引。现在在其中某处绘制一个大小为 N 的“窗口”。将窗口视为图像,因此您当然会使用两个循环来遍历每个值。它的局部左上角始终位于位置 (0,0)。它在图像上下文中的左上角与rowcol 的值相关。你会明白的,我相信。 就个人而言,我会避免你正在做的所有这些额外的数学运算,试图循环中心点。它只是使事情复杂化,并没有增加任何东西。只需在[0, numRows-N)[0, numCols-N) 范围内运行主循环,内部两个循环都在[0, N) 上运行。如果您需要知道窗口的中心点,那么它将是row+N/2, col+N/2。当然,如果 window 是一维数组,那么使用 2D 索引它是标准的,当您使用基于行的图像时,您可能应该记住:window[y * N + x]通常。跨度> 【参考方案1】:

我不打算回答这个问题,但现在我已经在 cmets 中写了很多文章了。

一般建议是通过将rowcol 视为窗口的左上角而不是中心来简化循环。这使数学变得简单明了(因此对于阅读代码的任何人来说都更清楚),尤其是对于大小均匀的窗口尺寸的情况。

假设窗口是方形的(尺寸N),这似乎是您的要求,外部循环变为:

for (int row = 0; row < numRows - N; ++row)

    for (int col = 0; col < numCols - N; ++col)
    
        // TODO: copy window

        // Your window's "center" if you need it
        int cx = col + N/2;
        int cy = row + N/2;

        // TODO: Do something with window...
    

现在,让我们执行“复制窗口”循环。这是一个简单的 NxN 图像副本,其中源位置为 [row + y][col + x]

// Copy window
for (int y = 0; y < N; ++y)

    for (int x = 0; x < N ++x)
    
        window[y * N + x] = imageArr[row + y][col + x];
    

如果您需要,将其扩展到矩形窗口非常简单,这将是您尝试的一个很好的练习。各种优化都是可以的,但我觉得这超出了你目前的水平,我其实不想向初学者推广优化。最好学习如何编写简单、清晰的代码。

【讨论】:

谢谢先生。你给了我一个很好的榜样。 我正在使用你建议的方格纸哈哈。我现在的目标是实现矩形窗口:) 是的,很抱歉。我经常建议某人使用纸张,但他们忽略了这些建议。你想这样做给我留下了深刻的印象,当你需要弄清楚一些事情时,这应该是你的默认方法。始终将纸和笔放在手边。我的键盘旁边随时都有一本小书,用于涂鸦、笔记和图表。我在一元店买了一堆。因为这是一本书,我没有松散的页面可以丢失/造成混乱,有时我需要回顾几个月来寻找我做过的事情。当我用完这本书时,我会开始一本新书,然后将旧书放在书架上。

以上是关于是否有复制存储在二维数组中的相邻像素值的算法?的主要内容,如果未能解决你的问题,请参考以下文章

二维数组搜索FloodFill算法

优化 CUDA 二维数组访问

Coursera 算法二 week2 Seam Carving

获取二维数组中的相邻元素?

java算法--稀疏数组

如何在java中声明一个二维数组的调用? [复制]