找回密码
 加入
搜索
查看: 7726|回复: 7

[效率算法] [千分悬赏]关于验证码识别中去除噪声的讨论(附单双噪点去除例子,详细注释可供学习)

 火.. [复制链接]
发表于 2013-4-19 16:33:19 | 显示全部楼层 |阅读模式
悬赏1000金钱已解决
本帖最后由 tryhi 于 2013-4-19 21:24 编辑

其实之前开过这个贴,后来没人回复之后好像被关闭了http://www.autoitx.com/thread-37246-1-1.html
发出去的分收不回大家尽力拍砖。



注:图中的软件是用了疯子前辈的软件http://www.autoitx.com/forum.php?mod=viewthread&tid=32094
由于没学过验证码识别,所以提出的问题可能有点弱
图中红色(单点双点)、绿色(三点相连)的点是要去除的(所谓的红色绿色是我标出来,实际上图片已经二值化了,见代码),目前我只想到了红色点的去除,关于绿色点没有比较好的方案,红色的思路是这样的,搜索该点周围8个点,如果空白,则去除,如果周围只有1个点,则搜索这一个的周围8个点,发现它也只有一个,就两个都去除,这样就能实现去除红色点的效果,代码如下,可能效率、思路、代码都不是很好,关于三点相连或者抱团的点,应该怎么去除比较好?R的右腿那里有个很浅的红色圆圈那里三个点是不用去除的,怕有人误除,特指出来。


以下代码为去除单点双点的算法



;去除单双噪点算法例子
#include <Array.au3>
$string = "                                                                      0                          "&@CRLF& _
"                  0 00                                                                           "&@CRLF& _
"                                       00                     0       0          0               "&@CRLF& _
"   0                                    0                              0              0      0   "&@CRLF& _
"                     0                         000                                0              "&@CRLF& _
"                                  0                                              0               "&@CRLF& _
"          0                      0                                      0                        "&@CRLF& _
"                                0                  0                   00                        "&@CRLF& _
"                                                   0                                   0         "&@CRLF& _
"     00       00         0                                                                0      "&@CRLF& _
"       00000000          0                                                            0          "&@CRLF& _
"         00              0               0     0                                    0000000      "&@CRLF& _
"         00                                               0                0     00000    000    "&@CRLF& _
"         00                        0                                               00       00 0 "&@CRLF& _
"         00                  0                                                      00       00  "&@CRLF& _
"    0   00                   000000000                        0                    00       00   "&@CRLF& _
"0       00     0              00    000                0000000000                  00        00  "&@CRLF& _
"        00             0      00     000             000       0       0           00        000 "&@CRLF& _
"        00                    00      00              00  0     0              0   00   0    00  "&@CRLF& _
"       00                     00 0    00              00   0                       00        00  "&@CRLF& _
"       00           0         00      000   0         00                           00         00 "&@CRLF& _
"       00              0      00     00               00  0  0                     000        00 "&@CRLF& _
"       00                     00    0000 0            00     0   0                  00        00 "&@CRLF& _
" 0     00                     0000000      0          00     00                     00        00 "&@CRLF& _
"       00                     00  00           0   0   00000000   0   0             00  0     00 "&@CRLF& _
"        00          0      0  000   00                  00    00     0               00        00"&@CRLF& _
"        00                     00   00                  000    0                     00        0 "&@CRLF& _
"        00                     00 0  00                 00     0                     00       00 "&@CRLF& _
"        00                     00  0000                 00                           00       0  "&@CRLF& _
"       00                      00    0000               00                         0  00     00  "&@CRLF& _
"       00                      00     00                00                        0   00   000   "&@CRLF& _
"   00  00                      00     00             0   00                      0   0000000     "&@CRLF& _
"     00000000          0      0000     000               00                         000          "&@CRLF& _
"                             00           0               000         0                       0  "&@CRLF& _
"                  0                        0        0    00           0   0                      "&@CRLF
 
Local $array_s[35][97];定义36x98的二维数组
$hang = StringRegExp($string,'\V+',3);===========此段代码为拆分进二维数组
For $i = 0 To 34
        $lie = StringSplit($hang[$i],'',2)
        For $j = 0 To 96
                $array_s[$i][$j] = $lie[$j]
        Next
Next;===================================================================
_quchuzaodian($array_s);主函数
_ArrayDisplay($array_s,'去除噪声之后');去除噪点之后的数组
 
 
 
Func _quchuzaodian(ByRef $array)
        $35 = UBound($array, 1) - 1
        $97 = UBound($array, 2) - 1
        For $i = 0 To $35;纵向历遍
                For $j = 0 To $97;横向历遍
                        If $array[$i][$j] = "0" Then;一路扫过去发现0停下搜索四周
                                $sizhou = _sizhou($array, $i, $j);搜索四周8个点,返回一个数组,[0]为四周存在0的的数量
                                If $sizhou[0] = 0 Then $array[$i][$j] = " ";发现四周不存在其他点,则去除该点(变为空格变量则去除)
                                If $sizhou[0] = 1 Then;发现只存在一个点
                                        $sizhou2 = _sizhou($array, $sizhou[1], $sizhou[2]);则搜索存在的这个点四周8个点
                                        If $sizhou2[0] = 1 Then;发现也只有一个点,也就是刚才那个点,则断定这是一个双点,可以去除这两个点
                                                $array[$i][$j] = " ";去除
                                                $array[$sizhou[1]][$sizhou[2]] = " ";去除
                                        EndIf
                                EndIf
                        EndIf
                Next
        Next
EndFunc   ;==>_quchuzaodian
 
Func _sizhou($array, $1, $2, $front = '0')
        If Not IsArray($array) Then Return SetError(1)
        Local $a = UBound($array, 1) - 1, $b = UBound($array, 2) - 1;$a为数组一维下标-1,$b为数组二维下标-1
        Local $temp[3] = [0];定义一个数组用来存返回的结果0为四周存在点的数量,,若只有一个点,则,1为x坐标,2为y坐标
        If $1 > 0 And $2 > 0 Then;左上角的点1维2维均要减1,所以要保证都大于零
                If $array[$1 - 1][$2 - 1] = $front Then $temp = _sizhou_udf($temp, $1, $2, 1);左上角定义为1
                EndIf
        If $1 > 0 Then;上面的点1维要减1,所以要保证大于零
                If $array[$1 - 1][$2 + 0] = $front Then $temp = _sizhou_udf($temp, $1, $2, 2);上面定义为2
                EndIf
                If $temp[0] >= 2 Then Return $temp;当超出2个点时候再往下已经没有意义了
        If $1 > 0 And $2 < $b Then;左上角的点1维减1(保证大于0),2维要加1(保证小于$b不能超界)
                If $array[$1 - 1][$2 + 1] = $front Then $temp = _sizhou_udf($temp, $1, $2, 3);右上角定义为3
        EndIf
                If $temp[0] >= 2 Then Return $temp;当超出2个点时候再往下已经没有意义了
        If $2 < $b Then
                If $array[$1 + 0][$2 + 1] = $front Then $temp = _sizhou_udf($temp, $1, $2, 4);右边定义为4
        EndIf
                If $temp[0] >= 2 Then Return $temp;当超出2个点时候再往下已经没有意义了
        If $1 < $a And $2 < $b Then
                If $array[$1 + 1][$2 + 1] = $front Then $temp = _sizhou_udf($temp, $1, $2, 5);右下角定义为5
        EndIf
                If $temp[0] >= 2 Then Return $temp;当超出2个点时候再往下已经没有意义了
        If $1 < $a Then
                If $array[$1 + 1][$2 + 0] = $front Then $temp = _sizhou_udf($temp, $1, $2, 6);下面定义为6
        EndIf
                If $temp[0] >= 2 Then Return $temp;当超出2个点时候再往下已经没有意义了
        If $1 < $a And $2 > 0 Then
                If $array[$1 + 1][$2 - 1] = $front Then $temp = _sizhou_udf($temp, $1, $2, 7);左下角定义为7
        EndIf
                If $temp[0] >= 2 Then Return $temp;当超出2个点时候再往下已经没有意义了
        If $2 > 0 Then
                If $array[$1 + 0][$2 - 1] = $front Then $temp = _sizhou_udf($temp, $1, $2, 8);左边定义为8
        EndIf
        Return $temp
EndFunc   ;==>_sizhou
 
Func _sizhou_udf($array,$1,$2,$i)
        Switch $i;将[1]、[2]分别变成该点坐标,这样会导致只记录最后一个点的坐标,不过没事,当超出两个点时这两个变量就没用了
                                Case 1
                        $array[1] = $1-1
                        $array[2] = $2-1
                Case 2
                        $array[1] = $1-1
                        $array[2] = $2+0
                Case 3
                        $array[1] =$1-1
                        $array[2] = $2+1
                Case 4
                        $array[1] = $1+0
                        $array[2] = $2+1
                Case 5 
                        $array[1] = $1+1
                        $array[2] = $2+1
                Case 6
                        $array[1] = $1+1
                        $array[2] = $2+0
                Case 7
                        $array[1] = $1+1
                        $array[2] = $2-1
                Case 8
                        $array[1] = $1+0
                        $array[2] = $2-1
        EndSwitch
        $array[0] += 1
        Return $array
EndFunc



发现好多人看不懂我的表达,没办法将例子中的变量跟这个图联系起来,其实这个图只是表示一个二维数组
看到$string这个变量没有,把它拆进二维数组,一个子变量存一个字符,只有“0”或者一个空格,两种状态
你运行一下就会发现这个数组运行前跟运行后的变化
之前标记为红色的0变量全部成了空格变量
那有什么办法将标记为绿色(三个相连)的0变量也一并变成空格变量,就是一个这样的问题
附件: 您需要 登录 才可以下载或查看,没有账号?加入

最佳答案

查看完整内容

應該不是很難的問題,歸遞就可以解決了!? 使用歸遞的話效率就... [au3] ;~ Duvet ;~ 2013-04-19 #include Local $String, $Array, $Total = 4 $String = _ "0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000"&@CRLF& _ "0000000000000000001011000000000000000000000000000000000000000000000000000000000000000000000000000"&@CRLF& _ "00000000000000000000000000000000000 ...
发表于 2013-4-19 16:33:20 | 显示全部楼层
本帖最后由 Duvet 于 2013-4-19 22:39 编辑

應該不是很難的問題,歸遞就可以解決了!?
使用歸遞的話效率就...

;~ Duvet
;~ 2013-04-19
#include <Array.au3>
Local $String, $Array, $Total = 4

$String = _
"0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000"&@CRLF& _
"0000000000000000001011000000000000000000000000000000000000000000000000000000000000000000000000000"&@CRLF& _
"0000000000000000000000000000000000000001100000000000000000000010000000100000000001000000000000000"&@CRLF& _
"0001000000000000000000000000000000000000100000000000000000000000000000010000000000000010000001000"&@CRLF& _
"0000000000000000000001000000000000000000000000011100000000000000000000000000000000100000000000000"&@CRLF& _
"0000000000000000000000000000000000100000000000000000000000000000000000000000000001000000000000000"&@CRLF& _
"0000000000100000000000000000000001000000000000000000000000000000000000001000000000000000000000000"&@CRLF& _
"0000000000000000000000000000000010000000000000000001000000000000000000011000000000000000000000000"&@CRLF& _
"0000000000000000000000000000000000000000000000000001000000000000000000000000000000000001000000000"&@CRLF& _
"0000011000000011000000000100000000000000000000000000000000000000000000000000000000000000001000000"&@CRLF& _
"0000000111111110000000000100000000000000000000000000000000000000000000000000000000000010000000000"&@CRLF& _
"0000000001100000000000000100000000000000010000010000000000000000000000000000000000001111111000000"&@CRLF& _
"0000000001100000000000000000000000000000000000000000000000100000000000000001000001111100001110000"&@CRLF& _
"0000000001100000000000000000000000010000000000000000000000000000000000000000000000011000000011010"&@CRLF& _
"0000000001100000000000000000010000000000000000000000000000000000000000000000000000001100000001100"&@CRLF& _
"0000100011000000000000000000011111111100000000000000000000000010000000000000000000011000000011000"&@CRLF& _
"1000000011000001000000000000001100001110000000000000000111111111100000000000000000011000000001100"&@CRLF& _
"0000000011000000000000010000001100000111000000000000011100000001000000010000000000011000000001110"&@CRLF& _
"0000000011000000000000000000001100000011000000000000001100100000100000000000000100011000100001100"&@CRLF& _
"0000000110000000000000000000001101000011000000000000001100010000000000000000000000011000000001100"&@CRLF& _
"0000000110000000000010000000001100000011100010000000001100000000000000000000000000011000000000110"&@CRLF& _
"0000000110000000000000010000001100000110000000000000001100100100000000000000000000011100000000110"&@CRLF& _
"0000000110000000000000000000001100001111010000000000001100000100010000000000000000001100000000110"&@CRLF& _
"0100000110000000000000000000001111111000000100000000001100000110000000000000000000001100000000110"&@CRLF& _
"0000000110000000000000000000001100110000000000010001000111111110001000100000000000001100100000110"&@CRLF& _
"0000000011000000000010000001001110001100000000000000000011000011000001000000000000000110000000011"&@CRLF& _
"0000000011000000000000000000000110001100000000000000000011100001000000000000000000000110000000010"&@CRLF& _
"0000000011000000000000000000000110100110000000000000000011000001000000000000000000000110000000110"&@CRLF& _
"0000000011000000000000000000000110011110000000000000000011000000000000000000000000000110000000100"&@CRLF& _
"0000000110000000000000000000000110000111100000000000000011000000000000000000000000010011000001100"&@CRLF& _
"0000000110000000000000000000000110000011000000000000000011000000000000000000000000100011000111000"&@CRLF& _
"0001100110000000000000000000000110000011000000000000010001100000000000000000000001000111111100000"&@CRLF& _
"0000011111111000000000010000001111000001110000000000000001100000000000000000000000001110000000000"&@CRLF& _
"0000000000000000000000000000011000000000001000000000000000111000000000100000000000000000000000100"&@CRLF& _
"0000000000000000001000000000000000000000000100000000100001100000000000100010000000000000000000000"&@CRLF

$Array = StringRegExp($String, "[10]", 3)
$Array = _1DTo2D($Array, 97)
_CheckColor($Array)
_ArrayDisplay($Array)
Exit

Func _1DTo2D(ByRef $oArray, $endj)
        Local $endi = Int(UBound($oArray) / $endj)
        Local $nArray[$endi][$endj]
        For $i = 0 To UBound($oArray) - 1
                $nArray[Int($i / $endj)][Mod($i, $endj)] = Int($oArray[$i])
        Next
        Return $nArray
EndFunc

Func _CheckColor(ByRef $oArray)
        For $i = 0 To UBound($oArray, 1) - 1
                For $j = 0 To UBound($oArray, 2) - 1
                        If $oArray[$i][$j] Then
                                If __CheckColor($oArray, $i, $j, True) Then ContinueLoop
                                $oArray[$i][$j] = 0
                        EndIf
                Next
        Next
EndFunc

Func __CheckColor(ByRef $oArray, $i, $j, $start = False)
        Local Static $k = 0, $up = 1, $down = 1, $left = 1, $right = 1
        If $start Then
                $k = 0
        EndIf
        If $k < $Total And $up And $left And $i And $j And $oArray[$i - 1][$j - 1] Then
                $up = 1
                $down = 0
                $left = 1
                $right = 0
                $k += 1
                __CheckColor($oArray, $i - 1, $j - 1)
        EndIf
        If $k < $Total And $up And $i And $oArray[$i - 1][$j] Then
                $up = 1
                $down = 0
                $left = 1
                $right = 1
                $k += 1
                __CheckColor($oArray, $i - 1, $j)
        EndIf
        If $k < $Total And $up And $right And $i And $j < UBound($oArray, 2) - 1 And $oArray[$i - 1][$j + 1] Then
                $up = 1
                $down = 0
                $left = 0
                $right = 1
                $k += 1
                __CheckColor($oArray, $i - 1, $j + 1)
        EndIf
        If $k < $Total And $left And $j And $oArray[$i][$j - 1] Then
                $up = 1
                $down = 1
                $left = 1
                $right = 0
                $k += 1
                __CheckColor($oArray, $i, $j - 1)
        EndIf
        If $k < $Total And $right And $j < UBound($oArray, 2) - 1 And $oArray[$i][$j + 1] Then
                $up = 1
                $down = 1
                $left = 0
                $right = 1
                $k += 1
                __CheckColor($oArray, $i, $j + 1)
        EndIf
        If $k < $Total And $down And $left And $i < UBound($oArray, 1) - 1 And $j And $oArray[$i + 1][$j - 1] Then
                $up = 0
                $down = 1
                $left = 1
                $right = 0
                $k += 1
                __CheckColor($oArray, $i + 1, $j - 1)
        EndIf
        If $k < $Total And $down And $i < UBound($oArray, 1) - 1 And $oArray[$i + 1][$j] Then
                $up = 0
                $down = 1
                $left = 1
                $right = 1
                $k += 1
                __CheckColor($oArray, $i + 1, $j)
        EndIf
        If $k < $Total And $down And $right And $i < UBound($oArray, 1) - 1 And $j < UBound($oArray, 2) - 1 And $oArray[$i + 1][$j + 1] Then
                $up = 0
                $down = 1
                $left = 0
                $right = 1
                $k += 1
                __CheckColor($oArray, $i + 1, $j + 1)
        EndIf
        $up = 1
        $down = 1
        $left = 1
        $right = 1
        Return $k = $Total
EndFunc

评分

参与人数 1金钱 +50 贡献 +5 收起 理由
tryhi + 50 + 5 学习了

查看全部评分

发表于 2013-4-19 19:40:20 | 显示全部楼层
不会,坐等高淫

评分

参与人数 1金钱 +20 收起 理由
tryhi + 20

查看全部评分

发表于 2013-4-19 23:03:18 | 显示全部楼层
回复 2# Duvet


    厉害!我一晚上了也没想到办法~

评分

参与人数 1金钱 +50 收起 理由
tryhi + 50 发哥辛苦了

查看全部评分

发表于 2013-4-24 00:59:19 | 显示全部楼层
偶是不会的了,帮忙顶下帖子
发表于 2013-4-24 11:32:30 | 显示全部楼层
不会这个、看别人高手怎么说。
发表于 2013-4-24 15:00:27 | 显示全部楼层
在学习做验证码,网上研究了好多去除噪点的算法
对这种噪点用中值滤波算法最好,只是我觉得验证码图片太小,滤波后字符会不清晰
送上滤波代码
我的图像数组是用的二维数组
Func Medianfilter($aArray)
        Local $iwidth = UBound($aArray), $iheight = UBound($aArray, 2)
        Local $a_return[$iwidth][$iheight]
        Local $window[9], $min ,$temp, $k
        For $y = 1 To $iheight - 2
                For $x = 1 To $iwidth - 2
                        $k = 0
                        For $i = $x-1 To $x+1
                                For $j = $y -1 To $y +1
                                        $window[$k] = $aArray[$i][$j]
                                        $k +=1
                                Next
                        Next
                        For $m = 0 To 4
                                $min = $m
                                For $n = $m+1 To 8
                                        If $window[$n] <$window[$min] Then 
                                                $min = $n
                                                $temp = $window[$m]
                                                $window[$m] = $window[$min]
                                                $window[$min] = $temp
                                        EndIf
                                Next
                        Next
                        $a_return[$x][$y] = $window[4]                        
                Next
        Next
        For $x = 0 To $iwidth -1
                $a_return[$x][0] = $aArray[$x][0]
                $a_return[$x][$iheight-1] = $aArray[$x][$iheight-1]
        Next
        For $y = 0 To $iheight -1 
                $a_return[0][$y] = $aArray[0][$y]
                $a_return[$iwidth-1][$y] = $aArray[$iwidth -1][$y]
        Next
        Return $a_return
EndFunc

评分

参与人数 1金钱 +80 贡献 +5 收起 理由
tryhi + 80 + 5 学习一下

查看全部评分

发表于 2013-5-8 06:49:08 | 显示全部楼层
恩  看了下 特征码 写到程序里 有点大 哈哈
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-5-10 17:01 , Processed in 0.084447 second(s), 24 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表