大家好,我是公眾號(hào)三分學(xué)堂的郭立元~
在群里看著他們聊天。最近因?yàn)闊o(wú)法使用聯(lián)立碼而出現(xiàn)驗(yàn)證碼問(wèn)題。沒(méi)有其他解決辦法。(大衛(wèi)亞設(shè))。
說(shuō)到這么一個(gè)驗(yàn)證碼,如下圖所示:
驗(yàn)證碼分兩部分,上部分是傾斜的數(shù)字,下面是4個(gè)選項(xiàng),點(diǎn)擊和上部分相同數(shù)字的選項(xiàng)即為驗(yàn)證成功。
原本通過(guò)這個(gè)驗(yàn)證可以整體截圖對(duì)接打碼平臺(tái),然后平臺(tái)返回正確選項(xiàng)的位置坐標(biāo),腳本點(diǎn)擊此坐標(biāo)就可以完成驗(yàn)證了。
要是不用打碼平臺(tái),本地識(shí)別可不可以解決呢?
這個(gè)驗(yàn)證的兩部分識(shí)別難度是不一樣的,上半部分難度高,下半部分難度低。
先從下半部分簡(jiǎn)單的開(kāi)始識(shí)別,這里我先測(cè)試smartocr命令,看看識(shí)別的準(zhǔn)確率。
通過(guò)測(cè)試發(fā)現(xiàn)這個(gè)部分的識(shí)別率基本接近100%準(zhǔn)確,既然準(zhǔn)確率非常高,那么就直接使用這個(gè)命令,不在測(cè)試其他的命令。
識(shí)別后的結(jié)果存入abcd這4個(gè)變量中,分別代表四個(gè)選項(xiàng)。
接下來(lái)要識(shí)別難度大的上半部分,還是測(cè)試:
①測(cè)試smartocr命令:
正確結(jié)果是64217,識(shí)別結(jié)果是66484,識(shí)別準(zhǔn)確是20%
把5個(gè)文字分開(kāi)又重新識(shí)別測(cè)試,識(shí)別準(zhǔn)確率依然很低,所以smartocr命令可以pass掉了。
這部分之所以難識(shí)別,因?yàn)閿?shù)字是雙層的,并且每一個(gè)字都是傾斜的,關(guān)于這類(lèi)數(shù)字的識(shí)別,我想到了這個(gè)軟件。
這是電腦端的識(shí)別,如果安卓端使用,可以把圖片用ftp傳遞電腦上識(shí)別,然后返回識(shí)別結(jié)果。
先看看識(shí)別效果:
5個(gè)數(shù)字只識(shí)別出4個(gè)數(shù)字,準(zhǔn)確率也很一般,不過(guò)我嘗試把數(shù)字放到一行,再次識(shí)別,發(fā)現(xiàn)準(zhǔn)確提高了。
可以看到識(shí)別結(jié)果,5個(gè)數(shù)字識(shí)別正確了4個(gè),準(zhǔn)確率是80%,基本上達(dá)到可以用的程度。
那么怎么把這些數(shù)字放到一行,又是一個(gè)難題?
我想到的思路是把每一個(gè)數(shù)字截圖出來(lái),然后再合并到一個(gè)圖片上~思路有了我們開(kāi)始著手去做。
①把每一個(gè)圖片的位置找出來(lái)
這里每個(gè)數(shù)字都不是粘連在一起,那么先橫向把數(shù)字分塊:
分塊原理是縱向遍歷每一列顏色點(diǎn),如果在一列當(dāng)中包含任意一個(gè)像素是數(shù)字的顏色值,就是有效區(qū)域,也就是上圖中紅框,如果一整列都沒(méi)有一個(gè)符合的顏色點(diǎn),那么就是非數(shù)字區(qū)域,也就是紅框以外的。
這是一個(gè)二維遍歷,先遍歷一列的顏色點(diǎn),再遍歷所有列。
為了便于后續(xù)處理,做一個(gè)二值化的處理,具體處理方式是:以列為單位,如果一列中包含數(shù)字的顏色點(diǎn),記作1,如果不包含記作0,如圖所示:
要實(shí)現(xiàn)這個(gè)二值化的計(jì)算,代碼如下所示:
TracePrint GetBinary(204,179,724,356,"2C4156")
Function GetBinary(x1,y1,x2,y2,color)
Dim binary,line=""
KeepCapture
For j = x1 To x2
For i = y1 To y2
If CmpColor(j, i, color, 0.9)=0 Then
binary = 1
Exit For
End If
If i = y2 Then
binary=0
End If
Next
line=line&binary
Next
ReleaseCapture
GetBinary=line
End Function
輸入結(jié)果:
結(jié)果中有5段連續(xù)的數(shù)字1,說(shuō)明驗(yàn)證圖上有5個(gè)數(shù)字,那問(wèn)題又來(lái)了,怎么提取每個(gè)數(shù)字對(duì)應(yīng)連續(xù)1的位置?
可以使用查找命令,先看示意圖:
示意圖中,先查找“01”就可以找到連續(xù)數(shù)字1的左側(cè),再查找“10”就可以找到連續(xù)數(shù)字1的右側(cè),如果是只有一段連續(xù)數(shù)字1,那么一次查找即可,但是我們例子中有5段,所以需要循環(huán)查找,并且每次查找的起始位置都要在上次查找結(jié)果的基礎(chǔ)上向后偏移至少1個(gè)位置。
代碼這樣寫(xiě):先查找01的
Dim line="00000000000000000000001111111111111111111111111111110000000000000000000000000000000000000000000001111111111111111111111111110000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000"
dim leftarr=GetPositions(line,"01")
TracePrint join(leftarr,"|")
Function GetPositions(line,str)
Dim arr(),i=0
Do
If InStr(arr(i - 1) + 1, line, str) = 0 Then
Exit Do
Else
arr(i) = InStr(arr(i - 1) + 1, line, str) + 1
i=i+1
End If
Loop
GetPositions=arr
End Function
運(yùn)算結(jié)果:
當(dāng)前腳本第3行:23|98|188|308|426
把“01”改成“10”在運(yùn)算一遍:
當(dāng)前腳本第3行:53|125|227|331|457
兩組數(shù)值都是5個(gè),分別代表5個(gè)數(shù)字左側(cè)和右側(cè)的位置。
易錯(cuò)點(diǎn)來(lái)了:上面所得到的位置坐標(biāo),都是相對(duì)坐標(biāo),相對(duì)的點(diǎn)是數(shù)字區(qū)域左上角的坐標(biāo):
還剩下每個(gè)數(shù)字的上下位置了,由于5個(gè)數(shù)字之間在縱向是沒(méi)有間隙的。
需要單個(gè)數(shù)字去獲取上下位置,方法還是剛剛那樣,不同之處是要先遍歷單行顏色點(diǎn),再逐行遍歷。
在提醒一遍,寫(xiě)代碼的時(shí)候還是要注意易錯(cuò)點(diǎn)——相對(duì)坐標(biāo)
TracePrint GetBinary2(23+204,179,53+204,356,"2C4156")
Function GetBinary2(x1,y1,x2,y2,color)
Dim binary,line=""
KeepCapture
For j = y1 To y2
For i = x1 To x2
If CmpColor(i, j, color, 0.9)=0 Then
binary = 1
Exit For
End If
If i = x2 Then
binary=0
End If
Next
line=line&binary
Next
ReleaseCapture
GetBinary2=line
End Function
輸出結(jié)果:
當(dāng)前腳本第1行:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111100000000000000000000000000000000000
獲取位置還是使用查找命令,查找“01”和“10”,再次強(qiáng)調(diào)得到結(jié)果是相對(duì)坐標(biāo)。
把所有的數(shù)字都按照這個(gè)方法獲取上下坐標(biāo),到此處我們已經(jīng)可以得到每個(gè)數(shù)字的范圍坐標(biāo),接下來(lái)就是截圖了。
考慮到后面數(shù)字要拼接到一起,所以截圖時(shí)外延5像素。
擴(kuò)展計(jì)算方式:
加上原始范圍是x1,y1,x2,y2
擴(kuò)展后的范圍是:x1-5,y1-5,x2+5,y2+5
最終代碼:
截圖(204,179,724,356,"2C4156")
Function 截圖(x1,y1,x2,y2,color)
dim lines= Getbinary(x1,y1,x2,y2,color)
TracePrint lines
dim leftarr= GetPositions(lines,"01")
TracePrint join(leftarr,"|")
dim rightarr= GetPositions(lines,"10")
TracePrint join(rightarr,"|")
For i = 0 To UBOUND(leftarr)
dim newline= GetBinary2(leftarr(i)+x1, y1, rightarr(i)+x1, y2, color)
TracePrint newline
TracePrint leftarr(i)+x1
TracePrint instr(1,newline,"01")+y1
TracePrint rightarr(i)+x1
TracePrint instr(1,newline,"10")+y1
SnapShot("/sdcard/pictures/yzm/"&i&".png",leftarr(i)+x1-5,instr(1,newline,"01")+y1-5,rightarr(i)+x1+5,instr(1,newline,"10")+y1+5)
TracePrint "--------------"
Next
End Function
Function GetBinary(x1,y1,x2,y2,color)
Dim binary,line=""
KeepCapture
For j = x1 To x2
For i = y1 To y2
If CmpColor(j, i, color, 0.9)=0 Then
binary = 1
Exit For
End If
If i = y2 Then
binary=0
End If
Next
line=line&binary
Next
ReleaseCapture
GetBinary=line
End Function
Function GetBinary2(x1,y1,x2,y2,color)
Dim binary,line=""
KeepCapture
For j = y1 To y2
For i = x1 To x2
If CmpColor(i, j, color, 0.9)=0 Then
binary = 1
Exit For
End If
If i = x2 Then
binary=0
End If
Next
line=line&binary
Next
ReleaseCapture
GetBinary2=line
End Function
Function GetPositions(line,str)
Dim arr(),i=0
Do
If InStr(arr(i - 1) + 1, line, str) = 0 Then
Exit Do
Else
arr(i) = InStr(arr(i - 1) + 1, line, str) + 1
i=i+1
End If
Loop
GetPositions=arr
End Function
在文件夾里面已經(jīng)把所有數(shù)字單獨(dú)截取出來(lái)了。
截圖部分的內(nèi)容已經(jīng)完成,下面開(kāi)始把所有圖片拼接到一起。
第一步:獲取所有圖片的尺寸,并存入數(shù)組中
Dim PicArr()
For i = 0 To 4
Dim Path = "/sdcard/pictures/yzm/"&i&".png"
Dim 返回值 = Image.Size(Path)
PicArr(i)={返回值[1],返回值[2]}
Next
Dim json=encode.tabletojson(PicArr)
TracePrint json
運(yùn)算結(jié)果:
當(dāng)前腳本第9行:[[41,50],[38,46],[50,51],[34,49],[42,49]]
第二步:因?yàn)槭菣M向拼接所有圖片,所以最終合成圖的寬度是所有圖片寬度之和。
Dim PicArr={{41,50},{38,46},{50,51},{34,49},{42,49}}
Dim x
For i = 0 To 4
x=x+PicArr[i+1][1]
Next
TracePrint x
第三步:合成圖的高度,5張圖中最高的高度就是合成圖的高度。
一組數(shù)字比較大小,可以用冒泡法,即相鄰兩個(gè)數(shù)字比較,前面數(shù)字大于后面數(shù)字,兩個(gè)數(shù)字調(diào)換位置,如果前面數(shù)字小于后面數(shù)字,兩個(gè)數(shù)字位置不變,這樣所有大的數(shù)字都被放到后面,那么最后一個(gè)數(shù)字就是最大的數(shù)字。
Dim PicArr={{41,50},{38,46},{50,51},{34,49},{42,49}}
Dim y
For i = 1 To 4
If PicArr[i][2] > PicArr[i+1][2] Then
PicArr[i+1][2]=PicArr[i][2]
End If
Next
y = PicArr[4][2]
TracePrint y
第四步:做一個(gè)以驗(yàn)證圖背景色顏色值的圖片
Dim x=205,y=51
Dim PixelData = Image.GetScreenData(1,1,x,y)
Dim r,g,b
Dim background="C7D1DB"
ColorToRGB(background,r,g,b)
TracePrint r,g,b
For j = 1 To x
For i = 1 To y
PixelData[j][i][3] = r
PixelData[j][i][2] = g
PixelData[j][i][1] = b
Next
Next
Image.SavePixelData PixelData, "/sdcard/pictures/yzm;
第五步:把每張數(shù)字圖片的顏色數(shù)據(jù),都賦值給上面的圖片。
Dim x=205,y=51
Dim PicArr={{41,50},{38,46},{50,51},{34,49},{42,49}}
Dim PixelData =Image.GetPicData("/sdcard/pictures/yzm;)
For n = 0 To 4
If n = 0 Then
dim m = 0
Else
m=m+PicArr[n][1]
End If
dim PixelDataword=Image.GetPicData("/sdcard/pictures/yzm/"&n&".png")
For j = 1 To PicArr[n+1][1]
For i = 1 To PicArr[n + 1][2]
For k = 1 To 3
PixelData[m+j][i][k]=PixelDataword[j][i][k]
Next
Next
Next
Next
Image.SavePixelData PixelData, "/sdcard/pictures/yzm;
完整代碼:
拼圖(4)
Function 拼圖(num)
Dim PicArr()
For i = 0 To num
Dim Path = "/sdcard/pictures/yzm/"&i&".png"
Dim 返回值 = Image.Size(Path)
PicArr(i)={返回值[1],返回值[2]}
Next
Dim json=encode.tabletojson(PicArr)
TracePrint json
Dim x
For i = 0 To num
x=x+PicArr[i+1][1]
Next
TracePrint x
Dim y
For i = 1 To num
If PicArr[i][2] > PicArr[i+1][2] Then
PicArr[i+1][2]=PicArr[i][2]
End If
Next
y = PicArr[num][2]
TracePrint y
Dim PixelData = Image.GetScreenData(1,1,x,y)
Dim r,g,b
Dim background="C7D1DB"
ColorToRGB(background,r,g,b)
TracePrint r,g,b
For j = 1 To x
For i = 1 To y
PixelData[j][i][3] = r
PixelData[j][i][2] = g
PixelData[j][i][1] = b
Next
Next
TracePrint x,y
PicArr = Encode.JsonToTable(json)
For n = 0 To num
If n = 0 Then
dim m = 0
Else
m=m+PicArr[n][1]
End If
dim PixelDataword=Image.GetPicData("/sdcard/pictures/yzm/"&n&".png")
For j = 1 To PicArr[n+1][1]
For i = 1 To PicArr[n + 1][2]
For k = 1 To 3
PixelData[m+j][i][k]=PixelDataword[j][i][k]
Next
Next
Next
Next
Image.SavePixelData PixelData, "/sdcard/pictures/yzm;
End Function
這期文章實(shí)現(xiàn)的功能很簡(jiǎn)單,但是思考的邏輯過(guò)程還是比較復(fù)雜的,另外在群里問(wèn)怎么把兩張圖合并在一起的同學(xué)可以來(lái)領(lǐng)教程了。
寫(xiě)到這里有點(diǎn)累了,找到正確答案的識(shí)別和比對(duì),不想寫(xiě)了,說(shuō)個(gè)大概思路:
(1)比對(duì)數(shù)字個(gè)數(shù),上部分是5個(gè)數(shù)字,只有選項(xiàng)B/C滿(mǎn)足,排除2個(gè)錯(cuò)誤答案
(2)因?yàn)檫x項(xiàng)的識(shí)別準(zhǔn)確率非常高,我假定它是完全準(zhǔn)確的。上部分的數(shù)字和選項(xiàng)比對(duì)這么幾個(gè)維度,并且用打分形式記錄
①單個(gè)數(shù)字對(duì)比,一個(gè)相同數(shù)字(+5分)
②同位數(shù)字比對(duì),比如第一位都是6,每對(duì)一位(+10分)
③連續(xù)位數(shù)相同,這個(gè)情況比較多,先判斷所有位相同的情況,如果這個(gè)滿(mǎn)足,直接認(rèn)定為正確答案,后續(xù)是1位不同,2位不同,分值依次降低。
就我們這個(gè)例子來(lái)說(shuō),它非常簡(jiǎn)單,幾個(gè)選項(xiàng)相差很大,所以這個(gè)比對(duì)就簡(jiǎn)單很多。
=正文完=
1.《電腦怎么在圖片上加文字不顯示?總結(jié)很全面速看!「安卓按鍵」找到圖片上文字的位置(另附切圖+拼圖方法)》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識(shí),僅代表作者本人觀點(diǎn),與本網(wǎng)站無(wú)關(guān),侵刪請(qǐng)聯(lián)系頁(yè)腳下方聯(lián)系方式。
2.《電腦怎么在圖片上加文字不顯示?總結(jié)很全面速看!「安卓按鍵」找到圖片上文字的位置(另附切圖+拼圖方法)》僅供讀者參考,本網(wǎng)站未對(duì)該內(nèi)容進(jìn)行證實(shí),對(duì)其原創(chuàng)性、真實(shí)性、完整性、及時(shí)性不作任何保證。
3.文章轉(zhuǎn)載時(shí)請(qǐng)保留本站內(nèi)容來(lái)源地址,http://f99ss.com/gl/3042325.html