【MSER】基于MSER算法的交通标志分割仿真

article/2025/9/13 6:21:03

1.软件版本

MATLAB2021a

2.本算法理论知识

[1]钱坤. 基于MSER和遗传优化SVM的交通标志识别的研究[D]. 大连理工大学.

[2]王斌, 常发亮, 刘春生. 基于MSER和SVM的快速交通标志检测[J]. 光电子.激光, 2016.

3.部分源码

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                              %
%                      MSER algorithm - Linear Time MSER                       %clc
clear
close alltic
% Read input image
img = imread('img/smp_6.jpg');
height = size(img,1);
width = size(img,2);
total_pixels_img = width*height;
usage = 'segmented';                   % select between segmented or gray scale% image as input: 'segmented' / 'gray'% Parameters to set
min_area_mser = 1000;
max_area_mser = 1000000;
mser_p.delta = 2;
mser_p.min_area = 0.00001*width*height;
mser_p.max_area = 0.25*width*height;
mser_p.max_variation = 0.5;
mser_p.min_diversity = 0.33;
color_of_interest = 'blue';             % Options are: red, green, blue
color_threshold = 100;                  % range from 0-255
ratio = 1.2;                            % ration between color interest and% others: 20%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% INIT ALGORITHM% 1) Select input image to process if it's gray or segmented and create a single
% row vector with the image
switch usagecase 'segmented'% Simple segmentation by color thresholdimg_seg = f_seg(img, color_threshold, color_of_interest, ratio);subplot(2,2,1);imshow(img);title(['Original Image (' num2str(width) 'x' num2str(height) ')']);subplot(2,2,2);imshow(img_seg);title(['Segmented img ( Color filt:' color_of_interest ' Threshold:' ...num2str(color_threshold) ')']);i = 1;for y=1:heightfor x=1:widthif img_seg(y,x) == 0img_scan(i,1) = 1;elseimg_scan(i,1) = img_seg(y,x);endi=i+1;endendimg_selected = img_seg;case 'gray'% Image converted in gray scaleimg_grey = rgb2gray(img);subplot(2,2,1);imshow(img);title(['Original Image (' num2str(width) 'x' num2str(height) ')']);subplot(2,2,2);imshow(img_grey);title(['Gray Image (' num2str(size(img_grey,2)) 'x' ...num2str(size(img_grey,1)) ')']);i = 1;for y=1:heightfor x=1:widthif img_grey(y,x) == 0img_scan(i,1) = 1;elseimg_scan(i,1) = img_grey(y,x);endi=i+1;endendimg_selected = img_grey;
end% 2) Create the bin mask with accessed pixels
bin_mask_access = zeros(total_pixels_img,1);% 3) Initialize control variables
priority = 256;                           % Variable that defines the smallest% 'dark' pixel
current_pixel = 1;
current_edge  = 0;
current_level = img_scan(current_pixel);
bin_mask_access(current_pixel) = 1;
index_regions = 0;
g_index_stack = 0;% Create the LIFO for the 256 gray leves
for i=1:256boundary_pixels(i) = CStack();
end% Insert into the tree the most 'bright' pixel that equivalent to 256
g_index_stack = g_index_stack + 1;
index_regions = index_regions + 1;
region_stack(index_regions).level = 256;
region_stack(index_regions).area = 0;
region_stack(index_regions).mom(1) = 0;
region_stack(index_regions).mom(2) = 0;
region_stack(index_regions).mom(3) = 0;
region_stack(index_regions).mom(4) = 0;
region_stack(index_regions).mom(5) = 0;
region_stack(index_regions).variation_mser = 999999;
region_stack(index_regions).stable = 0;
region_stack(index_regions).parent = 0;
region_stack(index_regions).child = 0;
region_stack(index_regions).next = 0;
% This is an auxiliary vector (LIFO) to store the regions pushed and not process
% ed by the function 'process_stack' yet, which defines the parent and child nod
% es. In normal behavior this must inflate and deinflate during the image proces
% sing
stack(g_index_stack).node = index_regions;% Each region_stack has a correspondent rect that represents the rectangle assoc
% iated with that region, it facilitates in the later step
rect(index_regions).top = Inf;
rect(index_regions).bottom = 0;
rect(index_regions).left = Inf;
rect(index_regions).right = 0;
rect(index_regions).draw = 1;% Insert into the tree the first region for the first pixel level in the image
g_index_stack = g_index_stack + 1;
index_regions = index_regions + 1;
region_stack(index_regions).level = current_level;
region_stack(index_regions).area = 0;
region_stack(index_regions).mom(1) = 0;
region_stack(index_regions).mom(2) = 0;
region_stack(index_regions).mom(3) = 0;
region_stack(index_regions).mom(4) = 0;
region_stack(index_regions).mom(5) = 0;
region_stack(index_regions).variation_mser = 999999;
region_stack(index_regions).stable = 0;
region_stack(index_regions).parent = 0;
region_stack(index_regions).child = 0;
region_stack(index_regions).next = 0;
stack(g_index_stack).node = index_regions;rect(index_regions).top = Inf;
rect(index_regions).bottom = 0;
rect(index_regions).left = Inf;
rect(index_regions).right = 0;
rect(index_regions).draw = 1;% 4) Run the main algorithm that will scan all pixels inside the image
gCounter = 0;
done = 0;
while (done == 0)gCounter = gCounter+1; % ...it'll always be the total_pixels_img% While loop to scan all edges of the pixel in analisyswhile current_edge < 4% ...get the neighbor pixel according to correspondent edge in the BIG row v% ector that contains all pixelsneighbor_pixel = f_neighbor_pixel(current_pixel,current_edge,width,height);if (bin_mask_access(neighbor_pixel) == 0)neighbor_level = img_scan(neighbor_pixel,1);bin_mask_access(neighbor_pixel) = 1;% If the neighbor pixel has a 'lowest (black)' level than the current one,% let push a new region and define as our new current pixelif (neighbor_level < current_level)% In this step we need to store the old current pixel and its current ed% ge and to execute this, we are joining with OR - logical operation the% two informations with this approach:%%                                   8 bits                  4 bits%  Pixel to map after ->    current pixel position       current edge%                        (remember that now, this is)     (we add +1)%                          (just a number in a row)    (because we want)%                                                        (the next edge)%% Example:%                                     CUR_PIXEL (8)       1010 1010 << 4%                                          EDGE (4)    +       1111%                             Later processing (12)  1010 1010 1111boundary_pixels(current_level).push(bitor(bitshift(current_pixel,4), ...(current_edge+1)));% ..always define priority as the 'darkest' pixel founded, because we'll% search for that pixel in the boundary stack after if we do not find an% y pixel lowest (black) in the edgesif (current_level < priority)priority = current_level;endcurrent_pixel = neighbor_pixel;current_edge = 0;current_level = neighbor_level;% Push a new region with the new 'darkest' pixel foundedindex_regions = index_regions + 1;region_stack(index_regions).level = current_level;region_stack(index_regions).area = 0;region_stack(index_regions).mom(1) = 0;region_stack(index_regions).mom(2) = 0;region_stack(index_regions).mom(3) = 0;region_stack(index_regions).mom(4) = 0;region_stack(index_regions).mom(5) = 0;region_stack(index_regions).variation_mser = 999999;region_stack(index_regions).stable = 0;region_stack(index_regions).parent = 0;region_stack(index_regions).child = 0;region_stack(index_regions).next = 0;g_index_stack = g_index_stack + 1;stack(g_index_stack).node = index_regions;% ..and its rectangle combinedrect(index_regions).top = Inf;rect(index_regions).bottom = 0;rect(index_regions).left = Inf;rect(index_regions).right = 0;rect(index_regions).draw = 1;continue;end% If the current pixel is the 'lowest (black)', store the neighboor for la% ter search iterationboundary_pixels(neighbor_level).push(bitor(bitshift(neighbor_pixel,4),0));if (neighbor_level < priority)priority = neighbor_level;endendcurrent_edge = current_edge + 1;end% We need to discover in the MxN representation, the value of the pixel for im% age math processing, for later computingx = mod(current_pixel, width); % Give us the offset in the line of the imageif x == 0x = width;endy = floor(current_pixel/width);% As the MSER alg. we need to accumulate the latest pixel in the latest region[region_stack rect] = f_accumulate(region_stack, rect, stack, ...g_index_stack, x, y);% If our priority is 256 we don't have a lowest pixel anymore, then we finish!% ..and we need to process all stack creating the tree with the regions to be% this way:% Example:%                        ________________256_______________%                       |          |            |          |%                     _243_     _ 251_        _202_       _215_%                    |     |   |      |      |     |     |     |%                   145   20  200     10    198    52    20   112%                ...................................................%%                                      PARENT%                                        |%                                       NODE%                                      /    \%                                   NEXT   CHILD%if (priority == 256)% PROCESS STACKnew_pixel_grey_level = 256; % Passing 256 as the new pixel grey level matche% s to create the root tree node[region_stack ...rect ...index_regions ...g_index_stack ...stack] = f_process_stack(new_pixel_grey_level, ...region_stack, ...stack, ...g_index_stack, ...index_regions, ...rect);done = 1;break;end% Remove the pixel with lowest (black) value stored in the stack to process...% we remove top because it's a LIFOpixel_component = boundary_pixels(priority).top();% Undo the concatenation made previous beforecurrent_pixel = bitshift(pixel_component,-4);current_edge = bitand(pixel_component,15);boundary_pixels(priority).pop();% If we empty the stack in that black level, we need to increase the prioritywhile (boundary_pixels(priority).isempty() && (priority < 256))priority = double(priority + 1);end% Get the black level for our new current pixelnew_pixel_grey_level = img_scan(current_pixel);if (new_pixel_grey_level ~= current_level)% PROCESS STACK[region_stack ...rect ...index_regions ...g_index_stack ...stack] = f_process_stack(new_pixel_grey_level, ...region_stack, ...stack, ...g_index_stack, ...index_regions, ...rect);current_level = new_pixel_grey_level;end
end% END OF MAIN ALGORITHM
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Post-processing step
% 5) Stable analisys of each region to determine the MSER regions
stable_counter = 0;
for i=1:size(region_stack,2)reg = region_stack(i);parent = region_stack(i);while (parent.parent && region_stack(parent.parent).level <= reg.level + ...mser_p.delta)parent = region_stack(parent.parent);endreg.variation_mser = (parent.area - reg.area)/reg.area;reg.stable = (reg.area >=  mser_p.min_area) && ...(reg.area <= mser_p.max_area) && (reg.variation_mser <= ...mser_p.max_variation);id = reg.parent;if id ~= 0parent = region_stack(id);while (parent.parent && reg.area > mser_p.min_diversity*parent.area)if(parent.variation_mser <= reg.variation_mser)reg.stable = false;endif(reg.variation_mser < parent.variation_mser)parent.stable = false;endrect(id).stable = parent.stable;region_stack(id) = parent;id = parent.parent;parent = region_stack(id);endendif (reg.stable == 1)stable_counter = stable_counter + 1;endrect(i).stable = reg.stable;region_stack(i) = reg;
end% Saving just the stable regions
t = 0;
for p=1:size(rect,2)if(rect(p).stable == 1)t = t+1;tmp(t) = rect(p);end
endrect = tmp;subplot(2,2,3);
imshow(img_selected);
title(['Original Image (' num2str(width) 'x' num2str(height) ...') with all MSER Regions']);
k=0;
for i=1:size(rect,2)if (rect(i).draw == 1)k=k+1;width_n = rect(i).right-rect(i).left;height_n = rect(i).bottom-rect(i).top;rectangle('Position',[rect(i).left rect(i).top width_n  height_n], ...'EdgeColor','r');end
end% 6) Filtering just the rectangles with some specific area range
for i=1:size(rect,2)rect(i).height = rect(i).bottom - rect(i).top;rect(i).width = rect(i).right - rect(i).left;rect(i).size = rect(i).height*rect(i).width;if (rect(i).size > min_area_mser && rect(i).size < max_area_mser)rect(i).draw = 1;elserect(i).draw = 0;end
endsubplot(2,2,4);
imshow(img);
title(['Original Image (' num2str(width) 'x' num2str(height) ...') with filtered MSER Regions']);% 7) Draw the rectangles in the original image
k=0;
for i=1:size(rect,2)if (rect(i).draw == 1)k=k+1;width_n = rect(i).right-rect(i).left;height_n = rect(i).bottom-rect(i).top;rectangle('Position',[rect(i).left rect(i).top width_n  height_n], ...'EdgeColor','r');end
endtime_p = toc;% 8) Reports
fprintf('\tConclusion Reports');
fprintf('\nImage size: Width=%d x Height=%d',width,height);
fprintf('\nTotal number of pixels: %d',total_pixels_img);
fprintf('\nFounded regions: %d',index_regions);
fprintf('\nStable regions: %d',stable_counter);
fprintf('\nRectangles drawed: %d', k);
fprintf('\nTime to process the image: %d seconds', time_p);
fprintf('\nMSER Parameters: ');
mser_p

