摘要: 极简单的方式序列化sqlalchemy结果集为JSON 阅读全文
posted @ 2017-07-06 11:00 StupidsCat 阅读(5794) 评论(4) 推荐(1) 编辑

现在的手游基本都是重复操作,一个动作要等好久,结束之后继续另一个动作.很麻烦,所以动起了自己写一个游戏辅助的心思.

这个辅助本身没什么难度,就是通过不断的截图,然后从这个截图中找出预先截好的能代表相应动作的按钮或者触发条件的小图.

找到之后获取该子区域的左上角坐标,然后通过windows API调用鼠标或者键盘做操作就行了.

这里面最难的也就是找图了,因为要精准找图,而且最好能适应不同的分辨率下找图,所以在模板匹配的基础上,就有了SIFT和SURF的特征点找图方式.

在写的过程中查找资料,大都是C++ 或者python的, 很少有原生的C#实现, 所以我就直接拿来翻译过来了(稍作改动).

SIFT算法


public Point2d Point2fToPoint2d(Point2f point) => new Point2d((double)point.X, (double)point.Y);


public
static Bitmap MatchPicBySift(Bitmap imgSrc, Bitmap imgSub) { using (Mat matSrc = imgSrc.ToMat()) using (Mat matTo = imgSub.ToMat()) using (Mat matSrcRet = new Mat()) using (Mat matToRet = new Mat()) { KeyPoint[] keyPointsSrc, keyPointsTo; using (var sift = OpenCvSharp.XFeatures2D.SIFT.Create()) { sift.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet); sift.DetectAndCompute(matTo, null, out keyPointsTo, matToRet); } using (var bfMatcher = new OpenCvSharp.BFMatcher()) { var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2); var pointsSrc = new List<Point2f>(); var pointsDst = new List<Point2f>(); var goodMatches = new List<DMatch>(); foreach (DMatch[] items in matches.Where(x => x.Length > 1)) { if (items[0].Distance < 0.5 * items[1].Distance) { pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt); pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt); goodMatches.Add(items[0]); Console.WriteLine($"{keyPointsSrc[items[0].QueryIdx].Pt.X}, {keyPointsSrc[items[0].QueryIdx].Pt.Y}"); } } var outMat = new Mat(); // 算法RANSAC对匹配的结果做过滤 var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d); var pDst = pointsDst.ConvertAll(Point2fToPoint2d); var outMask = new Mat(); // 如果原始的匹配结果为空, 则跳过过滤步骤 if (pSrc.Count > 0 && pDst.Count > 0) Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask); // 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果). if (outMask.Rows > 10) { byte[] maskBytes = new byte[outMask.Rows * outMask.Cols]; outMask.GetArray(0, 0, maskBytes); Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints); } else Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints); return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(outMat); } } }

SURF算法


  public static Point2d Point2fToPoint2d(Point2f point) => new Point2d((double)point.X, (double)point.Y);

