返回迭代器与松耦合

Returning Iterator vs Loose Coupling

本文关键字:耦合 迭代器 返回      更新时间:2023-10-16

我有一个关于我正在编写的数据结构体系结构的问题。我正在写一个图像类,我将在一个特定的算法中使用它。在这个算法中,我需要触摸图像中某个边界内的每个像素。我知道做这件事的经典方法是使用两个嵌套的for循环:

for(int i = ROW_BORDER; i < img->height - ROW_BORDER; i++)
    for(int j = COL_BORDER; j < img->width - COL_BORDER; j++)
        WHATEVER 

不过,有人告诉我,在STL的风格中,通常最好返回迭代器,而不是像上面那个样使用循环。让迭代器查看图像中的每个像素会很容易,甚至可以很容易地合并边界约束,但我觉得包含边界会让耦合变得松散。

所以,问题是,我应该返回一个特殊的"边界排除迭代器",使用for循环,还是有我没有想到的更好的方法?

为了避免像"好吧,只使用OpenCV或VXL!"这样的事情,我实际上并不是在写一个图像类,我正在写一个用于特征检测器的高斯金字塔差。也就是说,同样的问题也适用,写两个for循环比写三个或四个更简单。

为了有可重用的东西,我会使用map函数。

namespace your_imaging_lib {
    template <typename Fun>
    void transform (Image &img, Fun fun) {
        const size_t width = img.width(), 
                     size  = img.height() * img.width();
        Pixel *p = img.data();
        for (size_t s=0; s!=size; s+=width)
        for (size_t x=0; x!=width; ++x)
            p[x + s] = fun (p[x + s]);
    }
    template <typename Fun>
    void generate (Image &img, Fun fun) {
        const size_t width = img.width(), size = img.height();
        Pixel *p = img.data();
        for (size_t s=0, y=0; s!=size; s+=width, ++y)
        for (size_t x=0; x!=width; ++x)
            p[x + s] = fun (x, y);
    }
}

需要一些改进。例如,一些系统,如x,y在[0..1).中

然后你可以像这样使用:

using namespace your_imaging_lib;
Image i = Image::FromFile ("foobar.png");
map (i, [](Pixel const &p) { return Pixel::Monochrome(p.r()); });

generate (i, [](int x, int y) { return (x^y) & 0xFF; });

如果您需要同时了解坐标(x和y),我保证与每次迭代都需要额外检查的迭代器相比,这将提供更好的性能。

另一方面,迭代程序将使你的东西可以与标准算法(如std::transform)一起使用,如果不需要像素位置,并且你的数据中没有很大的间距(间距用于对齐,通常在图形硬件表面上找到),你可以使它们几乎同样快。

我怀疑您应该使用访问者模式——而不是返回迭代器或某种项目集合,您应该将要对每个像素/项目执行的操作传递给保存项目的数据结构,数据结构应该能够将该操作应用于每个项目。无论您的数据结构使用for循环还是迭代器遍历隐藏的像素/任何集合,操作都与数据结构解耦。

IMHO有一个触及每个像素的迭代器听起来是个好主意。然而,对我来说,把边界限制包括在内听起来并没有那么吸引人。也许可以尝试实现这样的目标:

IConstraint *bc=new BorderConstraint("blue-border");
for(pixel_iterator itr=img.begin(); itr!=img.end(); itr++) {
    if(!bc->check(itr))
       continue;
    // do whatever
}

其中IConstraint是一个基类,可以派生该基类以生成许多不同的BorderConstraint。我的基本原理是迭代器以不同的方式迭代,但我认为它们不需要了解您的业务逻辑。这可以通过上面的Constraints抽象到另一个设计构造中。

对于位图数据,值得注意的是在流行的图像处理API中没有常用的基于迭代器的算法或数据集这应该是一个线索,表明它很难像常规2D阵列那样高效地实现。(感谢phresnel)

如果你真的需要/更喜欢无边界图像的迭代器,你应该发明一个新的概念来迭代。我的建议是类似于ImageArea。

class ImageArea: Image
{  int clipXLeft, clipXRight;
   int clipYTop, clipYBottom;
  public:
   ImageArea(Image i, clipXTop ... )

然后从那里构造迭代器。迭代器可以是透明的,以处理图像或图像中的区域。

另一方面,基于x/y索引的常规方法也不是一个坏主意。迭代程序在抽象数据集方面非常有用,但当您自己实现它们时会带来成本。