一、前言

    写这个只是为了练习java跟opencv来做图像识别,并不是以刷分作为初衷,而且分数高了也提交不上去,会说存在可疑操作,不知道它的检测机制是怎样的,可能是触摸坐标还有间隔时间一直没变的原因。

二、所需的工具

    1.ADB工具(Android Debug Bridge tools),安卓调试桥工具,用这个就可以在电脑命令行输入命令,完成触摸,按压,截图等等一系列操作。

1)如果你电脑安装有Android SDK,可以去SDK的文件夹找一下,比如我的是在C盘:C:\Android\android-sdk\platform-tools,里面就有adb.exe。复制这个路径,到系统环境变量中找到Path添加进去就行了(不知道怎么配置环境变量可以去百度一哈)。

2)如果你电脑没有安装Android SDK的话,直接去http://adbshell.com/downloads下载ADB kits就好了,下载下来打开其实就相当于解压了,随便选个地方放好文件夹之后,同样选择adb.exe所在的路径,复制去配置环境变量。

3)配置完环境变量以后,win+R输入cmd,回车打开命令行窗口,输入adb再回车,如果能看到下面这些说明就是配置成功了,同时可以看到我的版本号是1.0.39,最好是32以上吧,我试过1.0.26的发现并不能正常使用。

4)接下来就可以用USB线连接电脑和手机了,首先手机要打开开发者选项(怎么打开不同的手机可能不一样,不懂就问下百度吧),勾选允许USB调试,此时会提示你授权电脑连接,确认即可。如果USB插上电脑时,手机只能看到正在充电,而没有显示USB连接方式(让你选媒体设备(MTP)、相机(PTP)之类的)时,可以换一条数据线试一下。以上都没问题的话,就可以在命令行输入adb devices了,显示如下:。一串数字字母+device说明就是成功连接了,如果只显示List of devices attached的话,或者device显示的是offline的话,尝试检查下驱动或者检查一下adb版本是否太低或者是否打开了开发者模式且允许USB调试。上述都成功的话就可以试一下使用adb命令了,如截图:adb shell screencap /sdcard/1/test/1.png 后面的路径表示截图存储的路径,回车执行完在手机的文件管理器中,sdcard一般是手机的内部存储,可以把它理解为根目录了,1/test下面就有一张1.png的图片了。

2. opencv(一个开源的计算机视觉库)。opencv可以去官网下载,不过速度堪忧,这里贴个我的网盘,版本是3.2.0,最新的是3.4。下载完后双击打开解压到任意目录就好了。

3. eclipse(编写java代码的IDE)。这里就不说我们安装java环境和eclipse了。主要讲一下eclipse怎么配置opencv。

1)打开eclipse,选择windows->Preferences->Java->Build Path->User libraries,点击右边的new,填入一个名字,我写的是opencv-3.2

点击ok,选中刚才创建的,点击右边的Add External JARs...,选择你解压的opencv的目录下的build\java\opencv-320.jar。然后就会是这样子的

,接着选中Native library location,点击右边的Edit,同样打开你opencv解压的目录下的build\java\,如果你电脑是32位的就选择x86文件夹,64位就选x64文件,接着点Apply and Close关闭窗口即可。

2)新建一个java工程,在工程上右键选择,Build Path->configure Build Path,选择上边的Libraries,再选择右边的Add Library,选中User Library,点击next,就能看到刚才添加的opencv-3.2了,打上勾,点击finish就好了。至此配置完成。

3)新建一个类测试一下opencv,添加以下代码,能输出矩阵说明opencv配置就没问题了:

import org.opencv.core.Mat;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Scalar;class SimpleSample {public static void main(String[] args) {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));System.out.println("OpenCV Mat: " + m);Mat mr1 = m.row(1);mr1.setTo(new Scalar(1));Mat mc5 = m.col(5);mc5.setTo(new Scalar(5));System.out.println("OpenCV Mat data:\n" + m.dump());}}

