大家好,我是公眾號(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