4.仿真

D238


http://chatgpt.dhexx.cn/article/Mc0yKndB.shtml

相关文章

MSER相关总结

最近做项目用到了MSER&#xff0c;特地在这做总结。 以前提到字符检测首先会想到Tesseract&#xff0c;但是tesseact对图像的二值化要求过高&#xff0c;比较适合于白底黑字的字符识别&#xff0c;对于复杂情况就无能为力了&#xff1b; 于是就想到用轮廓检测&#xff0c;这种…

最大稳定极值区域(MSER)检测

Lowe和Bay提出的SIFT和SURF算法高效实现了具有尺度和旋转不变性的特征检测&#xff0c;但这些特征不具有仿射不变性。 区域检测针对各种不同形状的图像区域&#xff0c;通过对区域的旋转和尺寸归一化&#xff0c;可以实现仿射不变性。 MSER&#xff08;Maximally Stable Extr…

MSER最稳定极值区域源码分析

最稳定极值区域介绍 如把灰度图看成高低起伏的地形图&#xff0c;其中灰度值看成海平面高度的话&#xff0c;MSER的作用就是在灰度图中找到符合条件的坑洼。条件为坑的最小高度&#xff0c;坑的大小&#xff0c;坑的倾斜程度&#xff0c;坑中如果已有小坑时大坑与小坑的变化率。…

OpenCVSharp入门教程 特征提取①——MSER区域特征提取Maximally Stable Extremal Regions

文章目录 一、前文二、特征提取流程三、界面布局四、功能实现4.1 打开图片4.2 特征提取—源码4.3 特征提取—参数讲解4.4 特征提取—Detect和DetectRegions 五、运行效果图六、发现并解决问题七、其他问题 一、前文 MSER Maximally Stable Extremal Regions 最大极值稳定区 业…

【OpenCV 例程 300篇】247. 特征检测之最大稳定极值区域(MSER)

『youcans 的 OpenCV 例程300篇 - 总目录』 【youcans 的 OpenCV 例程 300篇】247. 特征检测之最大稳定极值区域&#xff08;MSER&#xff09; 1. 最大稳定极值区域&#xff08;MSER&#xff09; 最大稳定极值区域&#xff08;MSER-Maximally Stable Extremal Regions&#xf…

师傅带徒弟学JavaScript-关东升-专题视频课程

师傅带徒弟学JavaScript—430人已学习 课程介绍 本课程是学习Web前端的基础课程&#xff0c;是学习Web前端框架、JavaWeb开发、Python Web开发、PHP开发和.NET Web开发前置课程。 课程收益 掌握JavaScript 讲师介绍 关东升 更多讲师课程 一个在IT领域摸爬滚打20多年的老程…