三、实现思想

  1. 我们知道跳一跳是根据我们按压屏幕时间长短来决定弹跳距离的,按压屏幕时间越长跳的越远,所以按压屏幕时间是与距离成正比的,即两者之间肯定有一个系数使得按压时间=起点到落地点的距离*系数,这里我把这个系数称为弹跳系数。
  2. 为得到按压时间我们必须先知道起点和落地点的距离和弹跳系数,弹跳系数可以在得出距离之后通过手动修改得到一个比较合适的值,我们接下来讲怎么得到起点和落地点之间的距离。
  3. 首先找到起点。由于小人是固定不变的,找到小人就找到了起点,这时候就用到了opencv的模板匹配了,通过opencv的模板匹配找到小人的起点,注意这里是小人的起点,就是小人在图片中最先匹配到的地方(图中绿色矩形左上角),有了这个点再加上一定的高度宽度就能得到起点坐标(图中蓝色的点)。
  4. 找到落地点的方法有两种,第一种是找到小白点,我们知道有时候在一个落地的地方中心会出现一个小白点,如果我们能找到这个小白点的坐标,那么就能准确定位到落地点的坐标,这时候同样利用到opencv的模板匹配来匹配小白点,然而小白点并不是经常有的,而且也比较难匹配到,我们就有了第二种方法,边缘检测,经过边缘检测的图如下,可以明显的看到物体的轮廓,我们只要确定落脚区域,计算出落脚区域的中心点,就是我们需要的落脚点。此时我们要知道,落脚位置肯定位于屏幕的上半部分,且不会上半部分中分数所占的部分,这样我们就能缩小一大部分的区域了。

四、详细步骤及代码编写:

1. 新建com.main包,在这个包下面新建Main.java类文件,并编写main方法入口,建议在进行接下来的第二步时,把每个步骤逐步的在main方法调用,有助于我们查看程序的执行过程并及时发现错误,不要等代码全部写完再来调用。

2. 新建com.util包,在这个包下面新建MyOpencv.java类文件,用于封装使用到的opencv的方法,便于我们调用。(顺便提一下这里小人图片和小白点最好从手机截,不要在电脑上打开图片再截,这样准确一点,还有手机如果有悬浮球的话在运行的时候关掉,不然也会导致误判)

1) 首先来看一下我们需要给MyOpencv这个类添加什么属性

 String bodyImg; //小人图片径,用于匹配String sourceImg;    //每一次起跳前的截图String whiteDotImg;  //小白点图片,能匹配到就是终点Point bodyPoint;     //小人的左上角坐标Point startPoint; //起点,即小人的中心Point endPoint;       //终点,下一个落点的中心long distance;  //起点到终点的距离int presstime;        //按压的时间,private Mat body;   //Mat存放小人图片的像素矩阵private Mat source; //截图的像素矩阵private Mat result; //模板匹配结果存放private Mat imgCanny; //边缘检测像素图,灰度图private MyFrame frame;  //最终做成了一个窗体,MyFrame继承JFrame,下个步骤再讲这个

2) 构造方法,不多说,常规初始化

public MyOpencv(String bodyImg,String sourceImg,String whiteDotImg,MyFrame frame) {this.bodyImg = bodyImg;this.sourceImg = sourceImg;this.whiteDotImg = whiteDotImg;this.startPoint = new Point(0,0);this.endPoint = new Point(0,0);this.bodyPoint = new Point(0,0);this.distance = 0;this.presstime = 0;this.frame = frame;}

3) 接着我们来找起跳点,先找到小人

//采用图像模板匹配,模板为小人,匹配小人在截图中的位置,从而得到起点坐标public void matchBody() {//这句话一定要加,而且要在最前面,不然后面的操作都会报错!!!System.loadLibrary(Core.NATIVE_LIBRARY_NAME);      //像素矩阵初始化,分别读入小人图片还有上传上来的整张截图this.body = Imgcodecs.imread(this.bodyImg);this.source = Imgcodecs.imread(this.sourceImg);//result存放模板匹配后的结果,先初始化为0,大小和截图大小一样this.result = Mat.zeros(source.rows(), source.cols(),source.type());//这里就是模板匹配了,w3school有相关介绍 https://www.w3cschool.cn/opencv/opencv-pswj2dbc.htmlImgproc.matchTemplate(source, body, result, Imgproc.TM_CCOEFF_NORMED);//在给定的矩阵中寻找最大和最小值(包括它们的位置),minMaxLocResult 返回的 maxLoc为匹配的模板在截图中的左上位置MinMaxLocResult minMaxLocResult = Core.minMaxLoc(result);//bodyPoint表示小人在截图中的左上角坐标this.bodyPoint = new Point(minMaxLocResult.maxLoc.x, minMaxLocResult.maxLoc.y);System.out.println("小人坐标起点:"+this.bodyPoint);//根据小人的高度和宽度以及在截图中的位置,粗略得到小人的中心点,即起点Point point = new Point(this.bodyPoint.x + body.width()/2, this.bodyPoint.y + 0.8*body.height());this.setStartPoint(point);System.out.println("起点坐标:"+this.startPoint);//复制一份截图,添加小人的标记和起点标记Mat mark = this.source.clone();   //绘制一个矩形把小人框起来Imgproc.rectangle(mark, bodyPoint, new Point((int)(this.bodyPoint.x+this.body.cols()), (int)(this.bodyPoint.y+this.body.rows())),new Scalar(0,255,0),5); //绘制一个点,表示标出来的起点Imgproc.circle(mark,startPoint , 10,new Scalar(255,0,0), -1);//将标记好的图写出,生成mark.jpgImgcodecs.imwrite("images/mark.jpg", mark);      //在Main.java的main方法里面创建一个MyOpencv对象,调用这个方法,就可以在这个工程文件夹下的images/里面看到mark.jpg的图片了,即匹配结果,看看效果吧}

4)通过上面的方法已经找到了起点,我们在前面提到在有小白点的前提下我们直接找到小白点就能确定终点,找不到还得做进一步的边缘检测,所以我们先找小白点

public boolean findWhiteDot() {//找小白点同样也是利用和找小人一样的方法:模板匹配//读入小白点的像素矩阵Mat whiteDot = Imgcodecs.imread(this.whiteDotImg);//读入截图的像素矩阵source = Imgcodecs.imread(this.sourceImg);//匹配结果的像素矩阵,初始化为0,大小和截图大小一致Mat dotResult = Mat.zeros(this.source.rows(), this.source.cols(),this.source.type());Imgproc.matchTemplate(this.source, whiteDot, dotResult, Imgproc.TM_CCOEFF_NORMED);MinMaxLocResult dotLocResult = Core.minMaxLoc(dotResult);//当匹配值大于0.8时就可以认为我们找到小白点,获取终点坐标,返回值为真if(dotLocResult.maxVal > 0.8) {System.out.println("小白点匹配值:"+dotLocResult.maxVal);System.out.println("找到小白点");this.endPoint.x = dotLocResult.maxLoc.x + whiteDot.width()/2;this.endPoint.y = dotLocResult.maxLoc.y + whiteDot.height()/2;//找到小白点时同样做标记输出到images文件夹Mat imgResult = source.clone();Imgproc.circle(imgResult, endPoint, 10, new Scalar(255, 255, 0),-1);Imgcodecs.imwrite("images/dotLocResult.jpg", imgResult);return true;}//没找到小白点返回falsereturn false;}

5)当findWhiteDot()返回false时说明没找到小白点,那就要做边缘检测了

public void edgeDetection() {//初始化矩阵为0,宽高和原截图一样Mat imgBlur = Mat.zeros(source.rows(), source.cols(),CvType.CV_32FC1);//对图片进行高斯模糊处理,去除噪点Imgproc.GaussianBlur(source, imgBlur, new Size(5,5), 0);//将经过高斯模糊处理的图片写出到文件夹Imgcodecs.imwrite("images/imgBlur.jpg", imgBlur);//初始化矩阵为0,宽高和原截图一样this.imgCanny = Mat.zeros(this.source.rows(), this.source.cols(),CvType.CV_32FC1);//高斯模糊处理后的图片进行边缘检测处理Imgproc.Canny(imgBlur, this.imgCanny, 1, 10);//因为后面要对图片进行裁剪,裁剪后可能会有小人的一部分身体出现,所以要先把图片中的小人抹掉,以免裁剪后出现小人影响计算//像素点为0为黑色,我们知道小人的起点坐标和大小,所以在这个范围内将像素点全部置0即可抹去小人for(int i = (int)this.bodyPoint.x; i <= (int)(this.bodyPoint.x+this.body.width()); i++) {for(int j = (int)this.bodyPoint.y; j <= (int)(this.bodyPoint.y+this.body.height()); j++) {this.imgCanny.put(j, i, 0);//注意这里的i和j,x坐标在像素图中是列数,y是行数}}//边缘检测后的图片输出到文件夹Imgcodecs.imwrite("images/imgCanny.jpg", this.imgCanny);}

6)边缘检测之后我们只要对图片进行裁剪,再进行计算,就能得到终点了,先讲下计算思路

