• 一个很简单的想法就是通过连通域进行分割,每个字符是一个连通域,不同字符之间是不同的连通域,因为这里没有粘连,所以处理起来是非常方便的。 那么重点就来了,如何实现连通域的分割呢? 原来的打算是通过扫描...

    最近在做一个东西,需要使用字符的分割,如下图所示

    可以看到这里的每个字符互相之间是没有粘连的,那么如何把他们分割开来呢?一个很简单的想法就是通过连通域进行分割,每个字符是一个连通域,不同字符之间是不同的连通域,因为这里没有粘连,所以处理起来是非常方便的。

    那么重点就来了,如何实现连通域的分割呢?

    原来的打算是通过扫描图像,通过寻找不同字符的边缘定位不同的字符,但是我发现对于“O”这种字符,由于他有外边缘和内边缘之分,在实现的过程中还要不断的判断,非常麻烦,纠结了很久最后没有想出简单的方法规避这个问题,最终也没有动手去实现。

    这里介绍一种简单易于实现的方法实现连通域分割,对于我这里的这幅图像是二值图像,我可以通过找到一个未访问过的前景像素点以后,就不断的遍历与之相邻的且未经遍历的前景像素点,直到无法找到这样的像素点,则一个连通域遍历结束。

    下面的算法的流程:

    1、扫描图像,直到当前像素为前景像素且未被访问过,将该像素点入栈CD。

    (1)出栈,把当前像素中的邻域的未被访问的前景像素点压入栈;

    (2)重复(1)中操作,直到栈空,至此找到一个连通域;

    2、重复1中的操作,直到遍历完所有图像。

    这种方法对图像就进行了一次遍历就可以找到所有的连通域,速度快且原理简单易于实现。下面给出实现的代码:

    void getConnectedDomain(Mat& src, vector<Rect>& boundingbox)//boundingbox为最终结果,存放各个连通域的包围盒
    {
    	int img_row = src.rows;
    	int img_col = src.cols;
    	Mat flag = Mat::zeros(Size(img_col, img_row), CV_8UC1);//标志矩阵,为0则当前像素点未访问过
    	for (int i = 0; i < img_row; i++)
    	{
    		for (int j = 0; j < img_col; j++)
    		{
    			if (src.ptr<uchar>(i)[j] == 0 && flag.ptr<uchar>(i)[j] == 0)
    			{
    				stack<Point2f> cd;
    				cd.push(Point2f(j, i));
    				flag.ptr<uchar>(i)[j] = 1;
    				int minRow = i, minCol = j;//包围盒左、上边界
    				int maxRow = i, maxCol = j;//包围盒右、下边界
    				while (!cd.empty())
    				{
    					Point2f tmp = cd.top();
    					if (minRow > tmp.y)//更新包围盒
    						minRow = tmp.y;
    					if (minCol > tmp.x)
    						minCol = tmp.x;
    					if (maxRow < tmp.y)
    						maxRow = tmp.y;
    					if (maxCol < tmp.x)
    						maxCol = tmp.x;
    					cd.pop();
    					Point2f p[4];//邻域像素点,这里用的四邻域
    					p[0] = Point2f(tmp.x - 1 > 0 ? tmp.x - 1 : 0, tmp.y);
    					p[1] = Point2f(tmp.x + 1 < img_col - 1 ? tmp.x + 1 : img_row - 1, tmp.y);
    					p[2] = Point2f(tmp.x, tmp.y - 1 > 0 ? tmp.y - 1 : 0);
    					p[3] = Point2f(tmp.x, tmp.y + 1 < img_row - 1 ? tmp.y + 1 : img_row - 1);
    					for (int m = 0; m < 4; m++)
    					{
    						int x = p[m].y;
    						int y = p[m].x;
    						if (src.ptr<uchar>(x)[y] == 0 && flag.ptr<uchar>(x)[y] == 0)//如果未访问,则入栈,并标记访问过该点
    						{
    							cd.push(p[m]);
    							flag.ptr<uchar>(x)[y] = 1;
    						}
    					}
    				}
    				Rect rect(Point2f(minCol, minRow), Point2f(maxCol + 1, maxRow + 1));
    				boundingbox.push_back(rect);
    			}
    		}
    	}
    }
    最终结果如下图所示:



    展开全文
  • 1. 算法目的:连通域分析算法的目的就是对二值图像进行分析,计算出在每帧图象上目标(这里是人)的位置。这里主要扩充了游程码的思想,将相互毗邻的值为“1”的像素点归结到同一个连通域中,不相互毗邻的点归结到...

     

    1. 算法目的:

    连通域分析算法的目的就是对二值图像进行分析,计算出在每帧图象上目标(这里是人)的位置。这里主要扩充了游程码的思想,将相互毗邻的值为“1”的像素点归结到同一个连通域中,不相互毗邻的点归结到不同的连通域中,并用矩形盒把所有的连通域包围起来,最后得出包围盒得左上、右下顶点坐标,连通域的面积、质心等特征值。

    l 难点:

    ① 如何在求连通域过程中同时确定连通域的质心;

    ② 系统固有噪声,以及人所携带得小目标干扰可能会导致误识别,产生误差。这一点可以通过给连通域的面积设定阀值的方法在一定范围内校正。

    l 缺点:

    无法解决多个人粘连到一起的情况,这时,多个粘连的人会被划分到同一个连通域中,引起记数误差。该算法无法正确处理这种情况,初步准备在该算法之后用其他算法解决。

    2.算法描述:

    l 算法接口

    ① 输入:int data(int width,int height);

    ② 输出:struct boxlist* arealist

    l 数据结构

    ① 连通域链表arealist*

    用来存储连通域分析处理好的,最终结果中的连通域包围盒。

    struct box* arealist

    ② 当前扫描段链表boxlist*

    用来存储正在处理的包围盒。

    struct box{

    int boxX1, boxY1 ; /*包围盒左上顶点的坐标*/

    int boxX2,boxY2 ; /*包围盒右下顶点的坐标*/

    int area ; /*该连通域的面积,即点数*/

    float centerX,centerY ; /*质心的坐标*/

    struct box* next ; /*指向链表的下一个节点*/

    int flag ; /*处理标志*/

    }boxlist* ;

    ③正在处理的行的扫描段链表seglist*

    用来存储上一行、当前行的扫描段。

    struct box{

    int x, y ; /*包围盒左上顶点的坐标*/

    struct box* box ; /*该段所属的box*/

    }seglist*;

    l 处理过程

    ① 从运动提取模块(唐华松负责)接收一幅数据帧data(int width,int height);

    ② 从第一行开始自左向右逐位扫描该数据帧,直到找到包含有扫描段(连续为“1“的段)的行,用链表seglist*保存各扫描段seg*,并用链表boxlist*保存各扫描段的包围盒box*,设置各坐标,并记算连通域面积,令各seg->box=box; box->flag=0;如果找不到包含扫描段的行,则转至①;

    ③ 扫描下一行,将各扫描段装入seglist1*;

    ④ 对seglist1*中的每一个扫描段seg1*,判断它与seglist*中各扫描段的邻接情况:

    ⑴如果该扫描段seg1*与seglist*中的所有扫描段都没有邻接的关系,则将该扫描段的包围盒box1*插入到boxlist*中,并令seg1->box=box1,box1->flag=1;

    ⑵如果该扫描段seg1*与seglist*中的一个或多个扫描段有邻接关系,则先合并seglist*中这些有邻接关系的扫描段的包围盒,box->x1=min(有邻接的box->x1),box->y1=min(有邻接的box->y1),box->x2=max(有邻接的box->x2), box->y2=max(有邻接的box->y2);

    然后,令seg1*->box=box,box->flag=1, box->x1=min(seg1->x1, box->x1),box->x2=max(seg1->x2, box->x2),box->y2= y;

    ⑶重复⑴、⑵的处理直到完成seglist1*的所有扫描段。

    ⑤ 释放seglist*各节点,然后,令seglist=seglist1;

    ⑥ 扫描boxlist*链表,对每一个节点box*,如果box->flag=0,则将该节点从boxlist*中移去,并插入到链表arealist*中(这里需要进一步考虑噪声滤波,初步考虑根据连通域的点数滤掉除人以外的其他干扰物体),为已经处理好的连通域;如果box->flag=1,则令box->flog=0。

    ⑦ 重复步骤③至⑥直到处理完当前帧的所有行。

    ⑧ 重复步骤①至⑦,处理下一帧图象。

    l 算法实现

    算法的实现过程见下图。

     

    各函数功能及输入输出

    1.Area.c文件

    该文件是主要处理程序,处理对连通域的扫描合并,其主要函数如下:

    (1) struct seg *getCurSegList(int data[height][width],int row)

    功能:扫描一行象素点,找到象素点为1的点,并根据是否连续分成不同的SegList,然后用指针连接起来。

    输入:将每帧图象的象素点值(0,1)用二维数组data存放,作为该函数的输入,并且将处理的当前行值row输入。

    输出:返回指针,该指针是第row行的扫描得到的SegList链表表头。

    (2) struct box *getArea(int data[height][width])

    功能:针对每一行调用getCurSegList函数,得到每行连通的象素段SegList,然后针对

    每个SegList判断它的前后左右是否有相联结的SegList,如果有则合并,然后

    加入到一个boxlist的链表中,并对boxlist链表中的元素判断,如果没有相连

    接段的则加入到arealist中。

    输入:二维数组data(存放每帧象素点值)。

    输出:返回指针,该指针是经处理得到的连通域的链表表头areaList。

    2.GetAreaList.c文件:

    该文件包括一个函数getAreaList,所示如下:

    struct box *getAreaList(int data[height][width],int fno)

    功能:对处理得到的连通域(数据类型为box)的某些参数赋值,比如帧号,标记位flag,

    计算连通区域的质心位置(横坐标和纵坐标),并滤掉一些噪声干扰(如果连通区

    域的面积小于AREAmin,则忽略掉)。

    输入:二维数组data(存放每帧象素点值),当前帧的帧号fno.

    输出:处理完全的连通域链表表头areaList.

    展开全文
  • 1.思路是用深度遍历,对图片进行二值化处理,先找到一个黑色像素,然后对这个像素的周围8个像素进行判断,如果没有访问过,就保存起来,...传入二值化后的图片进行连通域分割""" pixdata = img.l...

    1.思路是用深度遍历,对图片进行二值化处理,先找到一个黑色像素,然后对这个像素的周围8个像素进行判断,如果没有访问过,就保存起来,然后最后这个数组的最小x和最大x就是x轴上的切割位置。这种分割的方法还是只能适用于没有粘连的验证码,比垂直分割的好处是,可以处理位置比较奇怪的验证码。

    def cfs(img):
        """传入二值化后的图片进行连通域分割"""
        pixdata = img.load()
        w,h = img.size
        visited = set()
        q = queue.Queue()
        offset = [(-1,-1),(0,-1),(1,-1),(-1,0),(1,0),(-1,1),(0,1),(1,1)]
        cuts = []
        for x in range(w):
            for y in range(h):
                x_axis = []
                #y_axis = []
                if pixdata[x,y] == 0 and (x,y) not in visited:
                    q.put((x,y))
                    visited.add((x,y))
                while not q.empty():
                    x_p,y_p = q.get()
                    for x_offset,y_offset in offset:
                        x_c,y_c = x_p+x_offset,y_p+y_offset
                        if (x_c,y_c) in visited:
                            continue
                        visited.add((x_c,y_c))
                        try:
                            if pixdata[x_c,y_c] == 0:
                                q.put((x_c,y_c))
                                x_axis.append(x_c)
                                #y_axis.append(y_c)
                        except:
                            pass
                if x_axis:
                    min_x,max_x = min(x_axis),max(x_axis)
                    if max_x - min_x >  3:
                        # 宽度小于3的认为是噪点,根据需要修改
                        cuts.append((min_x,max_x + 1))
        return cuts
    
    def saveSmall(img, outDir, cuts):
        w, h = img.size
        pixdata = img.load()
        for i, item in enumerate(cuts):
            box = (item[0], 0, item[1], h)
            img.crop(box).save(outDir + str(i) + ".png")
    img = Image.open('out/51.png')
    
    saveSmall(img, 'cfs/', cfs(img))
     

    参考这篇文章 http://www.hi-roy.com/2017/09/20/Python%E9%AA%8C%E8%AF%81%E7%A0%81%E8%AF%86%E5%88%AB2/

     

    http://www.waitingfy.com/archives/3919

     
    展开全文
  • matlab连通域处理函数

    2019-01-15 10:27:48
    %提取ROI mouse=imrect; pos=getPosition(mouse);%用鼠标画一个矩形,返回矩形左上角x坐标、左上角y坐标、矩形宽度w、矩形高度h ROI=[pos(1) pos(2) pos(3) pos(4)]; J = imcrop(I,ROI); 1、 matlab函数bwareaopen...

    %提取ROI
    mouse=imrect;
    pos=getPosition(mouse);%用鼠标画一个矩形,返回矩形左上角x坐标、左上角y坐标、矩形宽度w、矩形高度h
    ROI=[pos(1) pos(2) pos(3) pos(4)];
    J = imcrop(I,ROI);

    1、 matlab函数bwareaopen──删除小面积对象
    格式:BW2 = bwareaopen(BW,P,conn)
    作用:删除二值图像BW中面积小于P的对象,conn为4或8,默认情况下使用8邻域。
    算法:
    (1)Determine the connected components.
    L = bwlabeln(BW, conn);
    (2)Compute the area of each component.
    S = regionprops(L, 'Area');
    (3)Remove small objects.
    bw2 = ismember(L, find([S.Area] >= P));

    2、matlab函数bwarea──计算对象面积
    格式:total = bwarea(BW)
    作用:估计二值图像中对象的面积。
    注:该面积和二值图像中对象的像素数目不一定相等。

    3、matlab函数bwboundaries──获取对象轮廓
    格式:B = bwboundaries(BW,conn)(基本格式)
    作用:获取二值图中对象的轮廓,和OpenCV中cvFindContours函数功能类似。B是一个P×1的cell数组,P为对象个数,每个cell 是Q×2的矩阵,对应于对象轮廓像素的坐标(i,j)即多少行多少列。

    4、matlab函数imregionalmin──获取极小值区域
    格式:BW = imregionalmin(I,conn)
    作用:寻找图像I的极小值区域(regional maxima),默认情况conn=8。


    5、matlab函数bwulterode──距离变换的极大值
    格式:BW2 = bwulterode(BW,method,conn)
    作用:终极腐蚀。寻找二值图像BW的距离变换图的区域极大值(regional maxima)。用于距离变换的距离默认为euclidean,连通性为8邻域。

    6、regionprops统计被标记的区域的面积分布,显示区域总数。
    函数regionprops语法规则为:STATS = regionprops(L,properties)
    该函数用来测量标注矩阵L中每一个标注区域的一系列属性。
    L中不同的正整数元素对应不同的区域,例如:L中等于整数1的元素对应区域1;L中等于整数2的元素对应区域2;以此类推。
    返回值STATS是一个 长度为max(L()的结构数组,结构数组的相应域定义了每一个区域相应属性下的度量。
    Properties可以是由逗号分割的字符串列表、包含字符 串的单元数组、单个字符串'all'或者'basic'。如果properties等于字符串'all',则表4.1中的度量数据都将被计算;如果properties等于字符串'basic',则属性:'Area','Centroid'和'BoundingBox'将被计算。表1就是所有有效的属性字符串。

    表1 属性字符串列表
    properties值
    'Area':图像各个区域中像素总个数
    'BoundingBox':包含相应区域的最小矩形        
    'Centroid':每个区域的质心(重心)        
    'MajorAxisLength':与区域具有相同标准二阶中心矩的椭圆的长轴长度(像素意义下)       
    'MinorAxisLength':与区域具有相同标准二阶中心矩的椭圆的短轴长度(像素意义下)       
    'Eccentricity':与区域具有相同标准二阶中心矩的椭圆的离心率(可作为特征)        
    'Orientation':与区域具有相同标准二阶中心矩的椭圆的长轴与x轴的交角(度)        
    'FilledArea':填充区域图像中的on像素个数        
    'ConvexHull':包含某区域的最小凸多边形       
    'ConvexImage':画出上述区域最小凸多边形        
    'ConvexArea':填充区域凸多边形图像中的on像素个数       
    'EquivDiameter':与区域具有相同面积的圆的直径        
    'Solidity':同时在区域和其最小凸多边形中的像素比例        
    'Extent':同时在区域和其最小边界矩形中的像素比例    
    'PixelIdxList':存储区域像素的索引下标    
    'PixelList':存储上述索引对应的像素坐标

     

    展开全文
  • 1.先搜索标记二值图像的所有连通域 2.根据连通域的形状和进邻连接等特征筛选,合并连通域。对于文档而言,连通域应该符合一定的高度,宽度以及相互间的比例。可以通过某种方法进行度量(根据文档特征),进行区域...



    文献:

    《复杂车辆图像中的车牌定位与字符分割方法》:

    1.先搜索标记二值图像的所有连通域

    2.根据连通域的形状和进邻连接等特征筛选,合并连通域。对于文档而言,连通域应该符合一定的高度,宽度以及相互间的比例。可以通过某种方法进行度量(根据文档特征),进行区域筛选合并。文中通过寻找波谷位置进行定位,接着以已有的车牌进行匹配。

    《一种低质量车辆牌照的字符分割方法》

    主流方法:基于投影+先验规则/滤波分析      无法分析倾斜,污损情况

             连通区域分析                    对字符粘连,断裂情况不佳

             机器学习方法                    HMM与上述两种方法结合

             自适应形态学      

    文章方法:需要先验知识,和车牌的特征对车牌进行精确分割。特点:是两级的分割方法预分割和精细分割

    实验:

    用连通区域分析的方法对字符图像进行处理,首先二值化后,对图像开运算,去除细小的噪声,然后对图像中八领域方式连接的连通域进行标记,计算连通区域的框线特征,包括左上顶点坐标,长宽,依照这些数据对图像进行分割。除了i,j对字母的分割效果还是不错的。

    源程序:

     clear all;clc;close all;
    [fn pn fi]=uigetfile('*.*','choose a picture');
    Img=imread([pn fn]);
    [~,~,c]=size(Img);
    if  c==1
        f2= ~im2bw(Img,graythresh(Img));
    else 
        Img=rgb2gray(imread([pn fn]));
        f2= ~im2bw(Img,graythresh(Img));
    end
    f=f2;
    f=bwareaopen(f,50);
    % figure(3);imshow(f);
    str=strel('square',2);
    % f=imclose(f,str);
    % str=strel('line',5,0);
     f=imdilate(f,str);
    figure(3);imshow(f);




    [L,num] = bwlabel(f,8);%标注二进制图像中已连接的部分
    Feastats = regionprops(L,'basic');%计算图像区域的特征尺寸
    Area=[Feastats.Area];%区域面积
    b=[Feastats.BoundingBox];%[x y width height]字符的大小
    sub=cell(1,num);%存储分割后的图像
    figure(1);
    %===============分割过程==============%
    for i=1:num
        a=floor(b((i-1)*4+2));%b中字符的特性是按4个一组放的,前两个为左上顶点坐标,后两个为长宽。
         if a==0
             a=1;
        end
        e=b((i-1)*4+4);
        d=floor(b((i-1)*4+1));


         if d==0
             d=1;
         end
        g=b((i-1)*4+3);
        
        sub{1,i}=f2(a:a+e,d:d+g);
         subplot(1,num,i);imshow(sub{1,i});
    end


     figure(2),imshow(f)
    hold on
    for k=1:num
        [r,c]=find(L==k);
        rbar=mean(r);
        cbar=mean(c);
        plot(cbar,rbar,'Marker','o','MarkerEdgeColor','k','MarkerFaceColor','k','MarkerSize',10);
        plot(cbar,rbar,'Marker','*','MarkerEdgecolor','w');
    end

    同的投影算法比较,连通域对数字的分割效果更好。


    展开全文
  • python验证码识别2:投影法、连通域法分割图片 9月 20, 2017 发布在 Python 今天这篇文章主要记录一下如何切分验证码,用到的主要库就是Pillow和Linux下的图像处理工具GIMP。首先假设一个固定位置和宽度、无粘连...
  • 上一次通过投影的方式进行了文本块分割,但这种方法有很大的局限性,要求分行清晰、不能有字符跨多行、不能倾斜...简单讲,就是把图像做一定的膨胀操作,使得同一个字符的不同部分以及相邻字符相互重叠到一起,变成...
  • 肺实质区域修补分割  历时一个多月,终于将肺实质区域修补分割实现了。特此共享,希望对有需要的人有所帮助...原始图像如下,像素为512*512。最初格式为dicom,因我的matlab7读入报错,所以使用dicom阅读器将其
  • 切割前: 切割后:    代码: #-*-coding:utf-8-*- from PIL import Image ...传入二值化后的图片进行连通域分割""" pixdata = img.load() w, h = img.size visited...
  • 这篇文章主要给大家介绍了关于python验证码识别教程之利用投影法、连通域法分割图片的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看...
  • 粘连细胞分割.zip

    2020-07-08 23:31:41
    python和matlab两个版本,本代码采用圆度检测的方法,筛选粘连细胞,并对粘连细胞进行分割。
  • halcon 粘连物体分割

    2018-09-05 16:30:09
    Halcon的官方例程,都是顶级工程师的思想精华,大多实际项目的难度并没有官方例程复杂,由于官方例程针对的是有一定Halcon基础的,本人在此次处理时添加了详细的中文注释,做出一定的调整,更容易让读者理解和接受。...
  • 转自:https://blog.csdn.net/icvpr/article/details/10259577OpenCV_连通区域分析(Connected Component Analysis/Labeling)【摘要】本文主要介绍在CVPR和图像处理领域中较为常用的一种图像区域(Blob)提取的方法...
  • Matlab 形态学图像处理(原文作者很是细心,感谢!)  形态学是提取图像特征的有力工具,针对二值图像和灰度图像的腐蚀、膨胀和重构的基本操作可以组合使用,以执行非常宽泛的任务。其练习代码和结果如下:   ...
  • 涉及到的函数为import matplotlib.pyplot as plt from skimage import measure, color labels = measure.label(img4[:,:,0], connectivity=2) dst = color.label2rgb(labels) plt.imshow(dst)
  • 【OpenCV实战】两种不同情况下的目标计数Python实现详解(含代码)一级目录二级目录三级目录 一级目录 二级目录 三级目录
  • 【20200521】数字图像处理DIP课程课业打卡十之二值图像的分析 一、DIP课程课业打卡十之二值图像的分析 一、填空题 1、图像膨胀 2、图像腐蚀 二、判断题 二、知识巩固 1、二值图像的分析—— 问题的提出 2、二值图像...
  • 图像分析:阶段总结

    2017-10-12 14:33:40
    本周的实验都是基于连通域的算法,连通域里面有一个很重要的概念就是阈值,阈值的选择非常关键,主要是本项目每个图片里面的目标灰度值与噪声灰度值差别不大,并且有些地方带粘连连通域求解之后会站在一起,无
  • 20.数字图像处理复习

    2020-05-19 11:14:47
    3.数字图像处理相对于模拟图像处理的优点有: C. 图像采集环境要求高(错误答案) A. 精度高 B. 再现性好 D. 通用性好 4.数字图像处理的主要研究内容有: D. 图像存储(错误答案) A. 图像分割 B. 图像增强 C. 图像...
  • 8 二值图像分析 目录(一)二值图像分析基本概念(二)二值图像分析方法1)贴标签2)腐蚀3)膨胀4)开运算与闭运算 问题的提出 经过图像分割之后,获得了目标物与非目标物两种不同的对象。但是提取出的目标物存在...
1 2 3 4 5 ... 7
收藏数 126
精华内容 50