关于前景、背景分离,可以考虑如下一个简单的算法:
- 从图片搜索 最亮区域Rect1 ,最暗区域 Rect2.
- 计算 Rect1均值 avg1, 计算 Rect2均值 avg2.
- 是计算avg= (avg1+avg2)/2, 作为 分割阈值。
这就是根据经验设计的 全局极值块均值 二值化算法。
double bin_min_max_block(const Mat& src, Mat& dst, const Size& minBlock = Size(15, 15), const Size& maxBlock = Size(15, 15), double ratio = 1.0)//搜索最小灰度块/最大灰度块,取均值{ //积分图,用于加速 Mat intMat; cv::integral(src, intMat, CV_32F); //搜索的块尺寸 Rect minRect, maxRect; double maxV = (std::numeric_limits::min)(); double minV = (std::numeric_limits::max)(); for (int i = 0; i < src.rows; ++i) { for (int j = 0; j < src.cols; ++j) { if (i + minBlock.height < src.rows && j + minBlock.width < src.cols)//越界判断 { Rect _rmin = Rect(j, i, minBlock.width, minBlock.height); //求最小块 double _sumMinBlockV = intergal_of_sum(intMat, _rmin); if (_sumMinBlockV < minV) { minRect = _rmin; minV = _sumMinBlockV; } } if (i + maxBlock.height < src.rows && j + maxBlock.width < src.cols)//越界判断 { Rect _rmax = Rect(j, i, maxBlock.width, maxBlock.height);//求最大块 double _sumMaxBlockV = intergal_of_sum(intMat, _rmax); if (_sumMaxBlockV > maxV) { maxRect = _rmax; maxV = _sumMaxBlockV; } } } } double avgMax = maxV / maxBlock.area(); double avgMin = minV / minBlock.area(); double thres = (avgMax + avgMin) / 2 * ratio; cv::threshold(src, dst, thres, 255, THRESH_BINARY); return thres;}//通过积分图,快速计算 Mat(Rect)值double intergal_of_sum(const Mat& inte, const Rect& r){ Point p1(r.x, r.y); Point p2(r.x + r.width, r.y); Point p3(r.x, r.y + r.height); Point p4(r.x + r.width, r.y + r.height); return inte.at(p1) + inte.at(p4) - inte.at(p2) - inte.at(p3);}
代码非常简单,使用 积分图,加速 计算 Mat(Rect) 的值。
这种二值化全局化的二值化有一定的道理,不过适应不见得很好。
但是,这是本人设计的简单方式,算是一种思维开拓。