高噪点的灰度图目标粗定位
/*
** @name: CoraseLocation
** @brief: 粗定位
** @param:[in] srcGray 灰度图()
** @param:[in] box 目标尺寸(像素)
** @param:[ou] roi 目标定位结果
** @return: true=成功,false=失败
*/
bool CoraseLocation(cv::Mat& srcGray, cv::Size box, cv::Rect& roi){
try
{
if (srcGray.empty()) return false;
if (srcGray.channels() != 1) return false;
if (box.width < 4 || box.width >= srcGray.cols) return false;
if (box.height < 4 || box.height >= srcGray.rows) return false;
//
roi = cv::Rect(0, 0, srcGray.cols, srcGray.rows);
// STEP01: 计算影像平均灰度与标准差
cv::Scalar meanVal, devVal;
cv::meanStdDev(srcGray, meanVal, devVal);
// STEP02: 计算积分图(寻找目标:亮区或暗区)
cv::Mat srcInte;
cv::integral(srcGray, srcInte, CV_64F);
// STEP03: 寻找亮区和暗区
cv::Point ptMin(-1, -1), ptMax(-1, -1);
double valMin = DBL_MAX, valMax = DBL_MIN;
for (int y = 0; y < srcInte.rows - box.height; y += box.height / 2){
for (int x = 0; x < srcInte.cols - box.width; x += box.width / 2){
double left_top = srcInte.at<double>(y, x);
double left_bottom = srcInte.at<double>(y + box.height, x);
double right_top = srcInte.at<double>(y, x + box.width);
double right_bottom = srcInte.at<double>(y + box.height, x + box.width);
//
double valBox = right_bottom - left_bottom - right_top + left_top;
if (valMin > valBox){
valMin = valBox;
ptMin.x = x + 1;
ptMin.y = y + 1;
}
if (valMax < valBox){
valMax = valBox;
ptMax.x = x + 1;
ptMax.y = y + 1;
}
}
}
valMin /= box.area();
valMax /= box.area();
// STEP04: 判断目标是亮区还是暗区,并重新转换为二值图
bool isWhiteMark = false;
cv::Mat srcBin;
if (abs(valMin - meanVal[0]) > abs(valMax - meanVal[0])){
// valmin: mark为暗
roi = cv::Rect(ptMin.x, ptMin.y, box.width, box.height);
isWhiteMark = false;
cv::threshold(srcGray, srcBin, valMin - devVal[0], 255, cv::THRESH_BINARY_INV);
}
else {
// valmax: mark为亮
roi = cv::Rect(ptMax.x, ptMax.y, box.width, box.height);
isWhiteMark = true;
cv::threshold(srcGray, srcBin, valMax + devVal[0], 255, cv::THRESH_BINARY);
}
// STEP05: 根据二值图,调整目标区域
std::vector<std::vector<cv::Point>> contours;
cv::findContours(srcBin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
valMax = DBL_MIN;
int idxMax = -1;
for (int i = 0; i < contours.size(); ++i){
auto area = cv::contourArea(contours[i]);
if (valMax < area){
valMax = area;
idxMax = i;
}
}
if (idxMax < 0){
return -1;
}
// STEP06: 输出拟合后的目标区域
roi = cv::boundingRect(contours[idxMax]);
return true;
}
catch (...)
{
}
return false;
}
效果: