首页 > 解决方案 > 我怎样才能尽可能快地做到这一点?- 遍历图像垫

问题描述

这个问题很简单。我还将解释我会做什么,以防有更快的方法来做到这一点,而无需优化这种特定的方式。

我浏览了一个图像及其 rgb 值。对于每种颜色,我都有大小为 256 的垃圾箱。因此,对于每个像素,我计算其 rgb 值的 3 个 bin。垃圾箱本质上为我提供了访问大向量中特定颜色数据的索引。有了这些数据,我做了一些无关紧要的计算。我要优化的是访问部分。

请记住,大向量有一个额外的维度。每个像素都属于图像的某些定义区域。对于它所属的每个区域,它在大向量中都有一个元素。因此,如果一个像素属于 4 个区域(例如 3、9、12、13),那么我要访问的数据是:data[colorIndex][3],data[colorIndex][9],data[colorIndex][12],data[colorIndex][13].

我认为这足以解释以下代码:

    //Just filling with data for the sake of the example
    int cols = 200; int rows = 200;
    cv::Mat image(200, 200, CV_8UC3);
    image.setTo(Scalar(100, 100, 100));
    int numberOfAreas = 50;
    //For every pixel (first dimension) we have a vector<int> containing ones for every area the pixel belongs to.
    //For this example, every pixel belongs to every area.
    vector<vector<int>> areasThePixelBelongs(200 * 200, vector<int>(numberOfAreas, 1));

    int numberOfBins = 32;
    int sizeOfBin = 256 / numberOfBins;

    vector<vector<float>> data(pow(numberOfBins, 3), vector<float>(numberOfAreas, 1));
    //Filling complete
    
    //Part I need to optimize
    uchar* matPointer;
    for (int y = 0; y < rows; y++) {
        matPointer = image.ptr<uchar>(y);
        for (int x = 0; x < cols; x++) {
            int red = matPointer[x * 3 + 2];
            int green = matPointer[x * 3 + 1];
            int blue = matPointer[x * 3];
            int binNumberRed = red / sizeOfBin;
            int binNumberGreen = green / sizeOfBin;
            int binNumberBlue = blue / sizeOfBin;

            //Instead of a 3d vector where I access the elements like: color[binNumberRed][binNumberGreen][binNumberBlue]
            //I use a 1d vector where I just have to calculate the 1d index as follows
            int index = binNumberRed * numberOfBins * numberOfBins + binNumberGreen * numberOfBins + binNumberBlue;
            vector<int>& areasOfPixel = areasThePixelBelongs[y*cols+x];
            int numberOfPixelAreas = areasOfPixel.size();
            for (int i = 0; i < numberOfPixelAreas; i++) {
                float valueOfInterest = data[index][areasOfPixel[i]];
                //Some calculations here...
            }
        }

    }

将每个 mat 元素作为 Vec3b 访问会更好吗?我想我本质上是使用 uchar 为每个像素访问一个元素 3 次。访问一个 Vec3b 会更快吗?

标签: c++opencvimage-processingoptimizationlarge-data

解决方案


首先,vector<vector<T>>由于它不是连续的,因此不能有效地存储在内存中。这通常会对性能产生很大影响,应尽可能避免(尤其是当内部数组大小相同时)。取而代之的是,您可以使用std::array固定大小的数组或扁平的 std::vector (使用 size dim1 * dim2 * ... dimN)。

此外,循环是并行化的良好候选者。您可以使用OpenMP轻松并行化此代码。这假设Some calculations here可以以线程安全的方式实现(如果有的话,你应该小心共享写入)。如果这段代码是令人尴尬的并行,那么生成的并行代码会快得多。尽管如此,使用多线程引入了一些开销,与整体计算时间相比可能太大(这高度依赖于 中的内容Some calculations here)。

最后,关于其中的内容Some calculations here可能会或可能不会调整代码,以便编译器使用SIMD 指令。这data[index][areasOfPixel[i]]可能会阻止大多数编译器这样做,但以下计算可能会。请注意,软件预取和收集指令可能有助于加快data[index][areasOfPixel[i]]操作速度。

请注意,访问像素的方式不应对运行时产生重大影响,因为计算应受内循环在包含某些未知代码的区域上迭代的速度的限制(除非此未知代码实际上也访问像素)。


推荐阅读