师傅带徒弟学:Python Web之Flask框架-关东升-专题视频课程

师傅带徒弟学&#xff1a;Python Web之Flask框架—317人已学习 课程介绍 Python Web是Python语言一个重要的应用方面&#xff0c;Python Web有很多&#xff0c;其中Flask和Django框架是他们的佼佼者。 Flask是一个Python实现的Web开发微框架。 课程收益 掌握Flask框架 讲师…

关东升的iOS实战系列图书 《iOS实战:入门与提高卷(Swift版)》已经上市

&#xfeff;&#xfeff; 承蒙广大读者的厚爱我的 《iOS实战&#xff1a;入门与提高卷&#xff08;Swift版&#xff09;》京东上市了&#xff0c;欢迎广大读者提出宝贵意见。http://item.jd.com/11766718.html 欢迎关注关东升新浪微博tony_关东升。 关注智捷课堂微信公共平台&…

Sharding-JDBC(一)SpringBoot集成

目录 1.背景2.简介3.依赖与配置4.表结构&#xff08;1..3&#xff09;5.测试验证5.1 批量保存5.2 列表查询 6.源码地址 1.背景 随着业务数据量的增加&#xff0c;原来所有的数据都是在一个数据库上&#xff0c;网络IO及文件IO都集中在一个数据库上&#xff0c;因此CPU、内存、…

