二值化图像8联通域标记
数字图像处理课程设计-基于图像处理的车牌识别技术
《数字图像处理》课程设计报告设计题目:基于图像处理的车牌识别技术学院:xxxxxxxxxxxxxxxx专业:xxxxxxxxxxxxxxxxxxxxxxxxxxx姓名:xxxxxxxxxxxxxxxxxxxxxxx学号:xxxxxxxxxxxxxxxxxxx指导教师:xxxxxx2015 年xx 月xx 日摘要智能交通系统已成为世界交通领域研究的重要课题,车牌识别系统作为智能交通系统的核心,起着非常关键的作用。
目前,图像处理技术在车牌识别中的应用研究已经成为科学界的一个重要研究领域。
本课程设计旨在粗浅地运用所学基本原理和知识分析数字图像处理技术在友好环境下的应用(所选车牌识别的车辆图片均为友好环境下,易于处理的实验图片,不具有广泛性)。
以车牌为研究对象,主要研究如何通过图像的预处理、车牌的定位、车牌字符分割和字符识别等一系列过程,完成车牌的识别。
关键词:智能交通、数字图像处理、车牌识别ABSTRACTIntelligent transportation system has become an important research topicin the world of transportation, license plate recognition system as thecore of intelligent transportation system, plays a key role. At present,the application of image processing technology in vehicle license platerecognition has become an important research area of the scientificcommunity.This course is designed to scratch the surface and apply the knowledgeto analyze the basic principles of digital image processing technologyin a friendly environment (experimental vehicle license platerecognition image selected pictures are environment-friendly, easy tohandle, does not have the breadth) . With license plate for the study,the main research how image preprocessing, license plate and licenseplate character segmentation and character recognition process and aseries of complete license plate recognition.Keywords:smart transportation 、Image Processing 、License Plate Recognition目录1、绪论 (4)1.1问题提出 (4)1.2背景及现状分析 (4)1.3目的及意义 (5)1.4开发工具 (5)2、系统设计 (5)2.1总体设计方案 (5)2.2流程图 (5)2.3模块功能分析 (6)2.3.1图像预处理 (6)2.3.2车牌定位 (8)2.3.3字符分割 (8)2.3.4字符识别 (10)3、系统结果分析 (12)3.1本系统结果分析 (12)3.2本系统的不足 (12)4、课程设计总结 (13)5、课程设计体会 (13)6、参考文献 (13)7、附录 (14)1、绪论伴随着工业的迅速发展,城市化的进展和汽车的普及,世界各国的交通量急剧增加。
基于FPGA的二值图像连通域标记快速算法实现
基于FPGA的二值图像连通域标记快速算法实现1 引言在图像自动目标识别和跟踪过程中,首先对图像目标进行阈值分割提取,得到的二值图像通常包含多个连通区域,系统利用图像目标的形状特性对可疑高威胁的飞行目标进行自动识别。
因此,需要对各连通区域块进行分别检测判断,本文采用改进的适合FPGA 实现的快速标记算法对各连通域进行检测提取。
实现二值图像连通体检测通常采用的方法有下几种[1] [2] [3]:区域生长法:首先对图像进行逐行(列)扫描,每遇到一个未标记的“1”像素点,就分配其一个未使用过的标号,然后对其领域进行检测,如有未标记过的“1”像素,则赋予相同的标号。
反复进行这一操作.直到不存在应该传播标号的“1”像素。
然后继续图像行(列)扫描,如检测判未标记的“1”像素则赋予其新的标号,并进行与以上相同的处理。
整个图像扫描结束,算法也就终止。
这种方法可准确地检测出各种类型的连通体.但处理时间也较长.因为要逐一检测每一“1”像素的邻域,且出现“1”像素的重复扫描。
跟踪算法:二值图像中每个取值为“1”的像素被标记一个与其坐标相关的标号,如由n,m 串构成的数。
热后,扫描标记后的图像,并将每十像素的标号改为其邻域内的最小标号。
反复执行这个过程,直到不需要作标记更改为止。
用这种方法处理小而凸的目标时,收敛速度较慢。
本文以适合FPGA 实现为目的,提出一种具有计算规则性的快速二值图像连通域标记算法。
与传统的二值图像标记算法相比,该算法具有运算简单性、规则性和可扩展性的特点,适合以FPGA 实现。
选用在100MHz 工作时钟下,处理384×288像素的红外图像能够达到400 帧/秒以上的标记速度,足够满足实时目标识别系统的要求。
处理速度可以满足大部分实时目标识别系统的要求。
二值图像的贴标签算法
⼆值图像的贴标签算法 贴标签就是将⼆值图中属于同⼀个连通域的像素标记起来。
之前编的程序需要多次遍历图像,所以速度⽐较慢,最近有朋友告诉我⼀种更简单的⽅法。
这⾥对⼆值图中⽩⾊的连通域进⾏贴标签,具体步骤是: 1、按⾏遍历图像,当遇到⼀个⽩点时,说明遇到了⼀个标签区域; 2、将当前⽩点的坐标作为种⼦点⼊栈; 3、判断栈是否为空,若栈⾮空,则在栈顶元素所在位置贴上对应的标签号,同时将⼆值图上的该位置赋成别的颜⾊(表明当前元素已经贴过标签),弹出栈顶元素,并将其8邻域的⽩点⼊栈,重复3直到栈空,这时,当前连通域已经完成贴标签过程; 4、继续按⾏遍历图像,直到遇到下⼀个⽩点,然后重复步骤2-3,直到遍历完图像;1////////////////////////////////////////////////////2// 功能:⼆值图贴标签(针对感兴趣区域)3// 参数:4// pBin - ⼆值图像5// pLabel - 标签矩阵(在外申请,和图像同样⼤⼩,并全部置0)6// lineByte - 图像的每⾏字节数7// roi - 感兴趣区域(左闭右开、上闭下开区间)8// 返回值:9// nLabel - 标签个数10///////////////////////////////////////////////////1112int Labeling(unsigned char *pBin, int *pLabel, int lineByte, CRect roi)13 {14//感兴趣区域的4条边界15int xMin = roi.left;16int xMax = roi.right;17int yMin = roi.top;18int yMax = roi.bottom;1920 stack<CPoint> stk;21int i,j,x,y,k;22int nLabel = 0; //标签编号(从1号标签贴起,⾮标签区域贴0)23for (y=yMin; y<yMax; y++)24 {25for (x=xMin; x<xMax; x++)26 {27if (pBin[y*lineByte+x]==255) //以找到的第⼀个⽩点为种⼦点28 {29 nLabel++;30 stk.push(CPoint(x,y)); //将种⼦点⼊栈31 pLabel[y*lineByte+x] = nLabel;32 pBin[y*lineByte+x] = nLabel*40;3334//若栈⾮空,弹出⼀个元素,并将其8邻域内的⽩点⼊栈,栈空时当前连通域完成贴标签35while (!stk.empty())36 {37 CPoint pt = stk.top();38 stk.pop();39 i = pt.y;40 j = pt.x;41 k = i*lineByte+j;42if (i>yMin && j>xMin && pBin[k-lineByte-1]==255) //左上43 {44 stk.push(CPoint(j-1,i-1));45 pLabel[k-lineByte-1] = nLabel;46 pBin[k-lineByte-1] = nLabel*40;47 }48if (i>yMin && pBin[k-lineByte]==255) //上49 {50 stk.push(CPoint(j,i-1));51 pLabel[k-lineByte] = nLabel;52 pBin[k-lineByte] = nLabel*40;53 }54if (i>yMin && j<xMax-1 && pBin[k-lineByte+1]==255) //右上55 {56 stk.push(CPoint(j+1,i-1));57 pLabel[k-lineByte+1] = nLabel;58 pBin[k-lineByte+1] = nLabel*40;59 }60if (j>xMin && pBin[k-1]==255) //左61 {62 stk.push(CPoint(j-1,i));63 pLabel[k-1] = nLabel;64 pBin[k-1] = nLabel*40;65 }66if (j<xMax-1 && pBin[k+1]==255) //右67 {68 stk.push(CPoint(j+1,i));69 pLabel[k+1] = nLabel;70 pBin[k+1] = nLabel*40;71 }72if (i<yMax-1 && j>xMin && pBin[k+lineByte-1]==255) //左下73 {74 stk.push(CPoint(j-1,i+1));75 pLabel[k+lineByte-1] = nLabel;76 pBin[k+lineByte-1] = nLabel*40;77 }78if (i<yMax-1 && pBin[k+lineByte]==255) //下79 {80 stk.push(CPoint(j,i+1));81 pLabel[k+lineByte] = nLabel;82 pBin[k+lineByte] = nLabel*40;83 }84if (i<yMax-1 && j<xMax-1 && pBin[k+lineByte+1]==255) //右下85 {86 stk.push(CPoint(j+1,i+1));87 pLabel[k+lineByte+1] = nLabel;88 pBin[k+lineByte+1] = nLabel*40;89 }90 }91 }92 }93 }9495return nLabel;96 }。
第13章 二值图像的描述和处理
(2) Hough变换的实现步骤
直线的参数方程比较适合于理解Hough变换的原理,但是 在检测垂直线条和参数的非线性离散化时会遇到困难。 一般编程实现时,把直线表示成以下的极坐标形式:
s = x cosθ + y sinθ
y
θ
(x,y)
θ
s
s
θ
x
s
参数空间变为θ-S空间 对一幅M×N的图像, θ的范围为0~180º; S的范围:0 ~ M 2 + N 2
x-1
y-1 3
x x+1
21
y4 y+1 5
0 67
顺时针追踪方向
边界灰度值 也是1
所围区域的 灰度值均为1
直到重新找到 第1个像素的坐
标后,结束
追踪的演示
追踪的边界如何描述?——采用链码
13.2.2 用链码描述轮廓特征
起始像素P(x,y)
8链码的8个方向: x-1 x x+1
y-1 3
21
s
具体步骤:
(1)设置一个二维数组作为累计数组A[s, θ ],第一维θ 表示角度,θ 范围
在0°~180°;第二维s代表距离,s范围在0~ M 2 + N 2 。 (2)采用边缘检测算子检测直线像素,并二值化。
(3)逐行、逐列扫描像素,当出现边缘像素时,让θ 从0°逐渐变化到 179°,步长为1°或2°,按公式s=xcosθ+ysinθ计算对应的距离,并使累计 数组的对应累计单元A[s, θ ]加1,直至处理完所有像素。
010110 0011110 0
011110 0011110 0
孔
010010 0010000 0
010110 0011000 0
图像处理实验报告实验目的:图像边缘检测和提取:分别用4和8连通的
图像处理实验报告实验目的:图像边缘检测和提取:分别用4和8连通的方法提取图像的边缘,将提取的边缘坐标保存入文本文件,并能通过读取文本文件恢复边缘图像。
实验原理:有两种方法可以提取边缘点:一.轮廓跟踪按照从左到右,从上到下的顺序搜索,找到的第一个黑点一定是最左下的边界点,记为A。
由于边界是连续的,所以每一个边界点都可以用这个边界点对前一个边界点所张的角度来表示。
因此可用下面跟踪准则:从第一个边界点开始,定义初始的搜索方向为沿左上方;如果左上方的点是黑点,则为边界点,否则搜索方向顺时针旋转45度(8连通方法为90度)。
这样一直到找到第一个黑点为止。
然后把这个黑点作为新的边界点,在当前搜索方向的基础上逆时针旋转90度,继续用同样的方法搜索下一个黑点,直到返回最初的边界点为止。
二.轮廓提取二值图图像轮廓提取,掏空内部,如果原图中有一点为黑色,且它的相邻点为黑色(此时是内部点),则将该点删除。
取4个相邻点则为4连通,8个相邻点则为8连通。
根据本实验中图像,为简单的二值图,且有3个黑块,用第一种方法不易跟踪,所以选用第二种方法较简单。
实现方法:所用4连通与8连通方法区别仅是选取的相邻点个数不同,实现方法基本一致,所以不分开论述。
步骤:1.遍历原图像每个像素,如果此像素及周围的点(4个或8个)都为黑点,则该像素认为是内部点,将其删除。
遍历一边,等于掏空图像内部点,仅剩边缘点。
2.用一个结构数组存储图像边缘点的坐标。
在一个新建的文本文件中依次写入图像高度和宽度,边缘像素点总个数,每个边缘点的坐标。
此步骤完成边缘的提取。
3.打开一个新pic图像,读取指定文本文件中的数据,即步骤2中存储内容。
然后在新打开的图像中改变图像高度和宽度,依读入的坐标点将相应点变为黑色,恢复边缘。
此步骤完成边缘的恢复。
4连通和8连通算法的比较:1.4连通算法中检测四个方向的像素点,会将图像内部更多的黑色点腐蚀,所留下的边界是8连通的。
8连通算法相反,所留下的边界是4连通的。
一种新的二值图像连通区域准确标记算法_刘贤喜
2007,43(22)ComputerEngineeringandApplications计算机工程与应用1引言经过阈值分割的二值图像,各个目标被分割成彼此分离的连通区域,对连通区域的标记在机器视觉领域里是一种非常重要的处理方法,连通区域标记过程就是要寻找图像中所有的目标对象,并且将属于同一目标对象的所有像素用唯一的标记值进行标记[1]。
因此通过某种方法把各个连通区域区分开来,分别研究各个连通区域的性质是提取图像特征、进行目标检测和识别的重要一步。
目前,连通区域标记法经常采用的方法主要有以下几种:第一种是边界跟踪—区域填充的方法[2],即先对连通区域进行边界跟踪,找到区域的边界并标记,然后搜索并标记连通区域的内部点,以达到标记不同连通区域的目的。
此方法主要的难点在于如何准确实现多轮廓跟踪和填充,目前解决的方法主要是采用限制区域的方法,此法对目标点距离很近且形状不规则的情况处理不理想,准确率低。
第二种是区域生长法[3],此法先对图像进行顺序扫描,然后每遇到一个目标点,就分配一个未使用的标号,然后对目标点的邻域进行检测,如果有没有标记的目标点,则赋予相同的标号,反复进行此操作,直到图像扫描结束。
这种方法重复扫描次数较多,对连通区域形状的适应性不强。
第三种是跟踪算法[4],二值图像中每个目标点都被标记为一个与其坐标相关的标号,然后扫描标记后的图像,并将每个像素的标号改为其邻域内的最小标号。
反复执行此操作,直到不需要作标记更改为止。
此方法处理小而凸的目标时,收敛速度较慢,处理效果差。
本文在认真分析以上算法的基础上,提出了一种顺序扫描二值图像进行标记的算法。
首先分析了在扫描标记过程中由于连通区域的形状不规则引起的标记冲突,并建立了标记冲突模型,然后在标记算法中增加回溯扫描算法对选择的两种典型情况的标记冲突进行处理,并对其它情况的标记冲突进行了分析说明,实验证明算法可以准确标记出各种形状的连通区域。
2顺序扫描标记算法中的标记冲突设经过阈值分割的二值图像的背景点的像素值为BJ,目标点的像素值为MB,扫描图像的方向为从左到右,从下到上,一种新的二值图像连通区域准确标记算法刘贤喜,李邦明,苏庆堂,刘中合,王玉亮,杨峰LIUXian-xi,LIBang-ming,SUQing-tang,LIUZhong-he,WANGYu-liang,YANGFeng1.山东农业大学机械与电子工程学院,山东泰安2710182.鲁东大学,山东烟台2640251.CollegeofMechanical&ElectronicalEngineering,ShandongAgriculturalUniversity,Tai’an,Shandong271018,China2.LudongUniversity,Yantai,Shandong264025,ChinaE-mail:bullish@sdau.edu.cnLIUXian-xi,LIBang-ming,SUQing-tang,etal.Newexactlabelingalgorithmofconnectedregionsinbinaryimages.ComputerEngineeringandApplications,2007,43(22):76-78.Abstract:Thebasiccharacteristicofcurrentlabelingalgorithmsareanalyzedandanewalgorithmforexactlabelingofconnect-edregionsinbinaryimagesisputforward.First,scanandlabelallthepixelpointsinturnandjudgethelabelingconflictsex-actlyoccurringduringthelabelingsourceandbuildthemodelsofthem,moreoveraddtherescanalgorithminordertoeliminatethelabelingerrorsarousedbylabelconflicts.Experimentalresultshowsthatthealgorithmcanlabelconnectedregionsofanyshapeexactlyandcomparedwiththecurrentlabelingalgorithms,thisonehaslowerrateofrepeatedscanandhigherefficiencyandmoreexactveracityinspeed,soithaswiderapplication.Keywords:binaryimage;connectedregion;regionlabeling;model摘要:在分析已有区域标记算法的基础上,提出了一种新的二值图像连通区域准确标记算法。
针对matlab四连通,和八连通的详解
针对matlab四连通,和八连通的详解功能:标注二进制图像中已连接的部分。
语法:L = bwlabel(BW,n) [L,num] = bwlabel(BW,n)其中BW为输入图像;N可取值为4或8表示连接四连通或八连通区域;NUM为找到的连通区域数目;L为输出图像矩阵,其元素值为整数,背景被标记为0,第一个连通区域被标记为1,第二个连通区域被标记为2,依此类推.所以你不明白的1,2,3即为第1,2,3个连通区域的标记网上给出的解释大部分是不完整的,官网的解释L = bwlabel(BW, n) returns a matrix L, of the same size as BW, containing labels for the connected objects in BW. The variable n can have a value of either 4 or 8, where 4 specifies 4-connected objects and 8 specifies 8-connected objects. If the argument is omitted, it defaults to 8.The elements of L are integer values greater than or equal to 0. The pixels labeled 0 are the background. The pixels labeled 1 make up one object; the pixels labeled 2 make up a second object; and so on.相信大家看了,都头晕的。
现在我给出列子,大家可以更加理解的:(1):A=[0 1 1 0 1 0 10 1 1 0 0 0 10 1 1 0 1 0 1]; [L,M]=bwlabel(A,4);此时L=[0 1 1 0 2 0 40 1 1 0 0 0 40 1 1 0 3 0 4] , M=4(2):A=[0 1 1 0 0 0 10 1 1 0 0 0 10 1 1 0 0 0 1]; [L,M]=bwlabel(A,4);L=[0 1 1 0 0 0 20 1 1 0 0 0 20 1 1 0 0 0 2] M=2;(3):A=[0 1 1 0 0 0 10 1 1 0 0 0 10 1 1 0 1 0 1]; [L,M]=bwlabel(A,4);L=[0 1 1 0 0 0 30 1 1 0 0 0 30 1 1 0 2 0 3] M=3大家看我A中1的位置就应该明白什么意思了吧!!其实大家可以这样理解的:四连通区域是这样的: 11 0 11以上的0是中心像素点1所在的位置就是四连通区域。
二值图像连通域标记优化算法
* 收稿日期: 2010- 04- 26 基金项目: 福建省重点学科项目( 闽教高[ 2006]48 号) 资助。
作者简介: 罗志灶, 男, 福建三明人, 闽江学院电子系讲师, 硕士, 主要从事数字图像和嵌入式系统设计与开发。
第4期
罗志灶, 周赢武, 等: 二值图像 连通域标记优化算法
∀ 35 ∀
标号的共同连通域标号及目标属性, 用于解决冲突标号的处理; 最后, 改进等价标号合并算法, 重新排序
标号, 获得合理的目标标号。
待合并连通域标号为下标, 该值指示临时连通域标号所标记的连通域属于哪个目标。
2. 2 算法简介
本算法分为两个阶段。
第一阶段, 对二值图像进行一次扫描, 按某种连通( 4 邻域或 8 邻域) 规则, 标记所有像素点的待合
并连通域标号, 同时, 按一定的规则, 标记待合并连通域标号的共同连通域标号。由于 4 邻域和 8 邻域 的模板核过小, 无法一次正确标记所有的目标, 会有大量等价标号存在。用共同连通域标号标记各等价
( 闽江学院 电子系, 福建 福州 350108)
摘 要: 在分析现有二值图像像素扫描连通域标记算法的基 础上, 提出 像素扫描 连通域标 记优化算 法。本算法具
有速度快, 算法简单, 易于实现的特点, 仅需两 次扫描, 即 可实现像 素的多 目标标 记。本算 法将背 景也作 为目标 加以标
记, 分两步扫描图像和临时连通域标号矩阵完成连通域的标记和合 并, 采用顺 序存储结构 存储和处 理等价标 号, 算法速
二值图像连通域标记算法与代码收藏
二值图像连通域标记算法与代码收藏10:19:42 二值图像连通域标记算法与代码这里列举二值图像连通域标记算法包括直接扫描标记算法和二值图像连通域标记快速算法一、直接扫描标记算法把连续区域作同一个标记,常见的四邻域标记算法和八邻域标记算法。
1、四邻域标记算法:1)判断此点四邻域中的最左,最上有没有点,如果都没有点,则表示一个新的区域的开始。
2)如果此点四邻域中的最左有点,最上没有点,则标记此点为最左点的值;如果此点四邻域中的最左没有点,最上有点,则标记此点为最上点的值。
3)如果此点四邻域中的最左有点,最上都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。
2、八邻域标记算法:1)判断此点八邻域中的最左,左上,最上,上右点的情况。
如果都没有点,则表示一个新的区域的开始。
2)如果此点八邻域中的最左有点,上右都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。
3)如果此点八邻域中的左上有点,上右都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。
4)否则按照最左,左上,最上,上右的顺序,标记此点为四个中的一个。
代码实现:#include <list>#include <vector>#include <algorithm>// 连通区域属性结构typedef struct tagMarkRegion{std::list<POINT> MarkPoi ntList;//点列表RECT rect;}MarkRegion;// 定义MarkMap 结构,用来存放等价对typedef struct tagEqualMark{int MarkValue1;// 标记值int MarkValue2;// 标记值} EqualMark;// 定义MarkMapping 结构,用来存放标记映射关系typedef struct tagMarkMapping{int nOriginalMark;// 第一次扫描的标记int nMappingMark;// 等价整理之后对应标记} MarkMapping;/*功能说明:八连通标记参数说明:I,表示图像数据指针ImageWidth, 表示图像宽ImageHeight,表示图像高off ,表示偏移量n Flag表示指定标记iColorType,表示颜色类型,(黑点,白点)mark Info ,表示连通区域属性信息返回值:连通点数量, int 类型*/intFillAreaFlag33(LPINTI,intImageWidth,intImageHeight,longoff,intnFlag,intiColo rType,MarkRegion &markInfo){bool bNew;RECT rect;int m,n,i,j,k,nDot=1,offset,offtemp,yMin;int dxy[8],x,y;dxy[0]=-ImageWidth-1;dxy[1]=-ImageWidth;dxy[2]=-ImageWidth+1;dxy[3]=-1;dxy[4]=1;dxy[5]=ImageWidth- 1;dxy[6]=ImageWidth;dxy[7]=ImageWidth+1;rect.left=65535; rect.right=-1;rect.bottom=65535;rect.top=-1;markInfo.MarkPointList.clear();POINT ptTmp;if(I[off]==iColorType && I[off]!=nFlag)// 黑点同时未被标记的情况{I[off]=nFlag;x=off%ImageWidth;y=off/ImageWidth;ptTmp.x = x;ptTmp.y = y;markInfo.MarkPointList.push_back(ptTmp);if(x<rect.left)rect.left=x;if(x>rect.right) rect.right=x;if(y<rect.bottom) rect.bottom=y;if(y>rect.top)rect.top=y;}else{return 0;}for(i=y; i<ImageHeight; i++){bNew=false; yMin=i;for(j=0; j<ImageWidth; j++){offset=i*ImageWidth+j;if(l[offset]==nFlag){for(k=0; k<8; k++)〃八邻域搜索{if(i==O && k<=2) continue; if(i==lmageHeight-1 && k>=5)continue;if(j==0 && (k==0 || k==3 || k==5))continue;if(j==ImageWidth-1 && (k==2 || k==4 || k==7))continue;offtemp=offset+dxy[k];if(I[offtemp]==iColorType && I[offtemp]!=nFlag){I[offtemp]=nFlag; nDot++;m=offtemp/ImageWidth;n=offtemp%ImageWidth;ptTmp.x = n;ptTmp.y = m;markInfo.MarkPointList.push_back(ptTmp);if(n < rect.left)rect.left=n;if(n > rect.right)rect.right=n;if(m < rect.bottom)rect.bottom=m;if(m > rect.top)rect.top=m;y=offtemp/ImageWidth;if(y<=yMin){yMin=y;if(!bNew) bNew=true;}}}}}if(bNew){i=yMin-1;}} markInfo.rect.left = rect.left; markInfo.rect.right = rect.right; markInfo.rect.top = rect.top; markInfo.rect.bottom = rect.bottom; return nDot;}/* 功能说明:四连通标记参数说明:I,表示图像数据指针ImageWidth, 表示图像宽ImageHeight,表示图像高off ,表示偏移量n Flag表示指定标记iColorType,表示颜色类型,(黑点,白点) mark Info,表示连通区域属性信息返回值:连通点数量, int 类型*/intFillAreaFlag22(LPINTI,intImageWidth,intImageHeight,longiColorType,MarkRegion &markInfo){bool bNew;RECT rect;int m,n,i,j,k,nDot=1,offset,offtemp,yMin;int dxy[4],x,y; dxy[0]=-ImageWidth;dxy[1]=1;dxy[2]=ImageWidth;dxy[3]=-1; rect.left=65535; rect.right=-1;rect.bottom=65535;rect.top=-1; markInfo.MarkPointList.clear();POINT ptTmp;if(I[off]==iColorType && I[off]!=nFlag)// 黑点同时未被标记的情况{I[off]=nFlag;x=off%ImageWidth;y=off/ImageWidth;ptTmp.x = x;off,intnFlag,intptTmp.y = y;markInfo.MarkPointList.push_back(ptTmp);if(x<rect.left) rect.left=x;if(x>rect.right) rect.right=x;if(y<rect.bottom)if(y>rect.top)rect.top=y;}else{return 0;}for(i=y; i<ImageHeight; i++){bNew=false; yMin=i;for(j=0; j<ImageWidth; j++){offset=i*ImageWidth+j;if(l[offset]==nFlag){for(k=0; k<4; k++)〃四邻域搜索{if(i==O && k==0) continue; if(i==lmageHeight-1 && k==2)continue;if(j==0 && k==3)continue;if(j==lmageWidth-1 && k==1)continue;offtemp=offset+dxy[k];if(l[offtemp]==iColorType && l[offtemp]!=nFlag){l[offtemp]=nFlag; nDot++;m=offtemp/lmageWidth;n=offtemp%lmageWidth;ptTmp.x = n;ptTmp.y = m;marklnfo.MarkPointList.push_back(ptTmp);if(n < rect.left)rect.left=n;if(n > rect.right)}}if(bNew)if(m < rect.bottom)rect.bottom=m;if(m > rect.top)rect.top=m;y=offtemp/ImageWidth;if(y<=yMin){yMin=y;if(!bNew)bNew=true;}}}i=yMin-1;}}markInfo.rect.left = rect.left;markInfo.rect.right = rect.right;markInfo.rect.top = rect.top;markInfo.rect.bottom = rect.bottom;return nDot;}二、二值图像连通域标记快速算法算法描述首先,在进行标记算法以前,利用硬件开辟独立的图像标记缓存和连通关系数组,接着在视频流的采集传输过程中,以流水线的方式按照视频传输顺序对图像进行逐行像素扫描,然后对每个像素的邻域分别按照逆时针方向和水平方向进行连通性检测和等价标记关系合并,检测出的结果对标记等价数组和标记缓存进行更新,在一帧图像采集传输结束后,得到图像的初步标记结果以及初步标记之间的连通关系,最后,根据标号对连通关系数组从小到大的传递过程进行标号的归并,利用归并后的连通关系数组对图像标记缓存中的标号进行替换,替换后的图像为最终标记结果,并且连通域按照扫描顺序被赋予唯一的连续自然数。
图像分析之连通组件标记算法
图像分析之连通组件标记算法图像处理之连接组件标记算法连接组件标记算法(connected component labeling algorithm)是图像分析中最常⽤的算法之⼀,算法的实质是扫描⼀幅图像的每个像素,对于像素值相同的分为相同的组(group),最终得到图像中所有的像素连通组件。
扫描的⽅式可以是从上到下,从左到右,对于⼀幅有N个像素的图像来说,最⼤连通组件个数为N/2。
扫描是基于每个像素单位,对于⼆值图像⽽⾔,连通组件集合可以是V={1}或者V={0}, 取决于前景⾊与背景⾊的不同。
对于灰度图像来说,连图组件像素集合可能是⼀系列在0 ~ 255之间的灰度值。
算法流程如下:1. ⾸先扫描当前像素相邻的⼋邻域像素值,发现连通像素加以标记。
2. 完全扫描所有像素点之后,根据标记将所有连通组件合并。
算法实现Class⽂件解释:AbstractConnectedComponentLabel:⼀个抽象的Class定义了抽象⽅法doConntectedLabel()同时完成了⼀些公共⽅法ConnectedComponentLabelAlgOne:⼀个容易读懂的连接组件算法完成,没有任何优化,继承上⾯的⾃抽象类ConnectedComponentLabelAlgTwo:⼀个快速的连接组件算法,基于算法优化,取当前像素的四邻域完成扫描与标记合并。
Label与PixelInfo是两个数据结构,⽤来存储算法计算过程中的中间变量。
ImageLabelFilter⽤来测试算法的驱动类,ImageAnalysisUI是现实测试结果的UI类算法运⾏结果:根据标记的索引将组件着⾊。
定义数据结构的代码如下:public class Label {private int index;private Label root;public Label(int index) {this.index = index;this.root = this;}public Label getRoot() {if(this.root != this) {this.root = this.root.getRoot();}return root;}public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}public void setRoot(Label root) {this.root = root;}}Pixelnfo的代码如下:package com.gloomyfish.image.analysis;public class PixelInfo {private int value; // pixel valueprivate int xp;private int yp;public PixelInfo(int pixelValue, int yp, int xp) { this.value = pixelValue;this.yp = yp;this.xp = xp;}public int getValue() {return value;}public void setValue(int value) {this.value = value;}public int getXp() {return xp;}public void setXp(int xp) {this.xp = xp;}public int getYp() {return yp;}public void setYp(int yp) {this.yp = yp;}}抽象的组件连通标记算法Class如下:public abstract class AbstractConnectedComponentLabel {protected int width;protected int height;protected Color fgColor;protected int[] inPixels;protected int[][] chessborad;protected Map<Integer, Integer> neighbourMap;public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}public abstract Map<Integer, List<PixelInfo>> doConntectedLabel();public boolean isForeGround(int tr, int tg, int tb) {if(tr == fgColor.getRed() && tg == fgColor.getGreen() && tb == fgColor.getBlue()) {return true;} else {return false;}}}实现抽象类的算法one的代码如下:import java.awt.Color;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class ConnectedComponentLabelAlgOne extends AbstractConnectedComponentLabel {public ConnectedComponentLabelAlgOne(Color fgColor, int[] srcPixel, int width, int height) { this.fgColor = fgColor;this.width = width;this.height = height;this.inPixels = srcPixel;this.chessborad = new int[height][width];for(int i=0; i<height; i++) {for(int j=0; j<width; j++) {chessborad[i][j] = 0;}}this.neighbourMap = new HashMap<Integer, Integer>();}// assume the input image data is binary image.public Map<Integer, List<PixelInfo>> doConntectedLabel() {System.out.println("start to do connected component labeling algorithm");int index = 0;int labelCount = 0;Label currentLabel = new Label(0);HashMap<Integer, Label> allLabels = new HashMap<Integer, Label>();for(int row=0; row<height; row++) {int ta = 0, tr = 0, tg = 0, tb = 0;for(int col=0; col<width; col++) {index = row * width + col;ta = (inPixels[index] >> 24) & 0xff;tr = (inPixels[index] >> 16) & 0xff;tg = (inPixels[index] >> 8) & 0xff;tb = inPixels[index] & 0xff;if(isForeGround(tr, tg, tb)) {getNeighboringLabels(row, col);if(neighbourMap.size() == 0) {currentLabel.setIndex(++labelCount);allLabels.put(labelCount,new Label(labelCount));} else {for(Integer pixelLabel : neighbourMap.keySet().toArray(new Integer[0])) {currentLabel.setIndex(pixelLabel);break;}mergeLabels(currentLabel.getIndex(), neighbourMap, allLabels);}chessborad[row][col] = currentLabel.getIndex();}}}Map<Integer, List<PixelInfo>> connectedLabels = consolidateAllLabels(allLabels);return connectedLabels;}private Map<Integer, List<PixelInfo>> consolidateAllLabels(HashMap<Integer, Label> allLabels) { Map<Integer, List<PixelInfo>> patterns = new HashMap<Integer, List<PixelInfo>>();int patternNumber;List<PixelInfo> shape;for (int i = 0; i < this.height; i++){for (int j = 0; j < this.width; j++){patternNumber = chessborad[i][j];if (patternNumber != 0){patternNumber = allLabels.get(patternNumber).getRoot().getIndex();if (!patterns.containsKey(patternNumber)){shape = new ArrayList<PixelInfo>();shape.add(new PixelInfo(Color.BLUE.getRGB(), i, j));}else{shape = patterns.get(patternNumber);shape.add(new PixelInfo(Color.BLUE.getRGB(), i, j));}patterns.put(patternNumber, shape);}}}return patterns;private void mergeLabels(int index, Map<Integer, Integer> neighbourMap, HashMap<Integer, Label> allLabels) {Label root = allLabels.get(index).getRoot();Label neighbour;for(Integer key : neighbourMap.keySet().toArray(new Integer[0])) {if (key != index){neighbour = allLabels.get(key);if(neighbour.getRoot() != root) {neighbour.setRoot(neighbour.getRoot());// thanks zhen712,}}}}/*** get eight neighborhood pixels** @param row* @param col* @return*/public void getNeighboringLabels(int row, int col) {neighbourMap.clear();for(int i=-1; i<=1; i++) {int yp = row + i;if(yp >=0 && yp < this.height) {for(int j=-1; j<=1; j++) {if(i == 0 && j==0) continue; // ignore/skip center pixel/itselfint xp = col + j;if(xp >=0 && xp < this.width) {if(chessborad[yp][xp] != 0) {if(!neighbourMap.containsKey(chessborad[yp][xp])) {neighbourMap.put(chessborad[yp][xp],0);}}}}}}}}测试代码可以参考以前的⽂章 -。
图像检测-8二值图像处理
128
0,0,1,1,0,0,1,1, 1,1,0,1,1,1,0,1, 1,1,0,0,1,1,1,1, 0,0,0,0,0,0,0,1, 160
0,0,1,1,0,0,1,1, 1,1,0,1,1,1,0,1, 1,1,0,0,1,1,1,1, 0,0,0,0,0,0,0,0,
193
1,1,0,0,1,1,0,0, 0,0,0,0,0,0,0,0, 1,1,0,0,1,1,1,1, 0,0,0,0,0,0,0,0,
例:下图,八接连(jiēlián)意义下为2个连通域
= “1”号标签
= “2”号标签
共五十五页
8.3.1 贴标签算法(suàn fǎ)
设一个二值矩阵表示一个黑白图像,为讨论 (tǎolùn)方便起见,令“黑=1”,“白=0”。
例:
共五十五页
8.3.1 贴标签算法(suàn fǎ)
1)初始化:设标签号为Lab=0,已贴标签数N=0,标签矩阵 (jǔ zhèn)g为全0阵,按照从上到下,从左到右的顺序寻找 未贴标签的目标点;
共五十五页
8.3.1 贴标签算法(suàn fǎ)
• 如果扫描过的像素标签(biāoqiān)号相同,则 g(i,j)=Lab;
例:
共五十五页
8.3.1 贴标签算法(suàn fǎ)
例:
共五十五页
8.3.1 贴标签算法(suàn fǎ)
• 如果扫描过的像素标签号不相同,例如(lìrú): Lab2>Lab1,则g(i,j)=Lab1,N=N-1,修改所有为Lab2 的像素值,使之为Lab1;
连接与连通域贴标签腐蚀膨胀开运算与闭运算轮廓提取边界跟踪和细线化几何特征的测量81二值图像分析的概念经过图像分割之后获得了目标物与非目标物两个不同的对象但是提取出的目标物存在以下的问题
二值图像连通域标记快速算法实现
二值图像连通域标记快速算法实现算法描述首先,在进行标记算法以前,利用硬件开辟独立的图像标记缓存和连通关系数组,接着在视频流的采集传输过程中,以流水线的方式按照视频传输顺序对图像进行逐行像素扫描,然后对每个像素的邻域分别按照逆时针方向和水平方向进行连通性检测和等价标记关系合并,检测出的结果对标记等价数组和标记缓存进行更新,在一帧图像采集传输结束后,得到图像的初步标记结果以及初步标记之间的连通关系,最后,根据标号对连通关系数组从小到大的传递过程进行标号的归并,利用归并后的连通关系数组对图像标记缓存中的标号进行替换,替换后的图像为最终标记结果,并且连通域按照扫描顺序被赋予唯一的连续自然数。
图 1 标记算法流程本文快速二值图像连通域标记算法分为三个环节:1.图像初步标记:为每个像素赋予临时标记,并且将临时标记的等价关系记录在等价表中2.整理等价表:这一环节分为两个步骤:(1)将具有等价关系的临时标记全部等价为其中的最小值;(2)对连通区域以自然数顺序重新编号,得到临时标记与最终标记之间的等价关系。
3.图像代换:对图像进行逐像素代换,将临时标记代换为最终标记.经过3个环节处理后,算法输出标记后的图像,图像中连通域按照由上到下,由左至右出现的顺序被标以连续的自然数。
1 图像初始标记标记算法符号约定:算法在逆时钟方向检测连通域时用w1,w2表示连续两行的图像数据,在紧接着的顺时钟方向连通域检测时用k0,k表示连续两行经过逆时钟方向标记后的图像数据。
其在工作窗口的位置在图2、3中分别说明;对初始逆时针方向临时标记用Z表示。
Z初始标记值为1。
二值图像连通域标记算法采用8连通判断准则,通过缩小标记范围剔除了图像的边界效应。
为了简化标记处理过程,使标记处理在硬件对一帧图像传输操作时间内结束,标记处理利用中间数据缓存分为连续的两种类型,其中类型1用于直接图像序列传输,硬件发起图像序列传输时,类型1采用逆时钟顺序连通域检测,对2×3工作窗口中的二值像素进行初始标记。
图像分析:二值图像连通域标记
二、连通域
如果像素点A与B邻接,我们称A与B连通,于是我们不加证明的有如下的结论:
三、连通区域的标记
第一行,我们得到两个团:[2,6]和[10,13],同时给它们标记1和2。
下面是这个过程的C++实现,每个等价表用一个vector<int>来保存,等价对列表保存在map<pair<int,int>>里。
整个算法步骤,我们只扫描了一次图像,同时我们对图像中的像素进行标记,要么赋予一个新的标号,要么用它同行P点。
最后不要忘了把C的值加1。
这个过程如下面图像S1中所示。
情况3
1)如果P是外轮廓的起点,也就是说我们是从P点开始跟踪的,那么我们从7号(右上角)位置P1P1开始,看7号在L上标记为一个负值。
如下图所示,其中右图像标记的结果。
2)那么如果P是不是外轮廓的起点,即P是外轮廓路径上的一个点,那么它肯定是由一个点进入的,我们设置为P−
在OpenCV中查找轮廓的函数已经存在了,而且可以得到轮廓之间的层次关系。
这个函数按上面的算法实现起来并不。
一种二值图像连通区域标记的简单快速算法
一种二值图像连通区域标记的简单快速算法作者:葛春平来源:《价值工程》2012年第28期摘要:针对传统二值图像连通区域标记需要对图像进行两次扫描的缺点,提出了一钟新的二值图像连通区域标记算法。
算法借助创建一与图像等大的标记矩阵,通过深度优先搜索算法对图像进行一次扫描后,将标记编号记录在标记矩阵中。
此算法不受连通区域的形状和面积影响,表现出了良好的鲁棒性。
最后通过OpenCV对该算法进行了实现并与传统标记算法进行了时间性能比较。
Abstract: A new connected component labeling algorithm was proposed for improving of traditional algorithm for it need twice scanning of image. Algorithm need a matrix with the same size of image, the label recorded in the matrix by a depth—first search on the image. This algorithm is not affected by the shape and area of the connected component. Finally, implement the Algorithm by OpenCV and compare it with the traditional algorithm in the aspect of time efficiency.关键词:二值图像连通区域标记;标记算法;矩阵Key words: connected component labeling for binary image;labeling algorithm;matrix中图分类号:TP31 文献标识码:A 文章编号:1006—4311(2012)28—0232—020 引言二值图像连通区域标记是从仅由表示背景的“0”像素和表示前景的“1”像素组成的图像中将相互邻接的(4邻域邻接和8邻域邻接)的连通区域用唯一的标记编号进行标记。
用VC++实现图像连通区域标记
Int nMa×Ma rkValue=O:
//记录最大的标识的值
int i,j:
//循环控制变量
/+定义存放等价对的链表,其元素是EquaIMa rk类型,定义
Iist是为了节约存储空问要使用C|ist,应该#lncIude<Afx-
temOl h> }/
CList<EquaIMark,EqualMa rk>『EqualMark: //初始化图像移动指针
//pInne rListAdd,每次向exList中添加的新元素
CPtrList。pInnerListAdd=new CPtrList:
ASSERT(pInne rLjstAdd!=NULL):
/+添加第一个等价对到e×Llst的第一个元素所指向的h
ne r L』jst中
¥/
p JnnerLjstAdd一)AddTa JI(f vojd 半 )JEquaIMark GetHead f)
的判断。 Note2:可以先对等价对进行排序,每次都保证MarkVal—
uel<MarkValue2,这样易于管理等价对。
Note3:在实际工作中,连续寻找出的等价对很容易重
复,将本次找出的等价对和链表中保存的最后一个等价对相比 较,如果不相等的话再存入等价对链表,这样可以大大降低链
表中等价对的重复。 Note4:第一次扫描之后,nMarkValue一1即为nMa)【Mark—
用阳卡争|饕现唐≯’雾蓬通区匆《稼萄参I
|i |i。;::
玉案静。。豫玲。褰建永金赞
一、引言
用图像处理方法做目标检测的一般顺序是:图像预处 理、边缘检测、阈值分割、区域标记、形状判断分析。
进行区域标记之前的图像一般已经被处理为二值图像。 如图1所示,二值图像中可能有多个连通区域。进行图像检 测的时候往往关心的是每个连通区域各自的特性。这就需要 使用区域标记的方法把不同的连通区域区分开来。
一种新的二值图像连通区域准确标记算法
n r e a tv rct i p e S t a d ra pi t . a d mo x c ea i n s e d,O i h swie p l ain e y c o
Ke r s b n r ma e; o n ce e in; go a e i g mo e y wo d : i a i g c n e t d r go r in l b l ; d l y e n
2鲁 东 大 学 , . 山东 烟 台 2 4 2 605
1C l g f Me h n c l& Elc r n c g n e i g S a d n rc l r ie st T i a , h n o g 2 1 1 C i a . o l e o c a i a e e to ia En i e rn , h n o g Ag i u t a Un v r i l ul y, a ’ S a d n 7 0 8, h n n
摘
要 : 分析 已有 区域 标 记 算 法 的基 础 上 , 出 了一 种 新 的 二值 图像 连 通 区域 准确 标 记 算 法 。 顺 序 扫 描 和 标 记 二 值 图像 的各 个 在 提
像 素 点 , 确判 断标 记 过 程 中 出现 的标 记 冲 突 , 建 立 标 记 冲 突的 模 型 , 算 法 中增 加 回溯 扫 描 算 法 , 除标 记 冲 突 引起 的标 记 误 准 并 在 消 差 。 实验证 明该 算 法可 以 准确 标 记 出各 种 形状 的 连 通 区域 , 已有 算 法相 比 扫描 重 复 率低 、 和 运行 准 确 、 度 快 , 有 很 好 的应 用 前景 。 速 具
2 L d n ie i Ya t i S a d n 6 0 5, h n . u o g Un v r t s y, n a , h n o g 2 4 2 C i a E— i: u l h d u e u c mal b l s @s a .d .n i
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
区域生长法利用区域生长的思想,一次生长过程可以标记一整个连通区,只需对图像进行一次扫描就能标记出所有连通区。算法描述如下:
Step1、输入待标记图像bitmap(二值化原图,SDRAM内,u16,只有0x0000与0xffff),初始化一个与输入图像同样尺寸的标记矩阵labelmap(SDRAM内,大小与二值化原图相同,u16,初值0x0000),一个队列queue(SDRAM内,大小与二值化原图相同)以及标记计数labelIndex(unsigned char,最大值255,初值0);
{
int searchIndex, i, length;
labelmap[pixelIndex] = labelIndex;
length = width * height;
for(i = 0;i < 8;i++)
{
searchIndex = pixelIndex + NeighborDirection[i][0] * width + NeighborDirection[i][1];//???
}
}
}
//头步骤1
int ConnectedComponentLabeling(unsigned char *bitmap, int width, int height, int *labelmap)
{
int cx, cy, index, popIndex, labelIndex = 0;
Queue *queue = NULL;
popIndex = PopQueue(queue);
}
}
}
}
//free(queue);
return labelIndex;
}
该算法最坏情况下,将对每个像素点都进行一次八邻域搜索,算法复杂度为O(n)。
//辅助队列
typedef struct QNode
{
int data;
struct QNode *next;
}QNode;
typedef struct Queue
{
struct QNode* first;
struct QNode* last;
}Queue;
void PushQueue(Queue *queue, int data)
{
QNode *p = NULL;
//p = (QNode*)malloc(sizeof(QNode));
p->data = data;
if(queue->first == NULL)
{
queue->first = p;
queue->last = p;
p->next = NULL;
}
else
{
p->next = NULL;
queue->last->next = p;
queue->last = p;
}
}
int PopQueue(Queue *queue)
{
QNode *p = NULL;
int data;
if(queue->first == NULL)
Step3、当queue不为空时,从queue中取出一个生长种子点p1,扫描p1的八邻域点,若存在未被标记过的前景像素,则在labelmap中进行标记,并放入queue中;
Step4、重复Step3直至queue为空,一个连通区标记完成;
Step5、转到Step2,直至整幅图像被扫描完毕,得到标记矩阵labelmap和连通区的个数labelIndex。
//queue = (Queue*)malloc(sizeof(Queue));
queue->first = NULL;
queue->last = NULL;
//memght);//labelmap初始化为0x0000
for(cy =01; cy < height- 1; cy++)
{
return -1;
}
p = queue->first;
data = p->data;
if(queue->first->next == NULL)
{
queue->first = NULL;
queue->last = NULL;
}
else
{
queue->first = p->next;
}
//free(p); //p归到队列原始的SDRAM起始地址
Step2、按从左至右、从上至下的顺序扫描bitmap,当扫描到一个未被标记的前景像素p时(0xffff,2个字节,unsigned short int),labelIndex加1,并在labelmap中标记p(相应点的值赋为labelIndex),同时,扫描p的八邻域点,若存在未被标记的前景像素,则在labelmap中进行标记,并放入queue中,作为区域生长的种子;
if(searchIndex > 0 && searchIndex < length &&
bitmap[searchIndex] ==0xffff255&& labelmap[searchIndex] == 0)
{
labelmap[searchIndex] = labelIndex;
PushQueue(queue, searchIndex);
SearchNeighbor(bitmap, width, height, labelmap, labelIndex, index, queue);
popIndex = PopQueue(queue);
while(popIndex > -1)//当前的联通区域全部标记完成
{
SearchNeighbor(bitmap, width, height, labelmap, labelIndex, popIndex, queue);
{
for(cx =01; cx < width- 1; cx++)
{
index = cy * width + cx;
if(bitmap[index] ==0xffff255&& labelmap[index] == 0)//改点为前景色,且未被标记,index为当前点坐标
{
labelIndex++;
return data;
}
static int NeighborDirection[8][2] = {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};//??
//搜索并标记当前像素的8邻域
void SearchNeighbor(unsigned char *bitmap, int width, int height, int *labelmap, int labelIndex, int pixelIndex, Queue *queue)