基于VS+Opencv2.4.10微信跳一跳輔助工具
最近微信的跳一跳小程序可謂火了一把,不是因?yàn)樗旧矶嗪猛?,而是有大部分的程序員們加入其中,利用各種領(lǐng)域方法,實(shí)現(xiàn)了微信跳一跳的外掛,分?jǐn)?shù)輕松上千或上萬(wàn)。之前也看了基于Python開(kāi)源的代碼,GitHub上現(xiàn)在的star已經(jīng)快超過(guò)1W了,簡(jiǎn)直不敢想。趁著今天禮拜天,在實(shí)驗(yàn)室中也簡(jiǎn)單的實(shí)現(xiàn)了一下微信跳一跳的輔助工具,精度還不夠高,我跑了一下才到90,純屬娛樂(lè)好玩的,后期再繼續(xù)改進(jìn),主要是依賴C++來(lái)實(shí)現(xiàn)了一下。
環(huán)境: Win10+VS2012+Opencv2.4.10+ADB工具
環(huán)境的搭建請(qǐng)查閱相關(guān)資料!
主要思路:
通過(guò)adb圖像獲取部分大家可以查閱相關(guān)資料,代碼也很簡(jiǎn)單:
adb shell screencap -p /sdcard/autojump.png adb pull /sdcard/autojump.png
利用上面兩行代碼即可將手機(jī)當(dāng)前的屏幕進(jìn)行截圖并且上傳到工程文件路徑下。
首先就是在上傳的autojump.png圖片上進(jìn)行模板匹配,匹配出小人,并計(jì)算小人的坐標(biāo);
然后就是通過(guò)Canny()函數(shù)進(jìn)行圖像的邊緣檢測(cè),這里使用的閾值為5,10基本可以檢測(cè)出所有邊緣信息;
然后根據(jù)一般下一個(gè)要跳的地點(diǎn)始終在小人的左半屏或又半屏部分這一先驗(yàn)知識(shí),來(lái)進(jìn)行查找范圍的確定,進(jìn)行行掃描,掃描到的第一個(gè)值為255的即返回當(dāng)前坐標(biāo)值;然后通過(guò)計(jì)算與小人坐標(biāo)的距離即可得到下一步要跳躍的距離,(注:本代碼中在下一個(gè)坐標(biāo)的縱坐標(biāo)進(jìn)行+50處理,由于本文中只利用了一個(gè)關(guān)鍵點(diǎn)進(jìn)行測(cè)試的,這樣做是顯然不合理的,接下來(lái)可以再利用第二個(gè)關(guān)鍵點(diǎn)進(jìn)行下一個(gè)跳躍目標(biāo)中心點(diǎn)的計(jì)算),由于本人手機(jī)是1080*1920的所以再得到距離過(guò)后乘以一個(gè)跳躍系數(shù)1.35,(這里不同分辨率的手機(jī)系數(shù)是不一樣的),這樣就得到了跳躍按壓時(shí)間,從而通過(guò)system()命令進(jìn)行調(diào)用ADB工具進(jìn)行與手機(jī)通訊實(shí)現(xiàn)模擬人的點(diǎn)擊。本文僅僅是簡(jiǎn)單的實(shí)現(xiàn)了一下看看效果,如果想跑高分還得進(jìn)行代碼的優(yōu)化與更改!其次因?yàn)槊看伟磯旱牡攸c(diǎn)肯定是不一樣的,而本文也采用簡(jiǎn)單的同一位置按壓,這樣做很容易被騰訊反作弊給查出來(lái)的,所以這里可以添加一個(gè)隨機(jī)數(shù)從而可以簡(jiǎn)單的避免位置重復(fù)!
代碼如下:
/* 時(shí)間:2018-1-7 地點(diǎn):SHNU 功能:wechat簡(jiǎn)單跳一跳C++代碼的實(shí)現(xiàn),有待改進(jìn),僅供學(xué)習(xí)之用!歡迎大家提出新算法 */ #include<opencv2/opencv.hpp> #include<iostream> #include<math.h> using namespace cv; using namespace std; //全局變量定義區(qū) Mat srcImage; Mat dstImage; Mat Character; //get_screenshot();獲取手機(jī)上的圖像 void get_screenshot(); //Canny_Dec();邊緣檢測(cè) void Canny_Dec(Mat& srcImage); //獲取Character坐標(biāo) Point get_Character_Loc(Mat& srcImage,Mat& Tem_img); //獲取下一個(gè)要跳的點(diǎn) Point get_next_img_Loc(Mat& srcImage,Point& Character_Loc); //計(jì)算距離 int get_distance(Point& first_point,Point& next_point); //跳躍 void jump(int&g_distance); int main(int argc,char** argv) { system("color 3F"); while (true) { get_screenshot(); srcImage = imread("autojump.png"); dstImage = srcImage.clone(); Character = imread("./Template/character.png"); //imshow("Character",Character); //cvtColor(srcImage,srcImage,CV_BGR2GRAY); Point next_p = get_Character_Loc(srcImage,Character); cout<<"next_p:"<<1111<<endl; Point get_next = get_next_img_Loc(srcImage,next_p); int g_distance = get_distance(next_p,get_next); jump(g_distance); //cout<<"get_next_img_Loc:"<<get_next<<endl; circle(dstImage,get_next,8,Scalar(0,221,2)); //imshow("test",dstImage); imwrite("Canny.png",dstImage); _sleep(1500); } return 0; } void get_screenshot() { system("adb shell screencap -p /sdcard/autojump.png"); system("adb pull /sdcard/autojump.png"); } Point get_Character_Loc(Mat& srcImage,Mat& Tem_img) { matchTemplate(srcImage,Tem_img,dstImage,CV_TM_SQDIFF); double minVal,maxVal; Point minLoc,maxLoc,matchLoc; minMaxLoc(dstImage,&minVal,&maxVal,&minLoc,&maxLoc,Mat()); matchLoc = minLoc; //matchLoc是最佳匹配的區(qū)域左上角點(diǎn) rectangle(srcImage,Rect(matchLoc,Size(Character.cols,Character.rows)),Scalar(255,255,0),1,8,0); //Canny(srcImage,srcImage,1,10); putText(srcImage,"Wang",Point(matchLoc.x+Character.cols*0.5,matchLoc.y+Character.rows),1,2,Scalar(0,0,255));//畫出Character小人的坐標(biāo) return Point(matchLoc.x+Character.cols*0.5,matchLoc.y+Character.rows); } Point get_next_img_Loc(Mat& srcImage,Point& Character_Loc) { cout<<"get_next_img_Loc"<<endl; cvtColor(srcImage,srcImage,CV_BGR2GRAY); Canny(srcImage,srcImage,5,10); imwrite("get_next_img_Loc.png",srcImage); //imshow("get",srcImage); cout<<"Character_Loc.x:"<<Character_Loc.x<<endl; if(Character_Loc.x < 540) { for(int j = int(srcImage.rows*0.2);j<int(srcImage.rows*0.8);j++) { uchar* data = srcImage.ptr<uchar>(j); for(int i = 1079;i > 540 ;i--) { if(data[i] == 255) { return Point(i,j); //cout<<"Point:"<<Point(i,j)<<endl; } } } } else { for(int j = int(srcImage.rows*0.2);j<int(srcImage.rows*0.8);j++) { uchar* data = srcImage.ptr<uchar>(j); for(int i = 0;i<540;i++) { if(data[i] == 255) return Point(i,j); } } } } int get_distance(Point& first_point,Point& next_point) { int A = first_point.x - next_point.x; int B = first_point.y - (next_point.y+50); return int(pow(pow(A,2)+pow(B,2),0.5)); } void jump(int&g_distance) { char AA[50]; int distance_ = g_distance * 1.35; sprintf(AA,"adb shell input swipe 320 410 320 410 %d",distance_); cout<<AA<<endl; system(AA); }
邊緣檢測(cè)圖片:
下一個(gè)關(guān)鍵點(diǎn)定位:
上圖中畫出的小圈圈,不太清晰,將就著看下!小菜水平有限,僅僅是基于好玩就弄了下!
結(jié)果:用開(kāi)源的隨便跑跑幾百,自己的怎么跑,90 【累哭】
華麗的分割線————————————————
又來(lái)更新一下啦!
晚上不想看論文就想到了之前的跳一跳,經(jīng)過(guò)一邊顯示命令窗口輸出和一邊顯示Canny()邊緣化處理終于找到了上次跑的分?jǐn)?shù)低的原因啦!
主要原因如下所示:
如上所示,由于之前選取的Canny()中的閾值為1和10,這導(dǎo)致一旦要跳到的下一個(gè)目標(biāo)物體的顏色和背景色很接近時(shí)就很容易使得邊緣的梯度小于10,因此就不會(huì)被認(rèn)為是邊緣,從而導(dǎo)致上面的這種情況出現(xiàn)。索性今天就將閾值設(shè)為3和8,并在Canny()函數(shù)前面加上了一個(gè)高斯濾波器。如下:
GaussianBlur(srcImage,srcImage,Size(3,3),0);
還有就是上面的_sleep(1500)函數(shù),這里如果閑時(shí)間比較久的話也是可以改為1000的,速度上有所提升。
同時(shí)加上按壓位置的隨機(jī)數(shù),使得每次按壓點(diǎn)都是在(320,410)—(350,460)之間。代碼如下:
int rand_x = int(320+rand()%50); //加上隨機(jī)數(shù)使得每次按壓都是在點(diǎn)(320,410)-(370,460)之間 int rand_y = int(410+rand()%50); sprintf(AA,"adb shell input swipe %d %d %d %d %d",rand_x,rand_y,rand_x,rand_y,distance_);
如下圖所示:
由上圖可知,每次按壓的位置都是在變的。
完整版代碼如下:
/* 時(shí)間:2018-1-7 地點(diǎn):SHNU 功能:wechat簡(jiǎn)單跳一跳C++代碼的實(shí)現(xiàn),有待改進(jìn),僅供學(xué)習(xí)之用!歡迎大家提出新算法 */ #include<opencv2/opencv.hpp> #include<iostream> #include<math.h> #include<stdlib.h>//rand()隨機(jī)數(shù)頭文件 using namespace cv; using namespace std; //全局變量定義區(qū) Mat srcImage; Mat dstImage; Mat Character; static int i = 0; //get_screenshot();獲取手機(jī)上的圖像 void get_screenshot(); //Canny_Dec();邊緣檢測(cè) void Canny_Dec(Mat& srcImage); //獲取Character坐標(biāo) Point get_Character_Loc(Mat& srcImage,Mat& Tem_img); //獲取下一個(gè)要跳的點(diǎn) Point get_next_img_Loc(Mat& srcImage,Point& Character_Loc); //計(jì)算距離 int get_distance(Point& first_point,Point& next_point); //跳躍 void jump(int&g_distance); int main(int argc,char** argv) { system("color 3F"); while (true) { get_screenshot(); srcImage = imread("autojump.png"); dstImage = srcImage.clone(); Character = imread("./Template/character.png"); //imshow("Character",Character); //cvtColor(srcImage,srcImage,CV_BGR2GRAY); Point next_p = get_Character_Loc(srcImage,Character); //cout<<"next_p:"<<1111<<endl; Point get_next = get_next_img_Loc(srcImage,next_p); int g_distance = get_distance(next_p,get_next); jump(g_distance); //cout<<"get_next_img_Loc:"<<get_next<<endl; circle(dstImage,get_next,8,Scalar(0,221,2)); //imshow("test",dstImage); imwrite("Canny.png",dstImage); _sleep(1000); } return 0; } void get_screenshot() { system("adb shell screencap -p /sdcard/autojump.png"); system("adb pull /sdcard/autojump.png"); } Point get_Character_Loc(Mat& srcImage,Mat& Tem_img) { matchTemplate(srcImage,Tem_img,dstImage,CV_TM_SQDIFF); double minVal,maxVal; Point minLoc,maxLoc,matchLoc; minMaxLoc(dstImage,&minVal,&maxVal,&minLoc,&maxLoc,Mat()); matchLoc = minLoc; //matchLoc是最佳匹配的區(qū)域左上角點(diǎn) cout<<"maxVal:"<<maxVal<<endl; rectangle(srcImage,Rect(matchLoc,Size(Character.cols,Character.rows)),Scalar(255,255,0),1,8,0); //Canny(srcImage,srcImage,1,10); putText(srcImage,"Wang",Point(matchLoc.x+Character.cols*0.5,matchLoc.y+Character.rows),1,2,Scalar(0,0,255));//畫出Character小人的坐標(biāo) return Point(matchLoc.x+Character.cols*0.5,matchLoc.y+Character.rows); } Point get_next_img_Loc(Mat& srcImage,Point& Character_Loc) { cout<<"get_next_img_Loc"<<endl; cvtColor(srcImage,srcImage,CV_BGR2GRAY); GaussianBlur(srcImage,srcImage,Size(3,3),0); Canny(srcImage,srcImage,3,8); char AA[30]; sprintf(AA,"get_next_img_Loc_%d.png",i); cout<<AA<<endl; imwrite(AA,srcImage); i++; //imshow("get",srcImage); cout<<"Character_Loc.x:"<<Character_Loc.x<<endl; if(Character_Loc.x < 540) { for(int j = int(srcImage.rows*0.2);j<int(srcImage.rows*0.8);j++) { uchar* data = srcImage.ptr<uchar>(j); for(int i = 1079;i > 540 ;i--) { if(data[i] == 255) { return Point(i,j); //cout<<"Point:"<<Point(i,j)<<endl; } } } } else { for(int j = int(srcImage.rows*0.2);j<int(srcImage.rows*0.8);j++) { uchar* data = srcImage.ptr<uchar>(j); for(int i = 0;i<540;i++) { if(data[i] == 255) return Point(i,j); } } } return Character_Loc; } int get_distance(Point& first_point,Point& next_point) { int A = first_point.x - next_point.x; int B = first_point.y - (next_point.y+50); return int(pow(pow(A,2)+pow(B,2),0.5)); } void jump(int&g_distance) { char AA[50]; int distance_ = g_distance * 1.35; int rand_x = int(320+rand()%50); //加上隨機(jī)數(shù)使得每次按壓都是在點(diǎn)(320,410)-(370,460)之間 int rand_y = int(410+rand()%50); sprintf(AA,"adb shell input swipe %d %d %d %d %d",rand_x,rand_y,rand_x,rand_y,distance_); cout<<AA<<endl; system(AA); }
通過(guò)測(cè)試效果如下:輕松得榜首,到五百多時(shí)程序依然可以一直在運(yùn)行,我覺(jué)得時(shí)間太長(zhǎng),所以就直接弄掛了。不過(guò)并不影響榜首的位置!上圖:
總結(jié):主要本人剛好也是視覺(jué)圖像方向的,哈哈,就閑的無(wú)聊測(cè)試了一把,經(jīng)過(guò)更改和測(cè)試。如果不遇到那種與背景色特別相近的,上榜首是沒(méi)問(wèn)題的! 嗯,說(shuō)了這么多,這個(gè)博客也就到此結(jié)束啦,有問(wèn)題歡迎留言!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:C++實(shí)現(xiàn)景區(qū)信息管理系統(tǒng)
欄 目:C語(yǔ)言
下一篇:C語(yǔ)言八皇后問(wèn)題解決方法示例【暴力法與回溯法】
本文標(biāo)題:基于VS+Opencv2.4.10微信跳一跳輔助工具
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/980.html
您可能感興趣的文章
- 01-10基于atoi()與itoa()函數(shù)的內(nèi)部實(shí)現(xiàn)方法詳解
- 01-10基于C語(yǔ)言sprintf函數(shù)的深入理解
- 01-10基于C程序啟動(dòng)代碼的深入分析
- 01-10基于getline()函數(shù)的深入理解
- 01-10基于C語(yǔ)言fflush()函數(shù)的使用詳解
- 01-10基于linux下獲取時(shí)間函數(shù)的詳解
- 01-10基于C語(yǔ)言指令的深入分析
- 01-10基于c中使用ftruncate()前需要fflush(),使用后需要rewind()的深入探討
- 01-10基于C++ list中erase與remove函數(shù)的使用詳解
- 01-10基于C++輸出指針自增(++)運(yùn)算的示例分析


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-11Mac OSX 打開(kāi)原生自帶讀寫NTFS功能(圖文
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10delphi制作wav文件的方法
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery