我正在 openCV 中编写一些代码,想要找到一个非常大的矩阵数组(单通道灰度、浮点数)的中值。
我尝试了几种方法,例如对数组进行排序(使用 std::sort)和选择中间条目,但与 matlab 中的中值函数相比,它非常慢。准确地说,在 matlab 中需要 0.25 秒的事情在 openCV 中需要 19 秒以上。
我的输入图像最初是尺寸为 3840x2748(约 10.5 兆像素)的 12 位灰度图像,转换为浮点数(CV_32FC1),其中所有值现在都映射到范围 [0,1],并且在代码中的某个点我通过调用以下命令请求中值:
double myMedianValue = medianMat(Input);
其中函数 MedianMat 为:
double medianMat(cv::Mat Input){
Input = Input.reshape(0,1); // spread Input Mat to single row
std::vector<double> vecFromMat;
Input.copyTo(vecFromMat); // Copy Input Mat to vector vecFromMat
std::sort( vecFromMat.begin(), vecFromMat.end() ); // sort vecFromMat
if (vecFromMat.size()%2==0) {return (vecFromMat[vecFromMat.size()/2-1]+vecFromMat[vecFromMat.size()/2])/2;} // in case of even-numbered matrix
return vecFromMat[(vecFromMat.size()-1)/2]; // odd-number of elements in matrix
}
我对函数 medinaMat 本身以及各个部分进行了计时 - 正如预期的那样,瓶颈在于:
std::sort( vecFromMat.begin(), vecFromMat.end() ); // sort vecFromMat
这里有人有有效的解决方案吗?
Thanks!
EDIT我尝试过使用 Adi Shavit 的答案中给出的 std::nth_element 。
函数 MedianMat 现在读作:
double medianMat(cv::Mat Input){
Input = Input.reshape(0,1); // spread Input Mat to single row
std::vector<double> vecFromMat;
Input.copyTo(vecFromMat); // Copy Input Mat to vector vecFromMat
std::nth_element(vecFromMat.begin(), vecFromMat.begin() + vecFromMat.size() / 2, vecFromMat.end());
return vecFromMat[vecFromMat.size() / 2];
}
运行时间从 19 秒以上缩短至 3.5 秒。这仍然远低于 Matlab 中使用中值函数的 0.25 秒......