public
static Bitmap MatchPicBySurf(Bitmap imgSrc, Bitmap imgSub, double threshold = 400) { using (Mat matSrc = imgSrc.ToMat()) using (Mat matTo = imgSub.ToMat()) using (Mat matSrcRet = new Mat()) using (Mat matToRet = new Mat()) { KeyPoint[] keyPointsSrc, keyPointsTo; using (var surf = OpenCvSharp.XFeatures2D.SURF.Create(threshold,4,3,true,true)) { surf.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet); surf.DetectAndCompute(matTo, null, out keyPointsTo, matToRet); } using (var flnMatcher = new OpenCvSharp.FlannBasedMatcher()) { var matches = flnMatcher.Match(matSrcRet, matToRet); //求最小最大距离 double minDistance = 1000;//反向逼近 double maxDistance = 0; for (int i = 0; i < matSrcRet.Rows; i++) { double distance = matches[i].Distance; if (distance > maxDistance) { maxDistance = distance; } if (distance < minDistance) { minDistance = distance; } } Console.WriteLine($"max distance : {maxDistance}"); Console.WriteLine($"min distance : {minDistance}"); var pointsSrc = new List<Point2f>(); var pointsDst = new List<Point2f>(); //筛选较好的匹配点 var goodMatches = new List<DMatch>(); for (int i = 0; i < matSrcRet.Rows; i++) { double distance = matches[i].Distance; if (distance < Math.Max(minDistance * 2, 0.02)) { pointsSrc.Add(keyPointsSrc[matches[i].QueryIdx].Pt); pointsDst.Add(keyPointsTo[matches[i].TrainIdx].Pt); //距离小于范围的压入新的DMatch goodMatches.Add(matches[i]); } } var outMat = new Mat(); // 算法RANSAC对匹配的结果做过滤 var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d); var pDst = pointsDst.ConvertAll(Point2fToPoint2d); var outMask = new Mat(); // 如果原始的匹配结果为空, 则跳过过滤步骤 if (pSrc.Count > 0 && pDst.Count > 0) Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask); // 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果). if (outMask.Rows > 10) { byte[] maskBytes = new byte[outMask.Rows * outMask.Cols]; outMask.GetArray(0, 0, maskBytes); Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints); } else Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints); return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(outMat); } } }

模板匹配

 public static System.Drawing.Point FindPicFromImage(Bitmap imgSrc, Bitmap imgSub, double threshold = 0.9)
        {
            OpenCvSharp.Mat srcMat = null;
            OpenCvSharp.Mat dstMat = null;
            OpenCvSharp.OutputArray outArray = null;
            try
            {
                srcMat = imgSrc.ToMat();
                dstMat = imgSub.ToMat();
                outArray = OpenCvSharp.OutputArray.Create(srcMat);
               
                OpenCvSharp.Cv2.MatchTemplate(srcMat, dstMat, outArray, Common.templateMatchModes);
                double minValue, maxValue;
                OpenCvSharp.Point location, point;
                OpenCvSharp.Cv2.MinMaxLoc(OpenCvSharp.InputArray.Create(outArray.GetMat()), out minValue, out maxValue, out location, out point);
                Console.WriteLine(maxValue);
                if (maxValue >= threshold)
                    return new System.Drawing.Point(point.X, point.Y);
                return System.Drawing.Point.Empty;
            }
            catch(Exception ex)
            {
                return System.Drawing.Point.Empty;
            }
            finally
            {
                if (srcMat != null)
                    srcMat.Dispose();
                if (dstMat != null)
                    dstMat.Dispose();
                if (outArray != null)
                    outArray.Dispose();
            }
        }

posted @ 2019-09-03 15:01 StupidsCat 阅读(9575) 评论(8) 推荐(7) 编辑
摘要: 先设置4个: [csharp] webrequest.ServicePoint.Expect100Continue = false; //是否使用 Nagle 不使用 提高效率 webrequest.ServicePoint.UseNagleAlgorithm = false; //最大连接数 webrequest.ServicePoint.ConnectionLimit = 65500; //数据是否缓冲 false ... 阅读全文
posted @ 2013-08-23 00:19 StupidsCat 阅读(3327) 评论(0) 推荐(1) 编辑
摘要: 子网的划分,实际上就是设计子网掩码的过程。子网掩码主要是用来区分IP地址中的网络ID和主机ID,它用来屏蔽IP地址的一部分,从IP地址中分离出网络ID和主机ID.子网掩码是由4个十进制数组成的数值"中间用"。"分隔,如255.255.255.0。若将它写成二进制的形式为:11111111.11111111.11111111.00000000,其中为"1"的位分离出网络ID,为"0"的位分离出主机ID,也就是通过将IP地址与子网掩码进行"与"逻辑操作,得出网络号. 每类地址具有默认的子网掩码:对于A类为25 阅读全文
posted @ 2013-08-14 15:15 StupidsCat 阅读(586) 评论(0) 推荐(0) 编辑
该文被密码保护。 阅读全文
posted @ 2013-08-13 11:17 StupidsCat 阅读(13) 评论(0) 推荐(0) 编辑
摘要: @echo off::获取日期 将格式设置为:20110820set datevar=%date:~0,4%%date:~5,2%%date:~8,2%::获取时间中的小时 将格式设置为:24小时制set timevar=%time:~0,2%if /i %timevar% LSS 10 (set timevar=0%time:~1,1%)::获取时间中的分、秒 将格式设置为:3220 ,表示 32分20秒set timevar=%timevar%%time:~3,2%%time:~6,2%@echo 当前时间:%datevar%%timevar%例子copy d:\1.exe "\ 阅读全文
posted @ 2013-08-07 21:12 StupidsCat 阅读(2089) 评论(0) 推荐(0) 编辑
摘要: 你想在五年之后,十年之后,或者一年之后的今天在哪?这些都是你的目标,你可不想一直呆在你现在的位置,但明确你的真正的目标是一件困难的事情。很多人认为设定人生目标就是找一些遥遥无期的梦想,但永远不会实现。这被看成是只是预言如何实现自己抱负,因为,第一,这些目标没有被足够详细的定义;第二,它始终只是一个目标,而没有相应的行动。定义你的目标是一件需要你花费很多时间仔细考虑的事情。下面的步骤可以让你开始这样的旅程:写出一个你的人生目标的清单。人生目标是一件重要的事,换句话说,就是你的人生抱负,不过抱负听起来总像一种超出你可控范围的事情,而人生目标是,如果你 愿意投入精力去做,就可能达到的。因此,你这一生 阅读全文
posted @ 2013-08-02 14:48 StupidsCat 阅读(363) 评论(0) 推荐(0) 编辑
摘要: EXEC sp_configure 'show advanced options', 1GORECONFIGUREGOEXEC sp_configure 'xp_cmdshell',1GORECONFIGUREGOEXEC master..xp_cmdshell 'net use Z: \\192.168.11.1\192.168.11.4BACKUP "bst123456" /user:192.168.11.1\shuiniao'GOexec master..xp_cmdshell 'net use \\192.16 阅读全文
posted @ 2013-08-01 17:04 StupidsCat 阅读(1420) 评论(0) 推荐(0) 编辑
摘要: 使用DMV来分析SQL Server启动以来累计使用CPU资源最多的语句。例如下面的语句就可以列出前50名SELECT TOP 50 s2.dbid, (SELECT TOP 1 SUBSTRING(s2.text,statement_start_offset / 2+1 , ( (CASE WHEN statement_end_offset = -1 THEN (LEN(CONVERT(nvarchar(max),s2.text)) * 2) ELSE statement_end_offset END) - statement_sta... 阅读全文
posted @ 2013-07-11 14:43 StupidsCat 阅读(518) 评论(0) 推荐(1) 编辑
摘要: 快速生成50W个16位的不重复的随机整数经测试,生成50W个不到1秒,500W两秒左右,1000W以上的话可能会内存溢出 Random rnd = new Random(); HashSet hs = new HashSet(); for (int i = 0; i < 500000; i++) { long l = (long)((rnd.NextDouble() + rnd.Next(1, 9)) / 10 * 9999999999999999); ... 阅读全文
posted @ 2013-07-10 14:45 StupidsCat 阅读(490) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示