国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

用C#調用Matlab圖像處理自制QQ游戲2D桌球瞄準器

2019-11-14 16:34:39
字體:
來源:轉載
供稿:網友

平時不怎么玩游戲,有時消遣就玩玩QQ里的2D桌球,但是玩的次數少,不能像骨灰級玩家一樣百發百中,腫么辦呢?于是某天突發奇想,決定自己也來做個“外掛”。說是外掛,其實只是一個瞄準器,畢竟外掛是修改別人的軟件,有點違法的意思,況且自己還沒有能力去那么做,所以自己還是弄個瞄準器,做做弊,過下小癮,同時也提高一下自己的編程能力。

起初(也就是半年前),自己嘗試做一個瞄準器的初始版本,用C#做,想法很簡單:

Step1.把鼠標移到洞口,獲取鼠標位置;

Step2.將鼠標放到要擊打的球的圓心上,獲取鼠標當前位置

Step3.根據進球時三點共線的原則按照球的半徑自動將鼠標移動到準確的擊球點。

示意圖如下:

 

于是當初就按照這個想法做了,開始給自己做了個C#版,調用Windows API中的GetDesktopWindow,GetWindowDC,SetCursorPos三個函數,經過簡單的數學運算,就基本實現了功能。代碼如下:

 

Csharp代碼 
  1. using System.Drawing;  
  2. using System.Windows.Forms;  
  3. using System.Windows;  
  4. using System.Runtime.InteropServices;  
  5. using System;  
  6.   
  7. namespace TaiqiuGua  
  8. {  
  9.   
  10.     public partial class Form1 : Form  
  11.     {  
  12.         const int ra=25;  
  13.         [DllImport("user32.dll")]  
  14.         static extern IntPtr GetDesktopWindow();  
  15.         [DllImport("user32.dll")]  
  16.         static extern IntPtr GetWindowDC(IntPtr hWnd);  
  17.         [DllImport("user32.dll")]  
  18.         static extern bool SetCursorPos(int X, int Y);  
  19.   
  20.         public Form1()  
  21.         {  
  22.             InitializeComponent();  
  23.         }  
  24.   
  25.         Point startP;  
  26.         Point endP;  
  27.           
  28.         PRivate void Form1_KeyDown(object sender, KeyEventArgs e)  
  29.         {  
  30.             switch(e.KeyData)  
  31.             {  
  32.                 case Keys.F1:  
  33.                     startP=Control.MousePosition;  
  34.                     break;  
  35.                 case Keys.F2:  
  36.                     endP = Control.MousePosition;  
  37.                     break;  
  38.                 case Keys.D1:  
  39.                     int x1 = (int)(endP.X + ra * ((endP.X - startP.X) / Math.Sqrt((endP.X - startP.X) * (endP.X - startP.X) + (endP.Y - startP.Y) * (endP.Y - startP.Y))));  
  40.                     int y1 = (int)(endP.Y + ra * ((endP.Y - startP.Y) / Math.Sqrt((endP.X - startP.X) * (endP.X - startP.X) + (endP.Y - startP.Y) * (endP.Y - startP.Y))));  
  41.                     SetCursorPos(x1, y1);  
  42.                     break;  
  43.                 case Keys.D2:  
  44.                     int x2 = (int)(endP.X - ra * ((-endP.X + startP.X) / Math.Sqrt((-endP.X + startP.X) * (-endP.X + startP.X) + (endP.Y - startP.Y) * (endP.Y - startP.Y))));  
  45.                     int y2 = (int)(endP.Y + ra * ((endP.Y - startP.Y) / Math.Sqrt((-endP.X + startP.X) * (-endP.X + startP.X) + (endP.Y - startP.Y) * (endP.Y - startP.Y))));  
  46.                     SetCursorPos(x2, y2);  
  47.                     break;  
  48.                 case Keys.D3:                      
  49.                     int x3 = (int)(endP.X + ra * ((endP.X - startP.X) / Math.Sqrt((endP.X - startP.X) * (endP.X - startP.X) + (-endP.Y + startP.Y) * (-endP.Y + startP.Y))));  
  50.                     int y3 = (int)(endP.Y - ra * ((-endP.Y + startP.Y) / Math.Sqrt((endP.X - startP.X) * (endP.X - startP.X) + (-endP.Y + startP.Y) * (-endP.Y + startP.Y))));  
  51.                     SetCursorPos(x3, y3);  
  52.                     break;  
  53.                 case Keys.D4:  
  54.                     int x4 = (int)(endP.X - ra * ((-endP.X + startP.X) / Math.Sqrt((-endP.X + startP.X) * (-endP.X + startP.X) + (-endP.Y + startP.Y) * (-endP.Y + startP.Y))));  
  55.                     int y4 = (int)(endP.Y - ra * ((-endP.Y + startP.Y) / Math.Sqrt((-endP.X + startP.X) * (-endP.X + startP.X) + (-endP.Y + startP.Y) * (-endP.Y + startP.Y))));  
  56.                     SetCursorPos(x4, y4);  
  57.                     break;  
  58.             }  
  59.             GC.Collect();  
  60.         }  
  61.     }  
  62. }  

使用時,只需要激活瞄準器窗口,按F1,F2獲取鼠標位置,再根據洞口位置分別選按1、2、3、4數字鍵就行。

經過N次試驗,成功率還挺高,只是有時候手動放置鼠標到被擊打球圓心會出現誤差,導致擊球不準,當然,后來我贏了很多場比賽(嘿嘿,有點不道德!)。

再后來,又用C寫了一遍,給同學用了。代碼如下:

Cpp代碼 
  1. #include <windows.h>  
  2. #include <math.h>  
  3. int ra=26;  
  4. int flag=0;  
  5. POINT startP,endP;  
  6. int x5,y5,x2,y2,x3,y3,x4,y4;  
  7. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;  
  8.   
  9. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)  
  10. {  
  11.     static TCHAR szAppName[] = TEXT ("GUA") ;  
  12.     HWND hwnd ;  
  13.     MSG msg ;  
  14.     WNDCLASS wndclass ;  
  15.     wndclass.style = CS_HREDRAW | CS_VREDRAW ;  
  16.     wndclass.lpfnWndProc = WndProc ;  
  17.     wndclass.cbClsExtra = 0 ;  
  18.     wndclass.cbWndExtra = 0 ;  
  19.     wndclass.hInstance = hInstance ;  
  20.     wndclass.hIcon = LoadIcon (NULL, IDI_application) ;  
  21.     wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;  
  22.     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;  
  23.     wndclass.lpszMenuName = NULL ;  
  24.     wndclass.lpszClassName = szAppName ;  
  25.     if (!RegisterClass (&wndclass))  
  26.     {  
  27.         MessageBox ( NULL, TEXT ("Program requires Windows NT!"),  
  28.             szAppName, MB_ICONERROR) ;  
  29.         return 0 ;  
  30.     }  
  31.         hwnd = CreateWindow (szAppName, TEXT ("Programmed By DC"),  
  32.             WS_OVERLAPPEDWINDOW,  
  33.             CW_USEDEFAULT, CW_USEDEFAULT,  
  34.             CW_USEDEFAULT, CW_USEDEFAULT,  
  35.             NULL, NULL, hInstance, NULL) ;  
  36.         ShowWindow (hwnd, iCmdShow) ;  
  37.         SetForegroundWindow(hwnd);  
  38.         MoveWindow(hwnd,100,100,200,200,TRUE);  
  39.         UpdateWindow (hwnd) ;  
  40.         while (GetMessage (&msg, NULL, 0, 0))  
  41.         {  
  42.             TranslateMessage (&msg) ;  
  43.             DispatchMessage (&msg) ;  
  44.         }         
  45.         return msg.wParam ;  
  46.     }  
  47.   
  48. void Draw(HWND hwnd,LPCSTR lpString)  
  49. {  
  50.     HDC hdc ;    
  51.     PAINTSTRUCT ps ;    
  52.     RECT rect ;   
  53.     hdc = BeginPaint (hwnd, &ps) ;    
  54.     GetClientRect (hwnd, &rect) ;    
  55.     DrawText (hdc, lpString, -1, &rect,  DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;    
  56.     EndPaint (hwnd, &ps) ;   
  57.     ReleaseDC(hwnd,hdc);  
  58. }  
  59.   
  60. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)  
  61. {  
  62.     HBRUSH hBrush ;  
  63.     HDC hdc ;  
  64.     PAINTSTRUCT ps ;  
  65.     RECT rc ;  
  66.     switch (message)  
  67.     {  
  68.         case WM_CREATE:  
  69.             return 0 ;  
  70.         case WM_PAINT :  
  71.             return 0 ;  
  72.         case WM_KEYDOWN:    
  73.             switch (wParam)    
  74.            {    
  75.             case VK_F1:    
  76.                     GetCursorPos(&startP);  
  77.                     flag=1;  
  78.                     InvalidateRect (hwnd, NULL, TRUE) ;  
  79.                     Draw(hwnd,"第1點已鎖定!");  
  80.                     break ;    
  81.             case VK_F2:    
  82.                     GetCursorPos(&endP);  
  83.                     flag=2;  
  84.                     InvalidateRect (hwnd, NULL, TRUE) ;  
  85.                     Draw(hwnd,"第2點已鎖定!");  
  86.                     break ;   
  87.             case 0x31:   
  88.                     x5 = (int)(endP.x + ra * ((endP.x - startP.x) / sqrt((endP.x - startP.x) * (endP.x - startP.x) + (endP.y - startP.y) * (endP.y - startP.y))));  
  89.                     y5 = (int)(endP.y + ra * ((endP.y - startP.y) / sqrt((endP.x - startP.x) * (endP.x - startP.x) + (endP.y - startP.y) * (endP.y - startP.y))));  
  90.                     SetCursorPos(x5, y5);  
  91.                     break;  
  92.             case 0x32:   
  93.                     x2 = (int)(endP.x - ra * ((-endP.x + startP.x) / sqrt((-endP.x + startP.x) * (-endP.x + startP.x) + (endP.y - startP.y) * (endP.y - startP.y))));  
  94.                     y2 = (int)(endP.y + ra * ((endP.y - startP.y) / sqrt((-endP.x + startP.x) * (-endP.x + startP.x) + (endP.y - startP.y) * (endP.y - startP.y))));  
  95.                     SetCursorPos(x2, y2);  
  96.                     break;  
  97.             case 0x33:                      
  98.                     x3 = (int)(endP.x + ra * ((endP.x - startP.x) / sqrt((endP.x - startP.x) * (endP.x - startP.x) + (-endP.y + startP.y) * (-endP.y + startP.y))));  
  99.                     y3 = (int)(endP.y - ra * ((-endP.y + startP.y) / sqrt((endP.x - startP.x) * (endP.x - startP.x) + (-endP.y + startP.y) * (-endP.y + startP.y))));  
  100.                     SetCursorPos(x3, y3);  
  101.                     break;  
  102.             case 0x34:  
  103.                     x4 = (int)(endP.x - ra * ((-endP.x + startP.x) / sqrt((-endP.x + startP.x) * (-endP.x + startP.x) + (-endP.y + startP.y) * (-endP.y + startP.y))));  
  104.                     y4 = (int)(endP.y - ra * ((-endP.y + startP.y) / sqrt((-endP.x + startP.x) * (-endP.x + startP.x) + (-endP.y + startP.y) * (-endP.y + startP.y))));  
  105.                     SetCursorPos(x4, y4);  
  106.                     break;  
  107.             }  
  108.             return 0;  
  109.         case WM_SIZE :   
  110.             if(flag==1)  
  111.             {  
  112.                 Draw(hwnd,"第1點已鎖定!");  
  113.             }  
  114.             else if(flag==2)  
  115.             {  
  116.                 Draw(hwnd,"第2點已鎖定!");  
  117.             }  
  118.             else  
  119.             {InvalidateRect (hwnd, NULL, TRUE) ; }  
  120.             return 0 ;  
  121.         case WM_KILLFOCUS:  
  122.             InvalidateRect (hwnd, NULL, TRUE) ;  
  123.             hdc = BeginPaint (hwnd, &ps) ;  
  124.             GetClientRect (hwnd, &rc) ;  
  125.             hBrush = CreateSolidBrush ( RGB(255,0,0) ) ;  
  126.             FillRect (hdc, &rc, hBrush) ;  
  127.             EndPaint (hwnd, &ps) ;  
  128.             ReleaseDC(hwnd,hdc);  
  129.             DeleteObject (hBrush) ;  
  130.             return 0;  
  131.         case WM_SETFOCUS:  
  132.             InvalidateRect (hwnd, NULL, TRUE) ;  
  133.             if(flag==1)  
  134.             {  
  135.                 Draw(hwnd,"第1點已鎖定!");  
  136.             }  
  137.             else if(flag==2)  
  138.             {  
  139.                 Draw(hwnd,"第2點已鎖定!");  
  140.             }  
  141.             return 0;  
  142.         case WM_DESTROY :  
  143.             PostQuitMessage (0) ;  
  144.             return 0 ;  
  145.     }  
  146.     return DefWindowProc(hwnd, message, wParam, lParam) ;  
  147. }  

 