第一篇【Python】基础-关东升-专题视频课程

第一篇【Python】基础—833人已学习 课程介绍 本书是智捷课堂开发的立体化图书中的一本&#xff0c;所谓“立体化图书”就是图书包含&#xff1a;书籍、视频、课件和服务等内容。 其中第一篇包括8章内容&#xff0c;系统介绍了Python语言的基础知识。内容包括Python语言历史…

shardingsphere-jdbc 整合 springboot

shardingsphere官网地址 https://shardingsphere.apache.org/document/5.2.0/cn/user-manual/shardingsphere-jdbc/spring-boot-starter/rules/sharding/ 当前我们演示的是水平分表 1、基础环境配置以及依赖管理 1.1 创建数据库表结构 CREATE TABLE address_0 (id bigint(…

如果张东升是个程序员

张东升是一家互联网公司的程序员&#xff0c;一直以来都勤勤恳恳老实工作。 可最近一段时间&#xff0c;行业不景气&#xff0c;老板不但下令开启了996的工作模式&#xff0c;更要命的是频频更改需求&#xff0c;弄得大家是敢怒不敢言。 时间一久&#xff0c;很多员工开始消极…

专访关东升:松耦合分层架构设计

关东升,国内知名iOS技术作家,iOS技术顾问,高级培训讲师,移动开发专家。拥有16年软件开发经验、8年培训行业经验。精通iOS、Android和 Windows Phone 7及Html5等移动开发技术。在App Store发布多款游戏和应用软件,擅长移动平台的应用和游戏类项目开发。目前主要从事iOS应用…

Java从小白到大牛第3篇 【进阶篇】-关东升-专题视频课程

Java从小白到大牛第3篇 【进阶篇】—4371人已学习 课程介绍 本视频是智捷课堂推出的一套“Java语言学习立体教程”的视频第三部分&#xff0c;读者以及观看群是初级小白&#xff0c;通过本视频的学习能够成为Java大牛。本主要内容包括&#xff1a;异常处理、集合、泛型、文…

Python项目实战:数据可视化与股票数据分析-关东升-专题视频课程

Python项目实战&#xff1a;数据可视化与股票数据分析—333人已学习 课程介绍 本视频内容包括使用Matplotlib绘制图表、MySQL数据库、Python访问数据库和Lambda表达式。 目录&#xff1a; 23.1 使用Matplotlib绘制图表 23.1.1 安装Matplotlib 23.1.2 图表基本构成要素 23.1…

【ShardingSphere技术专题】「ShardingJDBC实战阶段」SpringBoot之整合ShardingJDBC实现分库分表(JavaConfig方式)

前提介绍 ShardingSphere介绍 ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈&#xff0c;它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar&#xff08;计划中&#xff09;这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据…

关东升给的ios学习路线图(可以借鉴)

来源&#xff1a; http://www.zhijieketang.com/classroom/3/introduction 首页 课程 免费课程 会员 关于我们 登录 注册 首页 iOS课程 iOS会员-iOS开发学习路线图 iOS会员-iOS开发学习路线图 扫二维码继续学习 (0评价) 价格&#xff1a; 1500 金币 学员(17) 课程(37) …

关东升的《从零开始学Swift》3月9日已经上架

大家一直期盼的《从零开始学Swift》于3月9日已经上架&#xff0c;它是关东升老师历时8个月的呕心沥血所编著&#xff0c;全书600多页&#xff0c;此本书基于Swift 2.x&#xff0c;通过大量案例全面介绍苹果平台的应用开发。全书共分5 部分&#xff0c;包括Swift语法篇、Cocoa T…

python从小白到大牛百度云盘_Java从小白到大牛 (关东升著) 中文pdf+mobi版[36MB]

《Java从小白到大牛》是一本Java语言学习立体教程&#xff0c;读者群是零基础小白&#xff0c;通过本书的学习能够成为Java大牛。主要内容包括&#xff1a;Java语法基础、Java编码规范、数据类型、运算符、控制语句、数组、字符串、面向对象基础、继承与多态、抽象类与接口、枚…

SpringBoot 整合 Sharding-JDBC

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、sharding-jdbc简介二、使用步骤 1.新建项目、引入依赖2.代码实战总结 前言 SpringBoot 整合 Sharding-JDBC 提示&#xff1a;以下是本篇文章正文内容&…