最大极值稳定区域,是一种相似分水岭图像的分割与匹配算法。它具备SIFT SURF及 ORB等特征不具有的仿射不变性,近年来普遍应用于图像分割与匹配领域。ios
详细算法原理介绍可参见连接 http://blog.csdn.net/zhaocj/article/details/40742191算法
建立MSER类ui
//开发环境 vs2013+opencv3.1.0 // 建立MSER对象 cv::Ptr<cv::MSER> mesr1 = cv::MSER::create(2, 10, 5000, 0.5, 0.3); //若是想要了解各参数的含义,首先须要经过以上连接了解算法原理。2表示灰度值的变化量,10和5000表示检测到的组块面积的范围,0.5为最大的变化率,0.3为稳定区域的最小变换量
申明输出参数.net
std::vector<std::vector<cv::Point> > regContours; std::vector<cv::Rect> bboxes1;
MSER检测code
mesr1->detectRegions(gray, regContours, bboxes1);//gray为处理的图像,为单通道灰度图
保存检测到的结果对象
cv::Mat mserMapMat =cv::Mat::zeros(gray.size(), CV_8UC1); for (int i = (int)regContours.size() - 1; i >= 0; i--) { // 根据检测区域点生成mser+结果 const std::vector<cv::Point>& r = regContours[i]; for (int j = 0; j < (int)r.size(); j++) { cv::Point pt = r[j]; mserMapMat.at<unsigned char>(pt) = 255; } }
MSER根据须要检测的白色区域和黑色区域,又分为MSER+和MSER-blog
下面贴上Mser车牌目标检测示例 完整的C++代码 示例图片可到图片
#include "opencv2/highgui/highgui.hpp" #include "opencv2/features2d.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> // Mser车牌目标检测 std::vector<cv::Rect> mserGetPlate(cv::Mat srcImage) { // HSV空间转换 cv::Mat gray, gray_neg; cv::Mat hsi; cv::cvtColor(srcImage, hsi, CV_BGR2HSV); // 通道分离 std::vector<cv::Mat> channels; cv::split(hsi, channels); // 提取h通道 gray = channels[1]; // 灰度转换 cv::cvtColor(srcImage, gray, CV_BGR2GRAY); // 取反值灰度 gray_neg = 255 - gray; std::vector<std::vector<cv::Point> > regContours; std::vector<std::vector<cv::Point> > charContours; // 建立MSER对象 cv::Ptr<cv::MSER> mesr1 = cv::MSER::create(2, 10, 5000, 0.5, 0.3); cv::Ptr<cv::MSER> mesr2 = cv::MSER::create(2, 2, 400, 0.1, 0.3); std::vector<cv::Rect> bboxes1; std::vector<cv::Rect> bboxes2; // MSER+ 检测 mesr1->detectRegions(gray, regContours, bboxes1); // MSER-操做 mesr2->detectRegions(gray_neg, charContours, bboxes2); cv::Mat mserMapMat =cv::Mat::zeros(srcImage.size(), CV_8UC1); cv::Mat mserNegMapMat =cv::Mat::zeros(srcImage.size(), CV_8UC1); for (int i = (int)regContours.size() - 1; i >= 0; i--) { // 根据检测区域点生成mser+结果 const std::vector<cv::Point>& r = regContours[i]; for (int j = 0; j < (int)r.size(); j++) { cv::Point pt = r[j]; mserMapMat.at<unsigned char>(pt) = 255; } } // MSER- 检测 for (int i = (int)charContours.size() - 1; i >= 0; i--) { // 根据检测区域点生成mser-结果 const std::vector<cv::Point>& r = charContours[i]; for (int j = 0; j < (int)r.size(); j++) { cv::Point pt = r[j]; mserNegMapMat.at<unsigned char>(pt) = 255; } } // mser结果输出 cv::Mat mserResMat; // mser+与mser-位与操做 mserResMat = mserMapMat & mserNegMapMat; cv::imshow("mserMapMat", mserMapMat); cv::imshow("mserNegMapMat", mserNegMapMat); cv::imshow("mserResMat", mserResMat); // 闭操做链接缝隙 cv::Mat mserClosedMat; cv::morphologyEx(mserResMat, mserClosedMat, cv::MORPH_CLOSE, cv::Mat::ones(1, 20, CV_8UC1)); cv::imshow("mserClosedMat", mserClosedMat); // 寻找外部轮廓 std::vector<std::vector<cv::Point> > plate_contours; cv::findContours(mserClosedMat, plate_contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0)); // 候选车牌区域判断输出 std::vector<cv::Rect> candidates; for (size_t i = 0; i != plate_contours.size(); ++i) { // 求解最小外界矩形 cv::Rect rect = cv::boundingRect(plate_contours[i]); // 宽高比例 double wh_ratio = rect.width / double(rect.height); // 不符合尺寸条件判断 if (rect.height > 20 && wh_ratio > 4 && wh_ratio < 7) candidates.push_back(rect); } return candidates; } int main() { cv::Mat srcImage = cv::imread("car.jpg"); if (srcImage.empty()) return-1; cv::imshow("src Image", srcImage); // 候选车牌区域检测 std::vector<cv::Rect> candidates; candidates = mserGetPlate(srcImage); // 车牌区域显示 for (int i = 0; i < candidates.size(); ++i) { cv::imshow("rect", srcImage(candidates[i])); cv::waitKey(); } cv::waitKey(0); return 0; }