最近做验证码识别,原本用MATLAB已经实现的整个识别模型,不过代码要部署在Linux服务器上还是需要用另外的语言实现,于是决定用Python + OpenCV来实现。

bwlabel函数的作用是检测二值图像中连通域的个数及为每个连通域标记后的矩阵。

关于连通域检测算法我是参考的http://blog.sina.com.cn/s/blog_ad81d4310102vmll.html 这篇文章中的基于行程的标记 方法,以及传统的Two-Pass方法。

传统的Two-pass方法中关于连通域标记的规则如下:

1.逐行扫描图像上的点,检查每个点是否是前景点,如果不是,继续扫描;

2.检查该前景点的左边的点和上边的点

如果有一个为前景点,则为当前扫描点标记和此点相同编号;

如果两个都是前景点,则选择标号小的,为当前扫描点标记编号;这里注意如果两个都是前景点且标号不同,需要把标号小的点设为标号大的点的父节点,以方便第二遍扫描的时候用并查集算法(参考 利用不相交集实现等价元素的聚类 )合并;

如果都不是,则赋值目前标号label,label++(label初始值为零);

3.再次扫描图像,利用并查集算法合并联通的不同的label的区域。

第一二步就是一个二重循环遍历矩阵,对矩阵中每个元素的上邻元素和左邻元素进行判断来标记该元素,并扩充等价对列表。这两步都比较好理解。

经过标记后会得到一个标记后的矩阵和一个等价对列表。最后一步是将等价值列表合并成具有相同标记的标记集合,比如[(1,2),(1,5),(2,3),(4,6),(7,8)],那么需要把这幅等价值表转换成[(1,2,3,5),(4,6),(7,8)]这三个区域,最后通过这个新的表去重新遍历标记后的矩阵,将其他标记值修改为最小的标记值,这样最后就能得到一个标记了的连通域矩阵。

下面在仿照上面博客中的对等价值的处理。这篇博客中是用 C++ 来实现广度优先搜索,由于其中用到指针去改变栈的大小,这样能实现循环的时候边界长度随着栈的大小变化而动态的变化。

在java中这样在循环中动态改变列表的值数量是会报异常的,python中这样做的时候循环的边界大小不会随着列表的大小改变而改变。

参照博客中的算法,思路如下:

每个元素看做是无向图中的点,等价对看作是一条连通路径,所以先用等价对列表初始化一个连通矩阵 data。
创建一个列表 labelFlag 标记每个点是否被访问了。
对labelFlag进行遍历,如果labelFlag[i] == 0就表示i点没有被访问,!= 0就表示该点已经被访问了,则跳过该点继续遍历下一个点。
如果临时列表tempList为空,且遇到labelFlag[i]没有被访问,则说明需要创建一个新的连通域了。
如果tempList不为空,则将tempList列表的最后一个元素出栈得到元素index,然后判断index是否已经被访问了,如果没有被访问则继续对index为起点的路径访问;
如果index所指的行的元素不为0且不为 0 的元素所在的列对应的labelFlag[j]没有被访问,就把j压入tempList列表,并把j标记压入到连通集合中。

经过上面的遍历就能获得结果。

为了解决这个问题,我的代码实现如下:

import numpy as np

data = [(1, 2), (2, 4), (1, 5), (3, 6), (7, 8)]
maxLabel = np.max(data)
eqTab = np.zeros((maxLabel, maxLabel)) for left, right in data:
eqTab[left - 1, right - 1] = 1
eqTab[right - 1, left - 1] = 1 labelFlag = np.zeros(maxLabel) tempList = [1]
eqList = []
data_result = [] for i in xrange(maxLabel):
if labelFlag[i]:
continue
eqList = [i + 1]
tempList = [i + 1]
for k in xrange(maxLabel):
if not tempList:
break
index = tempList.pop()
for j in xrange(maxLabel):
if eqTab[index - 1, j] and not labelFlag[j]:
tempList.append(j + 1)
eqList.append(j + 1) labelFlag[index - 1] = 1 data_result.append(eqList) print data_result

输出结果为:[[1, 2, 5, 4], [3, 6], [7, 8]]

这个实现算法比较直白,完全是按照算法思路来写的程序,没有进一步考虑过优化什么的,读者可以自己琢磨琢磨。

等我把整个bwlabel算法写完再附上完整的源码。

Python实现MATLAB中的 bwlabel函数的更多相关文章

  1. python实现类似于Matlab中的magic函数

    参考这篇文章的代码封装了一个类似Matlab中的magic函数,用来生成魔方矩阵. #!/usr/bin/env python # -*- coding: utf-8 -*- import numpy ...

  2. matlab中的eval函数使用

    matlab中的eval函数使用 在matlab的命令行窗口中输入help eval命令回车就可以看到eval函数的官方解释,大概的意思就是执行matlab中的表达式,计算expression表示的代 ...

  3. Matlab中的eig函数和Opecv中eigen()函数的区别

    奇异值分解的理论参见下面的链接 http://www.cnblogs.com/pinard/p/6251584.html https://blog.csdn.net/shenziheng1/artic ...

  4. Matlab中的fread函数

    Matlab中fread函数用法    "fread"以二进制形式,从文件读出数据. 语法1:[a,count]=fread(fid,size,precision) 语法2:[a, ...

  5. matlab中的sub2ind函数

    在matlab中,矩阵的存储是按列优先,sub2ind函数将矩阵中指定元素的行列下标转换成存储的序号,即线性索引号.下面,我们举例子进行说明. 1 建立一个3*4*2的矩阵 rng(0,'twiste ...

  6. matlab中CRC的函数使用

    先学习一下matlab中CRC函数. 语法如下: h = crc.generator(‘Polynomial', polynomial, ‘param1', val1, etc.) 再看一个例子就比较 ...

  7. matlab中help所有函数功能的英文翻译

    doc funname 在帮助浏览器中打开帮助文档 help funname 在命令窗口打开帮助文档 helpbrowser 直接打开帮助浏览器 lookfor funname 搜索某个关键字相关函数 ...

  8. python开发_python中的range()函数

    python中的range()函数的功能hen强大,所以我觉得很有必要和大家分享一下 就好像其API中所描述的: If you do need to iterate over a sequence o ...

  9. Python连载43-current中的map函数、xml文件

    一.current中的map函数 1.map(fn,*iterable,timeout=None) (1)跟map函数相类似(2)函数需要异步执行(3)timeout代表超时时间 (4)map和sub ...

随机推荐

  1. 123457123456#0#-----com.twoapp.mathGame13--前拼后广--13种数学方法jiemei

    com.twoapp.mathGame13--前拼后广--13种数学方法jiemei

  2. ElasticSearch——冷热(hot&warm)架构部署

    背景 最近在做订单数据存储到ElasticSearch,考虑到数据量比较大,采用冷热架构来存储,每月建立一个新索引,数据先写入到热索引,通过工具将3个月后的索引自动迁移到冷节点上. ElasticSe ...

  3. nginx+mysql双主搭建

    说明:mysql双主架构经过测试在生产环境中使用没有问题,但是还是建议使用读写分离, Mysql主主同步环境部署: centos 7.4 三台云主机:mysql1 :10.1.1.142 mysql2 ...

  4. 使用mysqldump备份表数据

    使用mysqldump备份远程表数据到本地 下面的命令是使用mysqldump命令备份远程数据库的一张表的信息,并将信息保存到本地的一个文件的一个示例: mysqldump -h 192.168.1. ...

  5. MySQL建表时添加备注以及查看某一张表的备注信息

    建表的时候对列和表明添加备注: DROP TABLE IF EXISTS test_table; CREATE TABLE test_table ( ID INTEGER AUTO_INCREMENT ...

  6. DB2存储过程简单示例

    在这个示例中,我们将在DB2中创建一个名为DEMO1201的存储过程. 该存储过程的输入参数IN_NAME和IN_CREDITCARD,表示用户的姓名和身份证号. 该存储过程的作用是根据身份证号来新建 ...

  7. LODOP在页面让客户选择打印机

    获取打印机列表可以放在onload事件里,如过当前是使用的c-lodop,由于websoket链接需要时间,一进入页面可能会报错,被准备好或网页没下载完成等,也可以在点击事件里让用户获取打印机.之前写 ...

  8. 02. oc语言是动态语言

    参照着知乎上大神们给的解释,(https://www.zhihu.com/question/19918532)自己要总结下知识: 自己初级并没有理解 动态.静态.强类型.弱类型 语言的这些含义,区分. ...

  9. Ubuntu下配置LVS【h】

    以后服务器只用CentOS和Ubuntu.下午用redhat装个lvs装了一下午都没搞好,TNND的.果断用Ubuntu,不到两个小时就搞定了. 原文参见: http://kamengwang.blo ...

  10. 【计算机视觉】Selective Search for Object Recognition论文阅读1

    Selective Search for Object Recognition 作者: J. R. R. Uijlings, K. E. A. van de Sande, T. Gevers, A. ...