但是問題還存在,就是手動找圓心太麻煩,一般用觸摸板比鼠標方便,但是仍然很不智能,于是一直想著用圖像處理的方法去自動找圓心。

這幾天在做數模,經常用到Matlab,剛做了一道要處理圖像的題,正好想起這個問題來,于是,擱置的瞄準器繼續開始完善了。

很快就有了思路,通過C#截圖,然后Matlab進行圖像濾波,灰度化,二值化以及邊緣提取,然后進行圓曲線擬合,最后找到圓心,返回到C#中使用,代替手動找點。

首先,我用Matlab寫了個函數:

Html代碼 
  1. function [x,y]=findcenter()  
  2. %close all,clear,clc  
  3. format short  
  4. a=imread('E:/360data/重要數據/桌面/test.bmp');  
  5. b=rgb2gray(a);%轉化為灰度圖像  
  6. %figure;imshow(b)  
  7. b=filter2(fspecial('average',1),b)/255;  
  8. %b=medfilt2(b);%中值濾波  
  9. level=graythresh(b);%自動獲取灰度圖片的閾值  
  10. c=im2bw(b,level);%二值化  
  11. %figure;imshow(c)  
  12. bw=edge(c,'canny');  
  13. bw1=~bw;%取反,黑變白,白變黑  
  14. %figure;imshow(bw1)  
  15. %figure;imshow(bw1)  
  16. [yf,xf]=find(bw1==0);  
  17. xmin=min(xf);  
  18. xmax=max(xf);  
  19. ymin=min(yf);  
  20. ymax=max(yf);  
  21. %cirPx=[xmin;(xmax-xmin)/2;(xmax-xmin)/2;xmax]  
  22. %cirPy=[(ymax-ymin)/2;ymin;ymax;(ymax-ymin)/2]  
  23. %fitellipse(cirPx,cirPy)  
  24. centerX=(xmax+xmin)/2;  
  25. centerY=(ymax+ymin)/2;  
  26. ra=(ymax-ymin)/2;  
  27. x=centerX;y=centerY;  
  28. %hold on  
  29. %x=0:size(bw1,2);  
  30. %degree=[0:0.01:pi*2];  
  31. %degree=[0:0.01:pi*2];  
  32. %plot(ra*cos(degree)+centerX,ra*sin(degree)+centerY,'r-');  
  33. %plot(centerX,centerY,'r+');  

然后用Matlab2010b里的deploytool導出.net能使用的程序集dll文件(不知道為什么malab2009b在build時出現.net framework相關的錯誤),通過C#添加引用,調用其返回的參數,成功完成自動拾取圓心。

 

 

改進后代碼如下:

Csharp代碼 
  1. using System.Drawing;  
  2. using System.Windows.Forms;  
  3. using System.Windows;  
  4. using System.Runtime.InteropServices;  
  5. using System;  
  6. using MathWorks.MATLAB.NET.Arrays;  
  7. using MathWorks.MATLAB.NET.Utility;  
  8. using findcenter;  
  9.   
  10. namespace TaiqiuGua  
  11. {  
  12.   
  13.     public partial class Form1 : Form  
  14.     {  
  15.         const int ra=25;  
  16.         [DllImport("user32.dll")]  
  17.         static extern IntPtr GetDesktopWindow();  
  18.         [DllImport("user32.dll")]  
  19.         static extern IntPtr GetWindowDC(IntPtr hWnd);  
  20.         [DllImport("user32.dll")]  
  21.         static extern bool SetCursorPos(int X, int Y);  
  22.   
  23.         public Form1()  
  24.         {  
  25.             InitializeComponent();  
  26.         }  
  27.   
  28.         Point startP,startP1;  
  29.         Point endP,endP1;  
  30.           
  31.         private void Form1_KeyDown(object sender, KeyEventArgs e)  
  32.         {  
  33.             switch(e.KeyData)  
  34.             {  
  35.                 case Keys.F1:  
  36.                     startP=Control.MousePosition;  
  37.                     break;  
  38.                 case Keys.F5:  
  39.                     endP = Control.MousePosition;  
  40.                     break;  
  41.                 case Keys.F2:  
  42.                     startP1 = Control.MousePosition;  
  43.                     break;  
  44.                 case Keys.F3:  
  45.                     endP1 = Control.MousePosition;  
  46.                     break;  
  47.                 case Keys.D1:  
  48.                     int x1 = (int)(endP.X + ra * ((endP.X - startP.X) / Math.Sqrt((endP.X - startP.X) * (endP.X - startP.X) + (endP.Y - startP.Y) * (endP.Y - startP.Y))));  
  49.                     int y1 = (int)(endP.Y + ra * ((endP.Y - startP.Y) / Math.Sqrt((endP.X - startP.X) * (endP.X - startP.X) + (endP.Y - startP.Y) * (endP.Y - startP.Y))));  
  50.                     SetCursorPos(x1, y1);  
  51.                     break;  
  52.                 case Keys.D2:  
  53.                     int x2 = (int)(endP.X - ra * ((-endP.X + startP.X) / Math.Sqrt((-endP.X + startP.X) * (-endP.X + startP.X) + (endP.Y - startP.Y) * (endP.Y - startP.Y))));  
  54.                     int y2 = (int)(endP.Y + ra * ((endP.Y - startP.Y) / Math.Sqrt((-endP.X + startP.X) * (-endP.X + startP.X) + (endP.Y - startP.Y) * (endP.Y - startP.Y))));  
  55.                     SetCursorPos(x2, y2);  
  56.                     break;  
  57.                 case Keys.D3:                      
  58.                     int x3 = (int)(endP.X + ra * ((endP.X - startP.X) / Math.Sqrt((endP.X - startP.X) * (endP.X - startP.X) + (-endP.Y + startP.Y) * (-endP.Y + startP.Y))));  
  59.                     int y3 = (int)(endP.Y - ra * ((-endP.Y + startP.Y) / Math.Sqrt((endP.X - startP.X) * (endP.X - startP.X) + (-endP.Y + startP.Y) * (-endP.Y + startP.Y))));  
  60.                     SetCursorPos(x3, y3);  
  61.                     break;  
  62.                 case Keys.D4:  
  63.                     int x4 = (int)(endP.X - ra * ((-endP.X + startP.X) / Math.Sqrt((-endP.X + startP.X) * (-endP.X + startP.X) + (-endP.Y + startP.Y) * (-endP.Y + startP.Y))));  
  64.                     int y4 = (int)(endP.Y - ra * ((-endP.Y + startP.Y) / Math.Sqrt((-endP.X + startP.X) * (-endP.X + startP.X) + (-endP.Y + startP.Y) * (-endP.Y + startP.Y))));  
  65.                     SetCursorPos(x4, y4);  
  66.                     break;  
  67.                 case Keys.F4:  
  68.                     //Graphics g1 = pictureBox1.CreateGraphics();  
  69.                     //g1.CopyFromScreen(startP1.X,startP1.Y,0,0,new Size(endP1.X-startP1.X,endP1.Y-startP1.Y));  
  70.                     int w=endP1.X - startP1.X;  
  71.                     int h=endP1.Y - startP1.Y;  
  72.                     Bitmap bmSave = new Bitmap(w,h);  
  73.                     Graphics g=Graphics.FromImage(bmSave);  
  74.                     g.CopyFromScreen(startP1.X,startP1.Y,0,0,new Size(w,h),CopyPixelOperation.SourceCopy);  
  75.                     bmSave.Save(@"E:/360data/重要數據/桌面/test.bmp");  
  76.                     g.Dispose();  
  77.                     //g1.Dispose();  
  78.                     bmSave.Dispose();  
  79.                     findcenter.Class1 f = new findcenter.Class1();       
  80.                     MWArray centerx = f.findcenter();  
  81.                     MWArray centery = f.findy();  
  82.                     double[,] x = (double[,])centerx.ToArray();  
  83.                     double[,] y = (double[,])centery.ToArray();  
  84.                     SetCursorPos((int)(x[0, 0] + startP1.X), (int)(y[0, 0] + startP1.Y));  
  85.                     //int [] d=center.Dimensions;                      
  86.                     //int x=int.Parse((center[1, 1]).ToString());  
  87.                     //int y= int.Parse((center[1, 2]).ToString());  
  88.                     //MessageBox.Show((y[0,0]).ToString());  
  89.                     f.Dispose();  
  90.                     break;  
  91.             }  
  92.             GC.Collect();  
  93.         }  
  94.   
  95.         private void Form1_Activated(object sender, EventArgs e)  
  96.         {  
  97.             //this.BackColor = Color.Red;  
  98.         }  
  99.   
  100.         private void Form1_Deactivate(object sender, EventArgs e)  
  101.         {  
  102.             //this.BackColor = Color.Blue;  
  103.         }  
  104.   
  105.     }  
  106. }  

經試驗,成功率也很高,偶爾出現不準(估計是邊緣提取和計算精度的問題),但是大多數偏差可以手動修正。

到此為止,改進版全部完成。希望以后繼續改進,更加智能化。C# 真是碼農的利器啊!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 子长县| 阿勒泰市| 育儿| 克拉玛依市| 全椒县| 民乐县| 柞水县| 崇阳县| 扎鲁特旗| 永善县| 建湖县| 舞阳县| 宜兴市| 奉新县| 扶沟县| 临邑县| 陇川县| 名山县| 邵阳市| 华蓥市| 顺昌县| 朝阳市| 临沧市| 宣城市| 肃宁县| 红河县| 伽师县| 奉贤区| 麦盖提县| 南江县| 桂平市| 礼泉县| 汽车| 施甸县| 北川| 米脂县| 盐津县| 焉耆| 响水县| 荥经县| 东城区|