最大極值穩定區域,是一種相似分水嶺圖像的分割與匹配算法。它具備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; }