背景
有一张图像,很大,假设10000x10000,需要找其中的最大值和最小值,可以使用opencv的cv::minMaxLoc,但是对于这样的大图来说太慢了。可以多线程并行找。
方法
参考:How to atomically update a maximum value ?
void findMinMax(const cv::Mat& image, double& minV, double& maxV)
{
const auto updateMax = [](std::atomic<float> &z, const float depth)
{
float oldZ = z.load();
while (oldZ < depth && !z.compare_exchange_weak(oldZ, depth))
{
}
};
const auto updateMin = [](std::atomic<float> &z, const float depth)
{
float oldZ = z.load();
while (oldZ > depth && !z.compare_exchange_weak(oldZ, depth))
{
}
};
std::atomic<float> minVal, maxVal;
image.forEach<float>([&](const float d, const int* pos){
updateMin(minVal, d);
updateMax(maxVal, d);
});
minV = minVal;
maxV = maxVal;
}
int main()
{
constexpr int rows = 10000;
constexpr int cols = 10000;
cv::Mat image = cv::Mat(rows, cols, CV_32FC1);
image.forEach<float>([&](float &z, const int *pos)
{
const int r = pos[0];
const int c = pos[1];
z = ((r * cols + c) % 321) * 0.321 - 0.321; });
double minV, maxV;
auto start = clock();
cv::minMaxLoc(image, &minV, &maxV);
std::cout << "cvMinMax cost " << clock() - start << " ms" << std::endl;
std::cout << "cv min " << minV << " max " << maxV << std::endl;
minV = maxV = -1;
start = clock();
findMinMax(image, minV, maxV);
std::cout << "findMinMax cost " << clock() - start << " ms" << std::endl;
std::cout << "find min " << minV << " max " << maxV << std::endl;
}
结果自己定义的findMinMax比cv::minMaxLoc快一倍!
理解compare_exchange_weak这个函数是关键,需要稍微想想多个线程来更新最大最小值的这个过程。