一步一步学OAK之七:通过OAK相机实现特征跟踪

news2024/11/22 16:24:55

目录

  • 特征跟踪
  • Setup 1: 创建文件
  • Setup 2: 安装依赖
  • Setup 3: 导入需要的包
  • Setup 4: 定义FeatureTrackerDrawer类
    • 定义变量
    • 定义onTrackBar方法
    • 定义trackFeaturePath方法
    • 定义drawFeatures方法
    • 定义`FeatureTrackerDrawer`类的构造函数
  • Setup 5: 创建pipeline
  • Setup 6: 创建节点
    • 创建相机节点
    • 创建特征检测节点
    • 创建数据交互节点
  • Setup 7:设置相关属性
  • Setup 8: 建立链接关系
  • Setup 9: 为跟踪器对象设置硬件资源
  • Setup 10: 连接设备并启动管道
  • Setup 11: 创建与DepthAI设备通信的输入队列和输出队列
  • Setup 12: 主循环
    • 从队列中获取输入的图像帧。
    • 从队列中获取跟踪的特征
    • 显示帧图像
  • Setup 13:运行程序

特征跟踪

特征跟踪,也称为目标跟踪或点跟踪,是指在序列图像中追踪物体或者场景中的特定特征点的过程。特征点可以是具有独特性质的像素,如角点、边缘、纹理等。通过跟踪这些特征点,可以在连续图像帧中确定它们的位置、速度和运动轨迹。

在计算机视觉和图像处理中,特征点是图像中具有显著性质或者信息的位置。对图像序列进行特征点的跟踪可以用于很多应用,例如目标追踪、运动估计、相机姿态估计、结构重建等。

特征点的选择通常取决于应用的需求和图像中的内容,常用的特征点检测算法包括Harris角点检测、Shi-Thomasi角点检测、SIFT(尺度不变特征变换)等。特征点跟踪的算法有很多,例如光流法、角点追踪等,它们可以根据特征点在前后帧之间的移动来判断物体或场景的运动。

DepthAI给我们提供了特征跟踪(Feature Tracker)功能模块,它用于在连续的图像帧中追踪和识别特定的特征点。Depthai 通过使用硬件加速和可编程的算法,实现了实时的特征跟踪功能。

DepthAI 的特征跟踪功能通常用于目标追踪和运动估计应用。它可以识别并跟踪视频中的关键点、边缘、角点或其他具有显著性质的图像特征。这些特征点的位置和运动轨迹可以用于估计物体的运动,在许多应用中非常有用,比如机器人导航、增强现实、虚拟现实等。

另外,DepthAI 给我们提供了编程接口,使开发人员能够配置和使用特征跟踪功能。通过适当的配置参数和算法选择,可以优化特征跟踪的性能和准确性,以满足应用的需求。
下面我们来实现一个OAK相机特征跟踪的代码

Setup 1: 创建文件

  • 创建新建7-feature-tracker文件夹
  • 用vscode打开该文件夹
  • 新建一个main.py 文件

Setup 2: 安装依赖

安装依赖前需要先创建和激活虚拟环境,我这里已经创建了虚拟环境OAKenv,在终端中输入cd…退回到OAKenv的根目录,输入 OAKenv\Scripts\activate激活虚拟环境

安装pip依赖项:

pip install numpy opencv-python depthai blobconverter --user

Setup 3: 导入需要的包

在main.py中导入项目需要的包

import cv2
import depthai as dai
from collections import deque

这里从 Python 的 collections 模块中导入 deque 类,deque 类提供了各种方法来操作队列,如 append()appendleft()pop()popleft(),以及像列表一样的索引访问。当需要高效地从队列的两端添加或删除元素时,deque 尤为有用。

Setup 4: 定义FeatureTrackerDrawer类

定义一个名为 FeatureTrackerDrawer 的类,用于绘制特征追踪器的路径。

class FeatureTrackerDrawer:

定义变量

    lineColor = (200, 0, 200)
    pointColor = (0, 0, 255)
    circleRadius = 2
    maxTrackedFeaturesPathLength = 30 
    trackedFeaturesPathLength = 10

    trackedIDs = None
    trackedFeaturesPath = None
  • lineColor:追踪路径的线条颜色。
  • pointColor:特征点的颜色。
  • circleRadius:绘制特征点的圆的半径。
  • maxTrackedFeaturesPathLength:追踪路径的最大长度。
  • trackedFeaturesPathLength:追踪路径的当前长度。
  • trackedIDs:当前追踪的特征点的 ID 集合。
  • trackedFeaturesPath:特征点的追踪路径。

定义onTrackBar方法

    def onTrackBar(self, val):
        FeatureTrackerDrawer.trackedFeaturesPathLength = val
        pass

这个 onTrackBar 方法接收一个参数 val,该参数表示滑动条的当前值。

在这个方法中,它将传入的 val 值赋给 FeatureTrackerDrawer.trackedFeaturesPathLength,以更新追踪路径的长度。这样,当滑块的值改变时,追踪路径的长度也会相应地改变。

pass 语句表示该方法暂时不执行任何具体的操作,仅作为占位符存在。

定义trackFeaturePath方法

trackFeaturePath方法用于追踪特征点的路径,并更新追踪路径记录。

    def trackFeaturePath(self, features):

        newTrackedIDs = set()
        for currentFeature in features:
            currentID = currentFeature.id
            newTrackedIDs.add(currentID)

            if currentID not in self.trackedFeaturesPath:
                self.trackedFeaturesPath[currentID] = deque()

            path = self.trackedFeaturesPath[currentID]

            path.append(currentFeature.position)
            while(len(path) > max(1, FeatureTrackerDrawer.trackedFeaturesPathLength)):
                path.popleft()

            self.trackedFeaturesPath[currentID] = path

        featuresToRemove = set()
        for oldId in self.trackedIDs:
            if oldId not in newTrackedIDs:
                featuresToRemove.add(oldId)

        for id in featuresToRemove:
            self.trackedFeaturesPath.pop(id)

        self.trackedIDs = newTrackedIDs

该方法接受一个名为 features 的参数,表示当前帧中的特征点列表。

  • 使用newTrackedIDs = set()创建一个空的集合 newTrackedIDs 用于存储新追踪的特征点的 ID

  • 使用 for 循环遍历 features 中的每个特征点 currentFeature

    在循环中,首先获取当前特征点的 ID,并将其添加到 newTrackedIDs 集合中。

    检查当前特征点的 ID 是否已经存在于 trackedFeaturesPath 字典中。如果不存在,就使用deque()方法在字典中创建一个空的双向队列 path 来存储该特征点的路径。

    将当前特征点的位置 (currentFeature.position) 添加到 path 队列的末尾。

    使用 while 循环,确保 path 的长度不超过当前设置的最大追踪路径长度 (max(1, FeatureTrackerDrawer.trackedFeaturesPathLength))。如果超过了,则从队列的前端删除元素。

    将更新后的 path 队列赋值给 trackedFeaturesPath 字典中对应的特征点 ID。

  • 创建一个空的集合 featuresToRemove 用于存储需要移除的特征点的 ID。

  • 使用 for 循环遍历 trackedIDs 中的每个旧的特征点 ID。如果该 ID 不在 newTrackedIDs 集合中,表示该特征点不再存在于当前帧的特征点列表中,将其 ID 添加到 featuresToRemove 集合中。

  • 使用 for 循环遍历 featuresToRemove 集合中的每个特征点 ID,并从 trackedFeaturesPath 字典中移除对应的特征点路径。

  • newTrackedIDs 集合赋值给 trackedIDs,更新已追踪的特征点的 ID。

定义drawFeatures方法

定义drawFeatures方法,绘制特征点的路径和特征点本身。通过这个方法,可以在图像上绘制特征点的路径,并将特征点的位置设置为当前的追踪路径长度。

    def drawFeatures(self, img):

        cv2.setTrackbarPos(self.trackbarName, self.windowName, FeatureTrackerDrawer.trackedFeaturesPathLength)

        for featurePath in self.trackedFeaturesPath.values():
            path = featurePath

            for j in range(len(path) - 1):
                src = (int(path[j].x), int(path[j].y))
                dst = (int(path[j + 1].x), int(path[j + 1].y))
                cv2.line(img, src, dst, self.lineColor, 1, cv2.LINE_AA, 0)
            j = len(path) - 1
            cv2.circle(img, (int(path[j].x), int(path[j].y)), self.circleRadius, self.pointColor, -1, cv2.LINE_AA, 0)

drawFeatures 方法用于在图像上绘制特征点的路径。方法接收一个名为 img 的参数,表示要绘制特征点路径的图像。

  • 使用 cv2.setTrackbarPos 方法设置特征点的位置,以保持特征点的值与 FeatureTrackerDrawer.trackedFeaturesPathLength 相同。

  • 使用 for 循环遍历 trackedFeaturesPath 字典中的每个特征点路径。

    在循环中,首先获取当前特征点路径 featurePath

    然后,使用 for 循环遍历路径 path 中的每个点的索引。

    在循环中,获取当前点 path[j] 和下一个点 path[j+1] 的坐标,并将其转换为整数类型。

    调用 cv2.line 方法,在图像上绘制从当前点到下一个点的线段,线段的颜色为 self.lineColor,宽度为 1,线段的类型为 cv2.LINE_AA,线段的连接方式为 0。

    然后,将索引值 j 更新为路径 path 中的最后一个点的索引。

    接着,使用 cv2.circle 方法,在图像上绘制路径 path 中最后一个点的圆形标记,圆心坐标为路径最后一个点的坐标 (int(path[j].x), int(path[j].y)),圆的半径为 self.circleRadius,圆的颜色为 self.pointColor,圆的类型为 cv2.LINE_AA

定义FeatureTrackerDrawer类的构造函数

定义FeatureTrackerDrawer类的构造函数 __init__() ,它初始化了类的一些属性,该方法接受两个参数trackbarNamewindowName,分别代表跟踪点的名称和窗口的名称。

    def __init__(self, trackbarName, windowName):
        self.trackbarName = trackbarName
        self.windowName = windowName
        cv2.namedWindow(windowName)
        cv2.createTrackbar(trackbarName, windowName, FeatureTrackerDrawer.trackedFeaturesPathLength, FeatureTrackerDrawer.maxTrackedFeaturesPathLength, self.onTrackBar)
        self.trackedIDs = set()
        self.trackedFeaturesPath = dict()
  • trackbarNamewindowName赋值给self.trackbarNameself.windowName属性。

  • 使用cv2.namedWindow方法创建一个窗口,并将windowName作为窗口的名称。

  • 使用cv2.createTrackbar方法cv2.createTrackbar函数用于在GUI窗口中创建一个滚动条,并为其设置回调函数。滚动条的名称为trackbarName,所在的窗口为windowName。滚动条的初始值设置为FeatureTrackerDrawer.trackedFeaturesPathLength,最大值设置为FeatureTrackerDrawer.maxTrackedFeaturesPathLength。在滚动条位置发生变化时,会调用self.onTrackBar方法。

  • 将空集合赋值给self.trackedIDs属性,并将空字典赋值给self.trackedFeaturesPath属性。

通过这个构造函数,我们可以创建一个FeatureTrackerDrawer对象,并初始化相关的变量和属性。

Setup 5: 创建pipeline

pipeline = dai.Pipeline()

Setup 6: 创建节点

创建相机节点

monoLeft = pipeline.createMonoCamera()
monoRight = pipeline.createMonoCamera()

创建特征检测节点

featureTrackerLeft = pipeline.createFeatureTracker()
featureTrackerRight = pipeline.createFeatureTracker()

创建数据交互节点

xoutPassthroughFrameLeft = pipeline.createXLinkOut()
xoutTrackedFeaturesLeft = pipeline.createXLinkOut()
xoutPassthroughFrameRight = pipeline.createXLinkOut()
xoutTrackedFeaturesRight = pipeline.createXLinkOut()
xinTrackedFeaturesConfig = pipeline.createXLinkIn()

xoutPassthroughFrameLeft.setStreamName("passthroughFrameLeft")
xoutTrackedFeaturesLeft.setStreamName("trackedFeaturesLeft")
xoutPassthroughFrameRight.setStreamName("passthroughFrameRight")
xoutTrackedFeaturesRight.setStreamName("trackedFeaturesRight")
xinTrackedFeaturesConfig.setStreamName("trackedFeaturesConfig")

Setup 7:设置相关属性

设置相机的分辨率和板载插槽

monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P)
monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P)
monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)

Setup 8: 建立链接关系

建立相机和特征跟踪器之间的数据连接

monoLeft.out.link(featureTrackerLeft.inputImage)
featureTrackerLeft.passthroughInputImage.link(xoutPassthroughFrameLeft.input)
featureTrackerLeft.outputFeatures.link(xoutTrackedFeaturesLeft.input)
xinTrackedFeaturesConfig.out.link(featureTrackerLeft.inputConfig)

monoRight.out.link(featureTrackerRight.inputImage)
featureTrackerRight.passthroughInputImage.link(xoutPassthroughFrameRight.input)
featureTrackerRight.outputFeatures.link(xoutTrackedFeaturesRight.input)
xinTrackedFeaturesConfig.out.link(featureTrackerRight.inputConfig)

Setup 9: 为跟踪器对象设置硬件资源

setHardwareResources函数为跟踪器设置硬件资源。

numShaves = 2
numMemorySlices = 2
featureTrackerLeft.setHardwareResources(numShaves, numMemorySlices)
featureTrackerRight.setHardwareResources(numShaves, numMemorySlices)

featureTrackerConfig = featureTrackerRight.initialConfig.get()
print("Press 's' to switch between Lucas-Kanade optical flow and hardware accelerated motion estimation!")

使用setHardwareResources函数为两个跟踪器对象featureTrackerLeft和featureTrackerRight设置硬件资源。

numShaves(Myriad X硬件加速器的shave数量)和numMemorySlices(内存切片的数量)是两个参数,用于指定可用的硬件资源数量。

通过featureTrackerRight的initialConfig属性获取了其初始配置,并将其存储在featureTrackerConfig变量中。

Setup 10: 连接设备并启动管道

with dai.Device(pipeline) as device:

Setup 11: 创建与DepthAI设备通信的输入队列和输出队列

    passthroughImageLeftQueue = device.getOutputQueue("passthroughFrameLeft", 8, False)
    outputFeaturesLeftQueue = device.getOutputQueue("trackedFeaturesLeft", 8, False)
    passthroughImageRightQueue = device.getOutputQueue("passthroughFrameRight", 8, False)
    outputFeaturesRightQueue = device.getOutputQueue("trackedFeaturesRight", 8, False)

    inputFeatureTrackerConfigQueue = device.getInputQueue("trackedFeaturesConfig")

使用FeatureTrackerDrawer类创建两个特征跟踪器的绘图对象

    leftWindowName = "left"
    leftFeatureDrawer = FeatureTrackerDrawer("Feature tracking duration (frames)", leftWindowName)

    rightWindowName = "right"
    rightFeatureDrawer = FeatureTrackerDrawer("Feature tracking duration (frames)", rightWindowName)

使用FeatureTrackerDrawer类创建了两个特征跟踪器的绘图对象,一个用于左侧(leftFeatureDrawer),一个用于右侧(rightFeatureDrawer)。

这些绘图对象用于可视化特征跟踪的持续时间,并且与相应的窗口名称关联起来。

Setup 12: 主循环

    while True:

从队列中获取输入的图像帧。

        inPassthroughFrameLeft = passthroughImageLeftQueue.get()
        passthroughFrameLeft = inPassthroughFrameLeft.getFrame()
        leftFrame = cv2.cvtColor(passthroughFrameLeft, cv2.COLOR_GRAY2BGR)

        inPassthroughFrameRight = passthroughImageRightQueue.get()
        passthroughFrameRight = inPassthroughFrameRight.getFrame()
        rightFrame = cv2.cvtColor(passthroughFrameRight, cv2.COLOR_GRAY2BGR)
  • 分别从名为passthroughImageLeftQueue和passthroughImageRightQueue的队列中获取输入的图像帧。

  • 从inPassthroughFrameLeft和inPassthroughFrameRight中获取帧,并将它们分别存储在passthroughFrameLeft和passthroughFrameRight变量中。

  • 使用cv2.cvtColor函数将passthroughFrameLeft和passthroughFrameRight从灰度图像转换为BGR彩色图像,并分别存储在leftFrame和rightFrame变量中。

从队列中获取跟踪的特征

        trackedFeaturesLeft = outputFeaturesLeftQueue.get().trackedFeatures
        leftFeatureDrawer.trackFeaturePath(trackedFeaturesLeft)
        leftFeatureDrawer.drawFeatures(leftFrame)

        trackedFeaturesRight = outputFeaturesRightQueue.get().trackedFeatures
        rightFeatureDrawer.trackFeaturePath(trackedFeaturesRight)
        rightFeatureDrawer.drawFeatures(rightFrame)

从outputFeaturesLeftQueue队列中获取跟踪的特征,并将其存储在trackedFeaturesLeft变量中。

  • 使用leftFeatureDrawer对象的trackFeaturePath方法跟踪这些特征的路径,并使用drawFeatures方法在leftFrame图像上绘制这些特征。

  • 从outputFeaturesRightQueue队列中获取跟踪的特征,并将其存储在trackedFeaturesRight变量中。

  • 使用rightFeatureDrawer对象的trackFeaturePath方法跟踪这些特征的路径,并使用drawFeatures方法在rightFrame图像上绘制这些特征。

这样,我们就完成了特征跟踪和绘制的步骤,可以在图像上可视化跟踪的特征路径。

显示帧图像

        cv2.imshow(leftWindowName, leftFrame)
        cv2.imshow(rightWindowName, rightFrame)

对键盘输入响应的程序

        key = cv2.waitKey(1)
        if key == ord('q'):
            break
        elif key == ord('s'):
            if featureTrackerConfig.motionEstimator.type == dai.FeatureTrackerConfig.MotionEstimator.Type.LUCAS_KANADE_OPTICAL_FLOW:
                featureTrackerConfig.motionEstimator.type = dai.FeatureTrackerConfig.MotionEstimator.Type.HW_MOTION_ESTIMATION
                print("Switching to hardware accelerated motion estimation")
            else:
                featureTrackerConfig.motionEstimator.type = dai.FeatureTrackerConfig.MotionEstimator.Type.LUCAS_KANADE_OPTICAL_FLOW
                print("Switching to Lucas-Kanade optical flow")

            cfg = dai.FeatureTrackerConfig()
            cfg.set(featureTrackerConfig)
            inputFeatureTrackerConfigQueue.send(cfg)

使用cv2.waitKey函数来等待用户按下键盘上的按键。

  • 如果用户按下键盘上的’q’键,程序将跳出循环,从而退出程序。

  • 如果用户按下键盘上的’s’键,程序将执行以下操作:

  1. 检查featureTrackerConfig.motionEstimator.type的当前值。如果其值是dai.FeatureTrackerConfig.MotionEstimator.Type.LUCAS_KANADE_OPTICAL_FLOW,则会执行以下操作:

    • 将featureTrackerConfig.motionEstimator.type设置为dai.FeatureTrackerConfig.MotionEstimator.Type.HW_MOTION_ESTIMATION,以切换到硬件加速的运动估计。
  2. 如果featureTrackerConfig.motionEstimator.type的当前值不是dai.FeatureTrackerConfig.MotionEstimator.Type.LUCAS_KANADE_OPTICAL_FLOW,则会执行以下操作:

    • 将featureTrackerConfig.motionEstimator.type设置为dai.FeatureTrackerConfig.MotionEstimator.Type.LUCAS_KANADE_OPTICAL_FLOW,以切换到Lucas-Kanade光流。
  3. 创建一个新的dai.FeatureTrackerConfig对象cfg,并将featureTrackerConfig设置为其值。

  4. 使用inputFeatureTrackerConfigQueue队列发送cfg对象。

Setup 13:运行程序

在终端中输入如下指令运行程序

python main.py

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/702423.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Scrapy框架之下载中间件(详解)

目录 Scrapy中下载中间件 概念 方法 process_request(self, request, spider) 参数: process_response(self, request, response, spider) 参数 基本步骤 示例代码 注意 Scrapy 中 Downloader 设置UA 开发UserAgent下载中间件 代码 三方模块 配置模块到Settin…

Redis系列 | 分类树查询功能如何从2s优化到0.1s

大家好,今天我们继续来分享一个在项目开发过程中遇到的实际问题,这里也来梳理并总结一下我们是如何对它进行持续优化的,希望能对大家有所帮助。 分类树查询功能,在各个业务系统中可以说随处可见,特别是在一些电商系统中…

UGUI无线滑动列表

在游戏开发中,经常会遇到需要展示大量数据的情况,例如排行榜、背包等。为了优化显示效果和性能,一个常见的做法是使用无限滑动列表(Infinite Scroll View)。本文将详细解析如何实现无限滑动列表。 基本原理 无限滑动列…

市电电压双向越限报警保护器电路设计

该报警保护器能在市电电压高于或低于规定值时,进行声光报警,同时自动切断电器电源,保护用电器不被损坏。该装置体积小、功能全、制作简单、实用性强。 一、电路工作原理 电路原理如图 3 所示。 市电电压一路由C3降压,DW稳压&am…

驱动开发:应用DeviceIoContro模板精讲

在笔者上一篇文章《驱动开发:应用DeviceIoContro开发模板》简单为大家介绍了如何使用DeviceIoContro模板快速创建一个驱动开发通信案例,但是该案例过于简单也无法独立加载运行,本章将继续延申这个知识点,通过封装一套标准通用模板…

一、枚举类型——新特性(switch 中的箭头语法)

支持模式匹配 你可以认为模式匹配(pattern matching)是在 switch 关键字上进行了显著的功能扩充。 它是分成了多个模块、 历经了 Java 的多个版本持续实现的。这保证了每个模块在其他模块加入前都可以安全地运行。最后,所有的模块集中到一起…

LLM大模型应用开发的本地环境搭建

尽管 ChatGPT 仍然很受欢迎,但泄露的 Google 内部文件表明开源社区正在迎头赶上并取得重大突破。 我们现在能够在消费级 GPU 上运行大型 LLM 模型。 因此,如果你是一名开发人员,想要在本地环境中尝试这些 LLM 并用它构建一些应用程序&#x…

Kubernetes进阶实战2

Kubernetes具有以下几个重要特性 简言之,Kubernetes整合并抽象了底层的硬件和系统环境等基础设施,对外提供了一个统一的资源池供终端用户通过API进行调用。 Kubernetes具有以下几个重要特性。 (1)自动装箱 构建于容器之上&#x…

定时器T0流水灯

89C52RC芯片 12Mhz&#xff1a;FC18 11.0592Mhz &#xff1a;FC67 定时器T0初值计算 12Mhz 11.0592Mhz main.c #include<regx52.h> #include<intrins.h> //_crol_循环左移函数 #include "Timer0.h" #include "Key.h" /*定时器&#xff0c;…

玩转k8s:资源管理

1 资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 kubernetes的本质上就是一个集群系统&#xff0c;用户可以在集群中部署各种服务&#xff0c;所谓的部署服务&#xff0c;其实就是在kubernetes集群中运行…

【C++】哈希表的改造——unordered_map和unordered_set的模拟实现

文章目录 1. unordered系列的容器封装1.1 改造1:模版参数类型的改造1.1.1 HashNode改造1.1.2 HashTable改造 1.2 改造2:迭代器的增加与封装1.2.1 迭代器类的实现1.2.2 迭代器的封装 1.3 改造3:insert的改写封装1.4 析构函数的实现1.5 unordered_map&unordered_set的封装实现…

Range_image 可视化

范围图像与点云的区别 范围图像&#xff08;Range Image&#xff09;和点云&#xff08;Point Cloud&#xff09;是两种常见的表示和处理三维点数据的方式&#xff0c;它们之间有以下区别&#xff1a; 数据结构&#xff1a;点云是一组三维点的集合&#xff0c;每个点包含位置信…

React解决setState异步带来的多次修改合一和修改后立即使用没有变化问题

我们编写这样一段代码 import React from "react" export default class App extends React.Component {constructor(props){super(props);this.state {cont: 0}}componentDidMount() {this.setState({cont: this.state.cont1})}render(){return (<div>{ thi…

Ubuntu下编译VTK

1.先安装QT&#xff0c;不知道不装行不行&#xff0c;我们项目需要。 2.去VTK官网下载VTK源码。 3.解压源码。 4.编译需要用cmake-gui&#xff0c;装QT的一般都有&#xff0c;但需要把路径添加到PATH才能用。 5.打开cmake-gui&#xff0c;设置源码路径&#xff0c;编译输出路…

项目——学生信息管理系统6

目录 权限的处理 在 MainFrm中定义 一个 权限判断的方法 在 MainFrm 的构造方法中调用一下 测试用学生身份登录 测试用教师身份登录 接下来&#xff0c;我们到学生列表页面里面 ManageStudentFrm&#xff0c;继续权限的设置&#xff0c;学生只能查看自己的信息&#xff0c…

神坑:ElasticSearch8集群启动报错“Device or resource busy”(Docker方式)

昨天在Docker中配置ElasticSearcch8集群模式时&#xff0c;先初步配置了master主节点。然后主节点启动就报错&#xff0c;看日志&#xff0c;提示“Device or resource busy”。异常第一句大概这个样子&#xff1a; Exception in thread "main" java.nio.file.FileS…

WMS 窗口属性

WMS 窗口属性 1、窗口类型与层级1.1 Application Window普通应用程序窗口1.2 Sub Window子窗口1.3 System Window系统窗口 2、层级值与窗口类型2.1 WindowState2.2 WindowManagerPolicy 窗口管理的策略机制2.3 WindowToken句柄 3、窗口属性 LayoutParams Activity的预览窗口Sta…

基于51单片机的秒表系统

目录 基于51单片机的秒表系统一、原理图二、部分代码三、视频演示 基于51单片机的秒表系统 一、原理图 二、部分代码 #include <reg52.h>#define duanxuan P2 #define weixuan P1unsigned char code wxcode[]{0X01, 0x02, 0x04, 0x08, 0X10, 0X20, 0X40, 0X80};…

C# WPF 路径动画

路径动画&#xff1a;一个东西沿着你画的的线跑。 微软对这个有很详细的说明&#xff0c;有需要请参照微软Learn网站 cs的代码 PathGeometry pathGeometry new PathGeometry();PathFigure pathFigure new PathFigure();//pathFigure.IsClosed true;pathFigure.StartPoint…