我怎样才能尽快做到这一点? - 遍历图像垫
How can I make this as fast as possible? - Iterating through an image mat
这个问题很简单。我还将解释我会做什么,以防有更快的方法来执行此操作而无需优化此特定方法。
我查看图像及其 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 会更快吗?
首先,vector<vector<T>>
没有有效地存储在内存中,因为它 不连续 。这通常会对性能产生很大影响,应尽可能避免(尤其是当内部数组大小相同时)。取而代之的是,您可以将 std::array
用于固定大小的数组或展平 std::vector(大小为 dim1 * dim2 * ... dimN
)。
此外,循环是 并行化 的良好候选者。您可以使用 OpenMP 轻松并行化此代码。这假设 Some calculations here
可以以线程安全的方式实现(如果有的话,你应该小心共享写入)。如果此代码是令人尴尬的并行,那么生成的并行代码会更快。不过,使用多线程会引入一些开销,与整体计算时间相比可能太大了(这在很大程度上取决于 Some calculations here
中的内容)。
最后,关于 Some calculations here
中的内容,可能会也可能不会修改代码,因此编译器会使用 SIMD 指令。 data[index][areasOfPixel[i]]
可能会阻止大多数编译器这样做,但以下计算可能会。请注意,软件预取和收集指令可能有助于加快 data[index][areasOfPixel[i]]
操作的速度。
请注意,您访问像素的方式不应对运行时产生重大影响,因为计算应受限于在包含某些未知代码的区域上进行迭代的内部循环的速度(除非该未知代码实际上也访问像素) ).
这个问题很简单。我还将解释我会做什么,以防有更快的方法来执行此操作而无需优化此特定方法。
我查看图像及其 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 会更快吗?
首先,vector<vector<T>>
没有有效地存储在内存中,因为它 不连续 。这通常会对性能产生很大影响,应尽可能避免(尤其是当内部数组大小相同时)。取而代之的是,您可以将 std::array
用于固定大小的数组或展平 std::vector(大小为 dim1 * dim2 * ... dimN
)。
此外,循环是 并行化 的良好候选者。您可以使用 OpenMP 轻松并行化此代码。这假设 Some calculations here
可以以线程安全的方式实现(如果有的话,你应该小心共享写入)。如果此代码是令人尴尬的并行,那么生成的并行代码会更快。不过,使用多线程会引入一些开销,与整体计算时间相比可能太大了(这在很大程度上取决于 Some calculations here
中的内容)。
最后,关于 Some calculations here
中的内容,可能会也可能不会修改代码,因此编译器会使用 SIMD 指令。 data[index][areasOfPixel[i]]
可能会阻止大多数编译器这样做,但以下计算可能会。请注意,软件预取和收集指令可能有助于加快 data[index][areasOfPixel[i]]
操作的速度。
请注意,您访问像素的方式不应对运行时产生重大影响,因为计算应受限于在包含某些未知代码的区域上进行迭代的内部循环的速度(除非该未知代码实际上也访问像素) ).