这是一张将原截图经过边缘检测后并且裁剪了该截图从上往下数1/4处到1/2处之后的图片,我们很准确的得到了小人下一个落点的方块,为了直观的展示怎么计算落地点,我手动标注了绿色的线和红色的点(所以线画的有点歪),很明显,C点就是我们要求的落地点,A点是这个圆形最顶部的点,B点是这个圆形最右边的点,不难看出,C点的横坐标坐标恰巧就是A点的横坐标,C点的纵坐标就是B点的纵坐标,在这张图中,只有白色和黑色(白色是255,黑色是0),所以我们遍历整张像素图,找到第一个值为255的点(即A点),再找到值为255的点中横坐标最大的点(即B点),就能得出C点的坐标了。当然这个坐标不是最终的坐标,因为上半部分还有一部分被我们裁剪掉了,C点的纵坐标加回去这个裁剪掉的高度,就是在原图中真正的落地点(终点)坐标了,看下代码:

public void findEndPoint() {//先对边缘检测后的图片进行剪切//剪切是因为落地点只会在图片的上半部分,减少搜索范围//而且是在分数的下边,所以可以划分出一个大概的区域(从坐标(0,图片高度的1/4处)开始的宽为原图片的宽,长度为原图片的1/4的矩形)Mat imgCut = new Mat(this.imgCanny, new Rect(0, (int)Math.round(source.height()*0.25), source.width(), (int)Math.round(source.height()*0.25)));//复制一份,输出到文件夹Mat imgCopy = imgCut.clone();Imgcodecs.imwrite("images/imgCut.jpg", imgCopy);imgCopy.convertTo(imgCopy, CvType.CV_64FC3);    //不做这一步下面的计算会报错int size = (int) (imgCopy.total() * imgCopy.channels());    //像素点总数*通道数,灰度图通道数为1System.out.println("裁剪后的图片宽高:"+imgCopy.rows()+","+imgCopy.cols());System.out.println("像素点数量:"+size);System.out.println("通道数:"+imgCopy.channels());double data[] = new double[size];   //存储像素点的一维数组imgCopy.get(0, 0, data);    //将从(0,0)像素点的值存放到数组中,只有两种值,0为黑色,255为白色//不出错的话裁剪后的图基本只剩终点所在的方块,从上至下,从左至右//找到第一个白色点A(x1,y1),以及横坐标最大的白色点B(x2,y2),终点的坐标即为(x1,y2)Point point = new Point(0,0);int maxX = 0; //存储最大x坐标for(int i = 0; i < imgCopy.rows();i++) {for(int j = 0; j < imgCopy.cols(); j++) {//坐标在一维数组的下标转换(i,j)→[i*每行的列数+当前所在的列数j]if((int)data[i*imgCopy.cols()+j] == 255&&point.x == 0) {point.x = j;}if((int)data[i*imgCopy.cols()+j] == 255 && j>maxX && point.x!=0) {point.y = i;maxX = j;}}}//标记在裁剪后的图片中的终点,这时得到的坐标并不是真正的终点坐标,因为是以裁剪后的图片左上角为起点Imgproc.circle(imgCopy, endPoint,10,new Scalar(255,0,255), -1);Imgcodecs.imwrite("images/imgCut.jpg", imgCopy);point.y += this.source.height()*0.25; //y坐标应加上裁剪的1/4,横坐标不变this.setEndPoint(point);Imgproc.circle(this.imgCanny, this.endPoint,10,new Scalar(255,0,255), -1);     Imgcodecs.imwrite("images/imgCanny.jpg", imgCanny);}

7)至此所有关于图像处理的函数封装书写完毕,接下来调用

public void setDistance() {//求出起点和终点的距离this.distance = Math.round(Math.sqrt(Math.pow(this.startPoint.x-this.endPoint.x, 2)+Math.pow(this.startPoint.y-this.endPoint.y, 2)));}public void setPretime(double x) {//设置按压时间,x为前面提到的弹跳系数this.presstime = (int)(this.distance*x);}public void go() {this.matchBody();this.edgeDetection();if(!findWhiteDot()) {this.findEndPoint();}this.setDistance();//传入的参数是弹跳系数,来自于窗体输入框中的值,方便程序运行时用户根据情况实时改变这个弹跳系数,默认是1.35this.setPretime(Double.parseDouble(this.frame.getTextField().getText()));}

3. 窗体代码

package com.frame;import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;import javax.swing.JFrame;
import javax.swing.JPanel;import org.opencv.core.Point;import com.util.MyOpencv;public class MyFrame extends JFrame{private Label label;private TextField textField;private Button startButton;private Button stopButton;private JPanel panel;private TextArea textArea;//截图和上传图片的adb命令private String cmdScreen = new String("adb shell screencap /sdcard/1.png");private String cmdPull = new String("adb pull /sdcard/1.png D:\\opencv\\WeixinJump\\images");private Point p1,p2;MyOpencv myOpencv = new MyOpencv("images/body.jpg", "images/1.png","images/whiteDot.jpg",this);private Timer timer;public MyFrame() {this.setTitle("微信跳一跳");this.setSize(300,300);this.setLocationRelativeTo(null);panel = new JPanel(new GridLayout(2, 2));this.add(panel,BorderLayout.CENTER);this.timer = new Timer();this.label = new Label("弹跳系数:");this.textField = new TextField("1.35");this.textArea = new TextArea("分辨率1080*1920弹跳系数:1.35");this.startButton = new Button("开始");this.stopButton = new Button("停止");this.panel.add(label);this.panel.add(textField);this.panel.add(startButton);this.panel.add(stopButton);this.add(textArea,BorderLayout.SOUTH);this.setVisible(true);this.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {// TODO Auto-generated method stubSystem.exit(0);}});this.startButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {timer = new Timer();//设置了一个定时器,后面参数1000和5000的意思启动时延迟1秒执行,每5秒执行一次,就能实现一直跳了timer.schedule(new TimerTask() {@Overridepublic void run() {// TODO Auto-generated method stubexecAdbCmd(cmdScreen); //截取当前手机屏幕并保存在手机中execAdbCmd(cmdPull); //将手机中的截图上传到电脑的文件夹中//调用opencv封装好的方法myOpencv.go();//这里获取起点的坐标,在起点坐标附近再随机产生一个坐标,保证每次触摸坐标都不一样,不过这样做还是会被判做操作异常p1 = myOpencv.getStartPoint();p2 = new Point(p1.x+Math.random()*10,p1.y+Math.random()*15);System.out.println("触摸坐标为"+p1+" "+p2);//按压屏幕的adb指令String cmd = String.format("adb shell input swipe %d %d %d %d %d ",(int)p1.x,(int)p1.y,(int)p2.x,(int)p2.y,myOpencv.getPresstime());execAdbCmd(cmd);System.out.println("ok");}}, 1000,5000);}});this.stopButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {try {timer.cancel();System.out.println("定时器取消");} catch (Exception e2) {e2.printStackTrace();}}});}public void execAdbCmd(String cmd) {try {Process proc = Runtime.getRuntime().exec(cmd);proc.waitFor();System.out.println("execute...");} catch (Exception e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}public TextField getTextField() {return textField;}public void setTextField(TextField textField) {this.textField = textField;}}

8. main方法就简单啦,new一个窗体出来就好了

package com.main;import com.frame.MyFrame;public class Main {public static void main(String[] args) {new MyFrame();}}

界面效果如图:

五、总结

1. 项目存在一个会失败的地方,自己玩过跳一跳的都会知道,跳一跳会出现一个音乐盒,落在上面停留一会就可以+30分,同时这个音乐盒会飘出来一串音符,并且是连续的,如图,处理过之后的图片是这样的,很明显可以看到,如果按照之前定位终点的办法,这里就会把终点定位到这个音符上面去了,导致游戏结束,当然触发这个的概率不是很高,以后有学到什么新的办法再来解决这个问题吧。

2. 总体来说知道了图片处理的思路,做出这样一个基于opencv的跳一跳辅助并不是很难,虽然保证不了百分百准确落在中心点(很大一点原因是因为计算时取整导致了坐标有些偏移),但有了这个跳一千分以上问题也不大,现在检测也很厉害了,超过三四百分就提交不上去了,不过我们是重在学习嘛~就这样了。

基于java+opencv的微信跳一跳辅助相关推荐

  1. 基于Node.js的微信跳一跳辅助工具

    项目地址:https://github.com/sbfkcel/WechatJumpGameHelper 这是一个需要手动来玩的辅脚本,也是最为保险,官方无法禁封的辅助工具: 支持Mac OS.win ...

  2. 微信跳一跳辅助程序开发,基于C++与opencv图像识别

    趁着期末这段时间,课程不多,在学习opencv,闲来无事,看到网上有大神用python实现了Wechat的跳一跳的辅助外挂,看了大概原理,似乎跟我最近学的opencv好像很沾边,但是鄙人实在不懂Pyt ...

  3. 微信跳一跳java实现自动跳_微信跳一跳辅助Java代码实现

    微信跳一跳辅助的Java具体实现代码,供大家参考,具体内容如下 1.参考知乎教你用Python来玩微信跳一跳,鉴于本人Python一直都是半吊子水平,之前打算用python刷分,可无奈安装python ...

  4. 100行微信跳一跳java_安卓版微信跳一跳辅助 跳一跳辅助Java代码

    安卓版微信跳一跳辅助,java实现,具体内容如下 已经看到网上有大神用各种方式实现了,我这是属于简易版ADB命令式实现. 操作方法 1.光标移动到起始点,点击FORM 2.光标移动到目标点,点击TO ...

  5. JAVA实现微信跳一跳辅助(手动)

    工具:total control . eclipse/java环境 . ADB 环境:1.1 total control 官网下载地址: http://tc.sigma-rt.com.cn/   下载 ...

  6. python微信公众号秒杀代码_微信跳一跳辅助python代码实现

    微信跳一跳辅助python代码实现 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  微信跳一跳辅助python代码实现.txt ] (友情提示:右键点上行txt文档 ...

  7. c语言微信自动跳一跳,C/C++知识点之微信跳一跳辅助c++实现 轻松上万

    本文主要向大家介绍了 C/C++知识点之微信跳一跳辅助c++实现 轻松上万,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助.写在前面 17年年底Wechat出了这个跳一跳的小游戏,今 ...

  8. 微信跳一跳python全部代码_微信跳一跳辅助python代码实现

    微信跳一跳辅助的python具体实现代码,供大家参考,具体内容如下 这是一个 2.5D 插画风格的益智游戏,玩家可以通过按压屏幕时间的长短来控制这个「小人」跳跃的距离.可能刚开始上手的时候,因为时间距 ...

  9. python跳一跳编程构造_python实现微信跳一跳辅助工具步骤详解

    说明 1.windows上安装安卓模拟器,安卓版本5.1以上 2.模拟器里下载安装最新的微信6.6.1 3.最好使用python2.7,python3的pyhook包有bug,解决比较麻烦 步骤 1. ...

最新文章

  1. Ajax PHP 边学边练 之四 表单
  2. 元素与核素有什么区别?
  3. OpenCV 高级API:TextDetectionModel和TextRecognitionModel
  4. 【CF 1195】Basketball Exercise/Submarine in the Rybinsk Sea (hard edition)/OpenStreetMap+二维单调队列滑动窗口模板
  5. 工作115:赋值给form对象
  6. 去除ring3层的Debug标志
  7. 【转】Linux ln(link) 命令详解
  8. 嵌入式Linux驱动学习之路(十五)按键驱动-定时器防抖
  9. (转载)Python函数参数传递机制(超级详细)
  10. 缅甸是一个怎样的国家?第一次去这里有什么注意事项?
  11. 什么是虚拟DOM(React16源码分析)
  12. 徐州工程学院计算机报名,2019年3月江苏徐州工程学院计算机等级考试报名时间...
  13. Django模糊查询
  14. Java定时任务工具详解之Timer篇
  15. idea中git替换,推送到新的github或者gitlab上面
  16. Faster RCNN (pytorch)(转载)
  17. 地图采集商家,附近商家,最新企业信息采集软件的使用教程
  18. 建立自己的人脸数据集
  19. ubuntu安装ROS教程
  20. 象棋在线对战网页源码源码安装

热门文章

  1. 华创期货:谈谈长线交易对于亏损或盈利的影响
  2. win全盘重分- DiskGenius
  3. isdigit python函数什么意思_Python isdigit() 方法检测字符串是否只由数字组成
  4. Python连接qq邮箱服务器,调用qq邮箱发送邮件实战演示,qq邮箱授权码开通方法
  5. 宝塔面板 存储型xss 弹弹弹
  6. 矩阵求导(本质、原理与推导)详解
  7. 计算机毕业设计Java舞蹈网站(源码+系统+mysql数据库+Lw文档)
  8. 关于opencv中 THRESH_TRUNC 参数的疑惑
  9. Qt QString详解
  10. Android着色状态栏实践