我正在使用OpenCV编写代码,想要找到一个非常大的矩阵数组(单通道灰度,浮点数)的中值。
我尝试了几种方法,比如排序数组(使用std::sort)并选择中间条目,但与matlab中的median函数相比,速度非常慢。确切地说,matlab中需时0.25秒,在OpenCV中需要超过19秒。
我的输入图像最初是一个12位灰度图像,尺寸为3840x2748(约1050万像素),转换为float(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
这里有没有人有高效的解决方案?
谢谢!
编辑: 我尝试使用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秒...
+/- std::numeric_limits<float>::max()
吗?提供一些关于输入数据的详细信息,也许可以将其映射到整数域,从而更容易/更快地解决此问题。 - Antonio