引言

提起AccessibilityService首先想到的肯定是抢红包插件。没错,目前基本上抢红包插件分为两类:root和免root,而免root的红包插件全是基于AccessibilityService。随着AccessibilityService的广泛应用,现今已经有比较多的方法可以防御基于AccessibilityService实现的自动化插件了。有兴趣的朋友可以参考这篇文章:红包外挂史及AccessibilityService分析与防御。
本文通过AccessibilityService加上OpenCV辅助识别一些关键的特征,以此在高版本微信中实现抢红包的效果。

AccessibilityService基本用法

1、继承AccessibilityService

编写自己的Service类,必须重写onAccessibilityEvent()方法和onInterrupt()方法

public class HongbaoService extends AccessibilityService {/*** 当启动服务的时候就会被调用(非必须重写)*/@Overrideprotected void onServiceConnected() {super.onServiceConnected();}/*** 监听窗口变化的回调*/@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {int eventType = event.getEventType();//根据事件回调类型进行处理}/*** 中断服务的回调*/@Overridepublic void onInterrupt() {}
}

下面简要地介绍用到的几个AccessibilityEvent的事件类型

事件类型 描述
TYPE_VIEW_CLICKED View被点击
TYPE_VIEW_LONG_CLICKED View被长按
TYPE_VIEW_SELECTED View被选中
TYPE_NOTIFICATION_STATE_CHANGED 状态栏发生变化
TYPE_WINDOW_CONTENT_CHANGED 窗口内容发生变化
TYPE_WINDOW_STATE_CHANGED 打开弹出窗口、菜单、对话框等的时候触发

2、声明服务

首先,我们需要在manifests中配置该服务信息

        <serviceandroid:name=".service.HongbaoService"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"><intent-filter><action android:name="android.accessibilityservice.AccessibilityService" /></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@xml/accessible_service_config" /></service>

我们必须注意:任何一个信息配置错误,都会使该服务无反应

  • android:label:在无障碍列表中显示该服务的名字(默认与APP名字相同)
  • android:permission:需要指定BIND_ACCESSIBILITY_SERVICE权限,这是4.0以上的系统要求的
  • intent-filter:这个name是固定不变的
    ##3、配置服务参数
    配置服务参数是指:配置用来接受指定类型的事件,监听指定package,检索窗口内容,获取事件类型的时间等等。其配置服务参数有两种方法:
  • 方法一:安卓4.0之后可以通过meta-data标签指定xml文件进行配置
  • 方法二:通过代码动态配置参数

这里我使用的是第一种方法:
在项目中增加accessible_service_config文件,配置如下:

<accessibility-servicexmlns:android="http://schemas.android.com/apk/res/android"android:description="@string/app_description"android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged|typeNotificationStateChanged"android:accessibilityFeedbackType="feedbackAllMask"android:packageNames="com.tencent.mm"android:notificationTimeout="300"android:settingsActivity="com.shareder.ln_jan.wechatluckymoneygetter.activities.MainActivity"android:accessibilityFlags="flagDefault"android:canRetrieveWindowContent="true"android:canPerformGestures="true"/>
  • accessibilityEventTypes:表示该服务对界面中的哪些变化感兴趣,即哪些事件通知,比如窗口打开,滑动,焦点变化,长按等。具体的值可以在AccessibilityEvent类中查到,如typeAllMask表示接受所有的事件通知
  • accessibilityFeedbackType:表示反馈方式,比如是语音播放,还是震动
  • canRetrieveWindowContent:表示该服务能否访问活动窗口中的内容。也就是如果你希望在服务中获取窗体内容,则需要设置其值为true
  • description:对该无障碍功能的描述
  • notificationTimeout:接受事件的时间间隔,这里我设置的是300
  • packageNames:表示对该服务是用来监听哪个包的产生的事件,如"com.tencent.mm"为微信的包名
  • canPerformGestures: 安卓7.0后可通过dispatchGesture实现点击屏幕的操作,如需用此方法需将canPerformGestures设置为true

4、预备知识

4.1、获取节点信息

获取了界面窗口变化后,这个时候就要获取控件的节点。整个窗口的节点本质是个树结构,通过以下操作节点信息

1、获取窗口节点(根节点)

AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();

2、获取指定子节点(控件节点)

//通过文本找到对应的节点集合
List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText(text);
//通过控件ID找到对应的节点集合,如com.tencent.mm:id/gd
List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId(clickId);

4.2、模拟点击的方法

获取节点信息后可通过performAction方法或dispatchGesture方法产生点击屏幕的效果

1、performAction

//模拟点击
accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
//模拟长按
accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);

这种方法在微信6.6.1或之前的版本可用次方法拆开红包

2、dispatchGesture

GestureDescription gestureDescription = builder.addStroke(new GestureDescription.StrokeDescription(path, 450, 50)).build();
dispatchGesture(gestureDescription, new GestureResultCallback() {@Overridepublic void onCompleted(GestureDescription gestureDescription) {Log.e(TAG, "onCompleted");mPockeyOpenMutex = false;super.onCompleted(gestureDescription);}@Overridepublic void onCancelled(GestureDescription gestureDescription) {Log.e(TAG, "onCancelled");mPockeyOpenMutex = false;super.onCancelled(gestureDescription);}}, null);

微信6.7.3版本由于无法再通过遍历AccessibilityNodeInfo子节点找到拆红包按钮,故只能通过次方法实现模拟点击


微信抢红包原理分析及实现

1、原理分析

首先我们可以通过两种方式监控红包消息通知:监控微信悬浮框和监控屏幕状态变化
拆红包的流程可分为下列三种情况:

悬浮框通知

  • 通过TYPE_NOTIFICATION_STATE_CHANGED监控状态栏变化,当出现 [微信红包] 时进入微信,此时会直接进入到聊天页面

屏幕状态变化

  • 此时若在聊天页面则进入拆红包流程
  • 若在聊天列表页面则查找未读消息中是否包含 [微信红包] 字眼的信息,有则点击进入聊天页面

[聊天页面]拆红包流程

  • 通过findAccessibilityNodeInfosByText方法查找包含领取红包查看红包字样的节点,找到后通过performAction点击进入拆红包页面

  • 微信6.7.3版本前可通过getRootInActiveWindow获取窗口根节点,再通过遍历的方法找到唯一的一个Button节点,通过performAction点击该节点拆红包。但在6.7.3版本不再有效。故改用dispatchGesture根据屏幕分辨率判断**[开]**按钮的位置实现拆红包的功能。以本人手机为例,按钮位置如下:
    手机屏幕的尺寸是:1920*1080,则按钮点击的横坐标为x,纵坐标为y,则x、y的范围是:
    386<x<694 1015<y<1323

    计算按钮位置的代码如下:

                    Path path = new Path();if (640 == dpi) { //1440path.moveTo(720, 1575);} else if (320 == dpi) {//720ppath.moveTo(355, 780);} else if (480 == dpi) {//1080ppath.moveTo(533, 1115);} else if (440 == dpi) {//1080*2160path.moveTo(450, 1250);}
  • 拆开红包后通过performGlobalAction(GLOBAL_ACTION_BACK)方法从 [红包详情] 页面返回
  • 一次拆红包流程结束
    流程图如下:

2、注意事项

  • 在聊天列表中新版微信重写了TextView控件,这意味着不能通过findAccessibilityNodeInfosByText方法查找 [微信红包]
  • 由于新版微信中对已领取的红包会显示红包已被领取且不可再次点击,对于自己发放的红包若红包已领完会显示红包已被领完,若未领完则一直显示查看红包。所以只有在拆开自己发的红包时才需要做防止重复打开的处理。
  • 在国内第三方定制系统中出于对电量的优化,有可能限制AccessibilityService后台长时间运行。所以需要提醒用户设置后台运行权限

3、代码实现

聊天列表查找[微信红包]字样的新消息的实现

上面提到由于新版微信重写了TextView所以通过AccessibilityService基本上是获取不了任何聊天内容的消息了,相应的findAccessibilityNodeInfosByText方法也没有用了。
这里我的解决方法是通过截屏剪裁含有未读消息信息的区域,然后通过OpenCv特征点匹配的方式来确认哪些未读消息是包含 [微信红包] 的。具体实现如下:

  • MediaProjection实现屏幕截图

申请录屏权限

    /*** 申请屏幕录取权限*/private void requestScreenShot() {startActivityForResult(((MediaProjectionManager) this.getActivity().getSystemService("media_projection")).createScreenCaptureIntent(),REQUEST_MEDIA_PROJECTION);}

截取屏幕内容生成BMP

    public Bitmap getScreenShotSync() {if (!isShotterUseful()) {return null;}if (mImageReader == null) {mImageReader = ImageReader.newInstance(getScreenWidth(),getScreenHeight(),PixelFormat.RGBA_8888,//此处必须和下面 buffer处理一致的格式 ,RGB_565在一些机器上出现兼容问题。1);}VirtualDisplay tmpDisplay = virtualDisplay();try{Thread.sleep(50);                   //需要稍微停一下,否则截图为空}catch (InterruptedException e){e.printStackTrace();}Image img = mImageReader.acquireLatestImage();if (img == null) {return null;}int width = img.getWidth();int height = img.getHeight();final Image.Plane[] planes = img.getPlanes();final ByteBuffer buffer = planes[0].getBuffer();//每个像素的间距int pixelStride = planes[0].getPixelStride();//总的间距int rowStride = planes[0].getRowStride();int rowPadding = rowStride - pixelStride * width;Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height,Bitmap.Config.ARGB_8888);//虽然这个色彩比较费内存但是 兼容性更好bitmap.copyPixelsFromBuffer(buffer);bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);img.close();//mImageReader.close();tmpDisplay.release();return bitmap;}@TargetApi(Build.VERSION_CODES.LOLLIPOP)private VirtualDisplay virtualDisplay() {return mMediaProjection.createVirtualDisplay("screen-mirror",getScreenWidth(),getScreenHeight(),Resources.getSystem().getDisplayMetrics().densityDpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mImageReader.getSurface(), null, null);}

出于对效率的考虑Bitmap一直都是在内存中操作的,并不需要输出成文件
MediaProjection的详细介绍可参考:Android 5.0及以上实现屏幕截图

  • 微信聊天列表新消息的定位

如图:
从上图我们可以看到,新消息是包含一个现实未读消息数的TextView,我们可以以此来判断未读消息。消息内容则是View所以我们在AccessibilityService中无法获取其内容,但是我们可以定位到未读消息内容在屏幕中的位置。

  • OpenCv特征点匹配

关于OpenCv特征点匹配的方法有很多,有兴趣的读者可以参考这篇文章OpenCv他特征点匹配方法汇总。我使用的是ORB算法。这个算法的特点是速度快,但是在准确率和抗噪点能力上会有所欠缺。
Android接入OpenCv有三种方法:接入OpenCv的Java SDK包、封装JNI、编译OpenCv源码。其中最简单的是直接接入OpenCv的Java SDK包。下载地址
关键代码如下:

/*** 检测输入的图像是否匹配[微信红包]的本地图像** @param bmInput        输入的图像* @param isNormalScreen 对全面屏手机截取的区域不同,特征点也会不同* @return*/public boolean isPictureMatchLuckyMoney(Bitmap bmInput, boolean isNormalScreen) throws CvException {if (!isCachePictureExist()) {return false;}if (bmLocal == null) {bmLocal = BitmapFactory.decodeFile(strMoneyPicPath);}Mat inputGrayMat = getGrayMat(bmInput);Mat localGrayMat = getGrayMat(bmLocal);//特征点提取ORB orb = ORB.create(1000);                           //精度越小越准确MatOfKeyPoint kptsInput = new MatOfKeyPoint();MatOfKeyPoint kptsLocal = new MatOfKeyPoint();orb.detect(inputGrayMat, kptsInput);orb.detect(localGrayMat, kptsLocal);//特征点描述,采用ORB默认的描述算法Mat descInput = new Mat();Mat descLocal = new Mat();orb.compute(inputGrayMat, kptsInput, descInput);orb.compute(localGrayMat, kptsLocal, descLocal);//BFMatcher matcher = new BFMatcher(BFMatcher.BRUTEFORCE_HAMMING, false);DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);MatOfDMatch matchPoints = new MatOfDMatch();//Log.e("matchoutput", "--start---");//matcher.knnMatch(descInput,descLocal,matchPointsList,2);try {matcher.match(descInput, descLocal, matchPoints);} catch (CvException ex) {Log.e("matchoutput", ex.toString());return false;}//Log.e("matchoutput", "--end---");float min_dist = 0;DMatch[] arrays = matchPoints.toArray();for (int i = 0; i < descInput.rows(); ++i) {float dist = arrays[i].distance;if (dist < min_dist) min_dist = dist;}int goodMatchPointNum = 0;//筛选特征点float compareNum = Math.max(min_dist * 2, 30.0f);for (int j = 0; j < descInput.rows(); j++) {if (arrays[j].distance <= compareNum) {goodMatchPointNum++;}}Log.e("matchoutput", goodMatchPointNum + "");if (isNormalScreen) {return goodMatchPointNum > 10;} else {return goodMatchPointNum >= 7;}}

由于微信的字体是与系统字体有关。所以我在每次软件启动时在本地绘制一张 [微信红包] 的图片用于做特征点比对。当截图的特征点匹配的数目大于一定数量的时候就认为这个图片中的文字可能就是 [微信红包]
这里不采用ORC文字识别的原因是文字识别速度太慢了,采用这种方法的话会快好多。
而且随着微信版本的改动,想单纯通过AccessibilityService会原来越难,所以在以后的版本中可能需要用类似的方法去识别微信红包了

抢红包服务核心实现代码

  • 区分AccessibilityEvent消息类型

    @Overridepublic void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {//Log.e(TAG, "event recv");Log.e(TAG, "class:" + accessibilityEvent.getClassName().toString());if (!mGlobalMutex) {mGlobalMutex = true;setCurrentActivityName(accessibilityEvent);switch (accessibilityEvent.getEventType()) {case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:handleNotificationMessage(accessibilityEvent);break;case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:handleScreenMessage(accessibilityEvent);break;default:break;}mGlobalMutex = false;}}

TYPE_NOTIFICATION_STATE_CHANGED为状态栏通知

  • 根据ActivityName区分当前状态

获取当前ActivityName

    private void setCurrentActivityName(AccessibilityEvent event) {String activitiesName = event.getClassName().toString();currentNodeInfoName = activitiesName;if (activitiesName.startsWith("com.tencent.mm")) {//prevActivityName = currentActivityName;currentActivityName = activitiesName;Log.e(TAG, "current_name:" + event.getClassName().toString());}}
    private static final String CHATTING_LAUNCHER_UI = "com.tencent.mm.ui.LauncherUI";private static final String LUCKY_MONEY_RECV_UI = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI";private static final String LUCKY_MONEY_DETAIL_UI = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI";

CHATTING_LAUNCHER_UI 聊天列表页面或聊天页面
LUCKY_MONEY_RECV_UI 拆红包页面或红包过期页面
LUCKY_MONEY_DETAIL_UI 红包详情页面

  • 根据当前状态决策处理的方法

聊天列表页面或聊天页面

区分当前实在聊天列表还是在聊天页面,如果在聊天列表则查找是否有未读消息如果在聊天页面则通过findAccessibilityNodeInfosByText查找红包。
判断方法:

    /*** 检查是否在聊天列表** @return boolean*/private boolean isInChartList() {boolean b = false;AccessibilityNodeInfo root = getRootInActiveWindow();if (root != null) {if (root.getChildCount() > 0) {b = root.getChild(0).getChildCount() > 1;} else {b = false;}}return b;}

在聊天列表:判断是否有未读消息-截屏-截取未读消息区域-查找是否有红包来了

    /*** 查找未读消息区域,如果没有则返回空列表* @return*/private List<Rect> findNewsRectInScreen() {AccessibilityNodeInfo nodeInfo = findNodeInfoByClass(getRootInActiveWindow(), LIST_VIEW_NAME);List<Rect> resultList = new ArrayList<>();if (nodeInfo != null) {int chartCount = nodeInfo.getChildCount();for (int i = 0; i < chartCount; i++) {AccessibilityNodeInfo subChartInfo = nodeInfo.getChild(i);if (subChartInfo != null) {if (subChartInfo.getChildCount() > 0) {                                             //表示是未读消息,有可能有红包Rect outputRect = new Rect();subChartInfo.getBoundsInScreen(outputRect);if (!isNormalScreen) {outputRect.top -= 30;outputRect.bottom -= 30;}if (outputRect.height() == 0 || outputRect.width() == 0) {continue;}outputRect.left += (int) (outputRect.width() * 0.2);                                 //去除头像区域outputRect.top += (int) (outputRect.height() * 0.3);resultList.add(outputRect);}}}}return resultList;}

在聊天页面:查找包含[领取红包]的子节点-点击该节点-进入拆红包阶段

由于[领取红包]关键字是个TextView,所以可以通过findAccessibilityNodeInfosByText查找到该子节点,具体代码如下:

    private void findRedpockeyAndClick(AccessibilityEvent ev) {AccessibilityNodeInfo rootInfo = getRootInActiveWindow();//检查领取红包和查看红包List<AccessibilityNodeInfo> redPackeyInfoLst = null;if (mSharedPreferences.getBoolean("pref_watch_self", false)) {redPackeyInfoLst = getPacketNode(rootInfo, WECHAT_VIEW_OTHERS_CH, WECHAT_VIEW_SELF_CH);} else {redPackeyInfoLst = getPacketNode(rootInfo, WECHAT_VIEW_OTHERS_CH);}if (redPackeyInfoLst != null && !redPackeyInfoLst.isEmpty()) {//redPackeyInfo.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK);String str_filter = mSharedPreferences.getString("pref_watch_exclude_words", "");AccessibilityNodeInfo openPackeyInfo = null;if (str_filter.equals("")) {openPackeyInfo = redPackeyInfoLst.get(redPackeyInfoLst.size() - 1);} else {String[] str_fiilter_array = str_filter.split(" +");for (int k = redPackeyInfoLst.size() - 1; k >= 0; k--) {AccessibilityNodeInfo tmpInfo = redPackeyInfoLst.get(k);if (tmpInfo.getParent().getChildCount() <= 0) {continue;}String strPackeyMsg = tmpInfo.getParent().getChild(0).getText().toString();boolean b = false;for (String filter_text : str_fiilter_array) {if ((filter_text.length() > 0) &&strPackeyMsg.contains(filter_text)) {b = true;break;}}if (!b) {openPackeyInfo = tmpInfo;break;}}}if (openPackeyInfo != null) {AccessibilityNodeInfo parentInfo = openPackeyInfo.getParent();if (parentInfo != null) {parentInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);}}Log.e(TAG, "pockey find!");}}

这里还做了关键字过滤的处理,如果包含某些关键字则不打开该红包。做到专属红包不抢

拆红包页面或红包过期页面

拆红包代码

    private void openPacket() {DisplayMetrics metrics = getResources().getDisplayMetrics();float dpi = metrics.densityDpi;Log.e(TAG, "openPacket!" + dpi);if (android.os.Build.VERSION.SDK_INT <= 23) {//nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);Toast.makeText(MyApplication.getContext(), getString(R.string.not_support_low_level), Toast.LENGTH_SHORT).show();} else {if (android.os.Build.VERSION.SDK_INT > 23) {if (!mPockeyOpenMutex) {mPockeyOpenMutex = true;Path path = new Path();if (640 == dpi) { //1440path.moveTo(720, 1575);} else if (320 == dpi) {//720ppath.moveTo(355, 780);} else if (480 == dpi) {//1080ppath.moveTo(533, 1115);} else if (440 == dpi) {//1080*2160path.moveTo(450, 1250);}GestureDescription.Builder builder = new GestureDescription.Builder();try {GestureDescription gestureDescription = builder.addStroke(new GestureDescription.StrokeDescription(path, 450, 50)).build();dispatchGesture(gestureDescription, new GestureResultCallback() {@Overridepublic void onCompleted(GestureDescription gestureDescription) {Log.e(TAG, "onCompleted");mPockeyOpenMutex = false;super.onCompleted(gestureDescription);}@Overridepublic void onCancelled(GestureDescription gestureDescription) {Log.e(TAG, "onCancelled");mPockeyOpenMutex = false;super.onCancelled(gestureDescription);}}, null);} catch (Exception e) {e.printStackTrace();}}}}}

这里做了一个延时自动关闭的操作,因为如果红包过期了是不会进入红包详情页面的。所以这里如果过了一定时间还没有进入红包详情页面则认为这是过期红包。自动关闭
在微信6.6.1及之前的版本是可以遍历窗口节点,查找类名为android.vew.button的方法来查找到按钮的。再通过performAction点击该节点打开红包,这里就不贴出代码了。

红包详情页面

调用performGlobalAction(GLOBAL_ACTION_BACK)返回

写在最后

这是一个根据前人的版本结合自己的一些想法创造的版本。可能不一定是最优解,但是目前可以支持到微信7.0.0版本。如果哪位大神有更好的方法还望不吝赐教。
项目源码下载
安装包下载

AccessibilityService+OpenCV实现微信7.0.0抢红包插件相关推荐

  1. 最新微信8.0.1抢红包神器-亲测2021年2月11日可用-安卓IOS

    最新微信8.0.1抢红包神器-亲测2021年2月11日可用-安卓&IOS 文章目录 概述 效果图 使用指南 获取方式 概述 今晚就过年了,相信很多朋友在微信群能收到很多红包,但是过年可能吃的更 ...

  2. cv2.error: OpenCV(4.0.0): dst.data == (uchar*)dst_ptr in function 'cvShowImage'

    cv2.error: OpenCV(4.0.0): dst.data == (uchar*)dst_ptr in function 'cvShowImage' 文章目录: 一.错误 二.错误解决方式 ...

  3. ubuntu 16.0.4 opencv 4.0.0 + opencv_contrib 4.0.0 cmake-gui 安装

    下载和添加依赖包 1.首先更新 apt-get,在安装前最好先更新一下系统,不然有可能会安装失败.在终端输入: sudo apt-get update sudo apt-get upgrade 2.接 ...

  4. 微信企业号OAuth2.0授权-Java

    为什么80%的码农都做不了架构师?>>>    我也是醉了,中午做个饭这么难吃!连自己都看不下去了!怀着沉重的心情把微信企业号OAuth2.0授权看了看,感觉与公众号差别没什么,相信 ...

  5. 怎样查看电脑系统版本_微信7.0.0自动更新后怎样去还原以前的旧版本?

    今天"微信自动更新"上热搜了,不少安卓手机用户表示:今天早上打开微信,界面一片白,吓一跳,以为点错了.最后发现原来是自动更新到了7.0.0版本,但是真的,不习惯,还是喜欢以前那个老 ...

  6. 产品经理们眼中的微信7.0.0

    问题补充:微信7.0.0更新了,这一版整体改动非常大,4年时间从6.x.x到7.0.0,功能上改动最大的是看一看,视频,以及单聊强提醒设置,对于这次微信大改版,你怎么看? iamxiarui www. ...

  7. VS2013安装oepncv2.4.10 以及opencv 3.0.0

    Author:Maddock Date:2014.12.27 -------------------------------------- PS: VS2013 + OPENCV 3.0.0 的安装, ...

  8. Ubuntu14.04系统下安装配置OpenCV 4.0.0开发环境全过程

    最近研究一个项目时需要用到OpenCV,于是自己尝试在Ubuntu 14.04系统下安装了这个开发环境.下面就将具体的过程记录一下,便于后期查阅和同行分享. 〇.开发环境 首先介绍一下我的开发环境: ...

  9. highgui java opencv_java – OpenCV 3.0.0 JAR缺少HighGUI

    我正在使用Java支持来编译OpenCV 3.0.0.我的脚本是: mkdir /opt/opencv /opt/opencv/opencv-build cd /opt/opencv git clon ...

  10. 程序左上角的字_微信内测7.0.7新版本,小程序迎来大改动!

    最近几个月来,微信就跟打了鸡血一样不断更新了多个版本上线多个新功能.此前7月末,微信安卓7.0.6带来了将收藏笔记,文件预览等页面设为浮窗的功能,目前最多支持5个文档或笔记设为浮窗.这不,距离微信7. ...

最新文章

  1. Wp7下的Timer DispatcherTimer使用
  2. 微信小程序之配置app.json
  3. AJAX应注意IIS有没有.ashx扩展
  4. jetson nano包安装
  5. action 带参数跳转
  6. 工具条内控件背景色设置
  7. 粗读《构建之法》后的思考和收获
  8. Java中Lambda表达式与方法引用和构造器引用
  9. vector 的删除
  10. 知识越分享,收获越多。
  11. WPF 播放Flash
  12. HDFView 把 JPG 图片转换成 HDF5 格式文件
  13. 计算机是如何计算 log 函数的?
  14. matlab 画标准正态曲线,matlab中如何画标准正态分布的密度函数曲线?
  15. 手机wps取消不等宽分栏_wps取消分栏怎么设置
  16. 《HarmonyOS开发 – OpenHarmony开发笔记(基于小型系统)》第1章 OpenHarmony与Pegasus物联网开发套件简介
  17. Radio Userland已更新,版本号未更改...
  18. Python学习 - 列表
  19. 搞笑--为毛我顶多是个包工头
  20. 【Kong】网关-rate-limiting限流

热门文章

  1. SQL——正则表达式
  2. python批量修改图片格式、重命名
  3. 项目中常用字典表 —— 各个国家简称映射
  4. 小学生计算机基础知识课件,计算机基础知识课件(图表部份).ppt
  5. 格兰因果模型可以分析哪些东西_计量 | 使用向量自回归模型(VAR)的操作要点,必备!...
  6. hibernate二级缓存(二)二级缓存实现原理简单剖析
  7. 卡巴斯基提供升级包 解决病毒库升级
  8. Linux系统配置jdk环境变量
  9. 《计算机操作系统(慕课版)》(汤小丹著)课后习题答案
  10. 使用软件测试工具WinRunner的几点建议