OpenCV-PyQT项目实战(8)项目案例03:鼠标定位

news2024/9/20 14:44:52

欢迎关注『OpenCV-PyQT项目实战 @ Youcans』系列,持续更新中
OpenCV-PyQT项目实战(1)安装与环境配置
OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门
OpenCV-PyQT项目实战(3)信号与槽机制
OpenCV-PyQT项目实战(4)OpenCV 与PyQt的图像转换
OpenCV-PyQT项目实战(5)项目案例01:图像模糊
OpenCV-PyQT项目实战(6)项目案例02:滚动条应用
OpenCV-PyQT项目实战(7)项目案例03:鼠标框选
OpenCV-PyQT项目实战(8)项目案例04:鼠标定位

文章目录

  • OpenCV-PyQT项目实战(8)项目案例03:鼠标定位
    • 1. OpenCV 中实现鼠标点击定位
    • 2. PyQt实现鼠标点击定位
      • 2.1 支持鼠标事件的自定义 Label 类
      • 2.2 例程7-2:支持鼠标事件的自定义 MyLabel 类
    • 3. 项目实战:PyQt 鼠标点击定位
      • 3.1 使用 QtDesigner 开发 PyQt5 图形界面
      • 3.2. 项目主程序的开发
        • 3.2.1 实例化 MyLabel 类
        • 3.2.2 图像旋转槽函数
        • 3.2.3 信号与槽的连接
      • 3.3 完整例程 OpenCVPyqt09.py

OpenCV-PyQT项目实战(8)项目案例03:鼠标定位


本节介绍OpenCV和PyQt 实现鼠标定位的方法和案例。通过 PyQt 创建交互界面,使用鼠标事件在图像窗口点击定位,并将鼠标定位坐标返回到 OpenCV 进行图像处理。


1. OpenCV 中实现鼠标点击定位

函数cv.setMouseCallback用于设置回调函数,将回调函数与指定窗口绑定。

函数原型:

cv. setMouseCallback (windowName, onMouse[, param]) → retval

函数cv.setMouseCallback设置回调函数,将鼠标事件响应函数onMouse与指定窗口windowName进行绑定。回调函数在鼠标事件发生时自动执行。

参数说明:

● windowName:图像显示窗口的名称

● onMouse:回调函数的函数名,鼠标事件的响应函数

● param:传递到回调函数的参数,可选项

回调函数的格式:

def onMouse (event, x, y, flags, param)

● x, y:事件发生时鼠标在图像坐标系的坐标

● param:传递到setMouseCallback函数调用的参数,可选项

● event:鼠标事件的类型

- cv.EVENT_MOUSEMOVE:鼠标移动

- cv.EVENT_LBUTTONDOWN:点击鼠标左键

- cv.EVENT_RBUTTONDOWN:点击鼠标右键

- cv.EVENT_MBUTTONDOWN:点击鼠标中键

- cv.EVENT_LBUTTONUP:释放鼠标左键

- cv.EVENT_RBUTTONUP:释放鼠标右键

- cv.EVENT_MBUTTONUP:释放鼠标中键

- cv.EVENT_LBUTTONDBLCLK:双击鼠标左键

- cv.EVENT_RBUTTONDBLCLK:双击鼠标右键

- cv.EVENT_MBUTTONDBLCLK:双击鼠标中键

● flags:查看某种按键动作是否发生

- cv.EVENT_FLAG_LBUTTON:鼠标左键拖曳

- cv.EVENT_FLAG_RBUTTON:鼠标右键拖曳

- cv.EVENT_FLAG_MBUTTON:鼠标中键拖曳

- cv.EVENT_FLAG_CTRLKEY:按下Ctrl键不放

- cv.EVENT_FLAG_SHIFTKEY:按下Shift键不放

- cv.EVENT_FLAG_ALTKEY:按下Alt键不放

注意问题:

⒈回调函数onMouse是一个通过函数指针调用的函数,是指定窗口windowName鼠标事件的响应函数,在鼠标事件发生时执行。

⒉回调函数没有返回值。需要传递变量值时,可以把变量定义为全局变量,或通过参数param进行传递。

⒊回调函数运行后会一直监听鼠标动作,相当于打开一个并行的进程,一直占用系统资源。可以使用destroyWindow函数关闭监听的窗口,回调函数就会结束。


例程8-1:OpenCV 鼠标回调函数获取点击坐标

# cvDemo08.py
# OpenCV 鼠标回调函数获取点击坐标
# Copyright 2023 Youcans, XUPT
# Crated:2023-02-16

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

def onMouseAction(event, x, y, flags, param):  # 鼠标交互 (左键选点右键完成)
    global status
    setpoint = (x, y)
    if event == cv.EVENT_LBUTTONDOWN:  # 鼠标左键点击
        pts.append(setpoint)  # 选中一个多边形顶点
        print("选择顶点 {}:{}".format(len(pts), setpoint))
    elif event == cv.EVENT_MBUTTONDOWN:  # 鼠标中键点击
        pts.pop()  # 取消最近一个顶点
    elif event == cv.EVENT_RBUTTONDOWN:  # 鼠标右键点击
        status = False  # 结束绘图状态
        print("结束绘制,按 ESC 退出。")


if __name__ == '__main__':
    img = cv.imread("../images/imgLena.tif")  # 读取彩色图像(BGR)
    imgCopy = img.copy()

    # 鼠标交互 ROI
    print("单击左键:选择 ROI 顶点")
    print("单击中键:删除最近的顶点")
    print("单击右键:结束 ROI 选择")
    print("按 ESC 退出")
    pts = []  # 初始化 ROI 顶点坐标集合
    status = True  # 开始绘图状态
    cv.namedWindow('origin')  # 创建图像显示窗口
    cv.setMouseCallback('origin', onMouseAction, status)  # 绑定回调函数
    while True:
        if len(pts) > 0:
            cv.circle(imgCopy, pts[-1], 5, (0,0,255), -1)  # 绘制最近一个顶点
        if len(pts) > 1:
            cv.line(imgCopy, pts[-1], pts[-2], (255, 0, 0), 2)  # 绘制最近一段线段
        if status == False:  # 判断结束绘制 ROI
            cv.line(imgCopy, pts[0], pts[-1], (255,0,0), 2)  # 绘制最后一段线段
        cv.imshow('origin', imgCopy)
        key = 0xFF & cv.waitKey(10)  # 按 ESC 退出
        if key == 27:  # Esc 退出
            break
    cv.destroyAllWindows()  # 释放图像窗口

    # 提取多边形 ROI
    print("ROI 顶点坐标:", pts)
    points = np.array(pts, np.int)  # ROI 多边形顶点坐标集
    cv.polylines(img, [points], True, (255,255,255), 2)  # 在 img 绘制 ROI 多边形
    mask = np.zeros(img.shape[:2], np.uint8)  # 黑色掩模,单通道
    cv.fillPoly(mask, [points], (255,255,255))  # 多边形 ROI 为白色窗口
    imgROI = cv.bitwise_and(img, img, mask=mask)  # 按位与,从 img 中提取 ROI

    plt.figure(figsize=(9, 6))
    plt.subplot(131), plt.title("origin image"), plt.axis('off')
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(132), plt.title("ROI mask"), plt.axis('off')
    plt.imshow(mask, cmap='gray')
    plt.subplot(133), plt.title("ROI cropped"), plt.axis('off')
    plt.imshow(cv.cvtColor(imgROI, cv.COLOR_BGR2RGB))
    plt.tight_layout()
    plt.show()

在这里插入图片描述



2. PyQt实现鼠标点击定位

PyQt 中实现鼠标点击定位,本质上是鼠标动作的响应。

2.1 支持鼠标事件的自定义 Label 类

基本的 QLabel 类并不支持鼠标动作,因此需要自定义一个支持鼠标动作的 Label 类。

PyQt中,每个事件类型都被封装成相应的事件类,如鼠标事件为QMouseEvent,键盘事件为QKeyEvent等。而它们的基类是QEvent。

QMouseEvent 鼠标事件:

mousePressEvent (self, event):鼠标按下事件
mouseReleaseEvent (self, event):鼠标释放事件
mouseDoubieCiickEvent (self, event):双击鼠标事件
mouseMoveEvent(self,event):鼠标移动事件
enterEvent (self, event):鼠标进入控件事件
leaveEvent (self, event):鼠标离开控件事件
wheelEvent (self, event):滚轮滚动事件

QMouseEvent 鼠标方法:

ignore():让父控件继续收到鼠标事件
accept():不让父控件继续收到鼠标事件
x()、y():返回相对于控件空间的鼠标坐标值
pos():返回相对于控件空间的QPoint对象
localPos():返回相对于控件空间的QPointF对象
globalX()、globalY():返回相对于屏幕的x,y 坐标值
globalPos():返回相对于屏幕的QPoint对象
windowPos():返回相对于窗口的QPointF对象
screenPos():返回相对于屏幕的QPointF对象
timestamp():返回事件发生的时间;

QMouseEvent 鼠标事件的具体内容:
按下并释放鼠标按钮时,将调用以下方法:

mousePressEvent (self, event) - 鼠标键按下时调用;
mouseReleaseEvent (self, event) - 鼠标键公开时调用;
mouseDoubieCiickEvent (self, event) - 双击鼠标时调用。必须注意,在双击之前的其他事件。双击时的事件顺序如下:

- MouseButtonPress
- MouseButtonRelease
- MouseButtonDblClick
- MouseButtonPress
- MouseButtonRelease

2.2 例程7-2:支持鼠标事件的自定义 MyLabel 类

程序说明:

  1. 在图像窗口点击鼠标左键,选取 2 个基准点绘制直线;点击鼠标右键,清除选择的基准点;
  2. 超过 2个基准点时,自动清零,重新选取基准点;
  3. 将选取点的坐标传回主程序,进行图像处理。
class MyLabel(QLabel):
    def __init__(self, parent=None):
        super(MyLabel, self).__init__(parent)
        self.points = []

    def paintEvent(self, event):
        super().paintEvent(event)
        painter = QPainter()
        painter.begin(self)
        painter.setPen(QPen(Qt.blue, 4, Qt.SolidLine))  # 实线画笔,蓝色
        if len(self.points)==2:
            painter.drawLine(self.points[0][0], self.points[0][1], self.points[1][0], self.points[1][1])
        painter.setPen(QPen(Qt.red, 10))  # 画点,红色
        for k in range(len(self.points)):
            painter.drawPoint(self.points[k][0], self.points[k][1])
        painter.end()

    def mousePressEvent(self, event):
        if event.buttons() == Qt.LeftButton:  # 左键点击
            if len(self.points)==2:
                self.points.clear()  # 清空绝对坐标
            x0 = event.x()
            y0 = event.y()
            self.points.append([x0, y0])
            self.update()  # 获取鼠标点击的点之后,通知画线
        elif event.buttons() == Qt.RightButton:  # 右键点击
            self.points.clear()  # 清空绝对坐标
            print("Clear selected points!")

    def getGlobalPos(self):  # 返回绝对坐标
        return self.points


3. 项目实战:PyQt 鼠标点击定位

本项目基于 PyQt5 GUI,使用鼠标在图像窗口区域点击选取两点,绘制直线,以该直线为水平基准线,旋转图像并显示在第二窗口。



3.1 使用 QtDesigner 开发 PyQt5 图形界面

本例的 UI 继承自 uiDemo4.ui :


在这里插入图片描述

于是,我们就完成了本项目的图形界面设计,将其保存为 uiDemo9.ui文件。

在 PyCharm中,使用 PyUIC 将选中的 uiDemo9.ui 文件转换为 .py 文件,就得到了 uiDemo9.py 文件。



3.2. 项目主程序的开发

3.2.1 实例化 MyLabel 类

自定义的 MyLabel 类不能在 QtDesigner 中创建,要在主程序中定义如下。

        self.label_1 = MyLabel(self.centralwidget)
        self.label_1.setGeometry(QRect(20, 20, 400, 320))
        self.label_1.setAlignment(Qt.AlignCenter)
        self.label_1.setObjectName("label_1")

3.2.2 图像旋转槽函数

click_pushButton槽函数,由 pushButton_3.clicked 按钮信号触发。

    def click_pushButton_3(self):  # 点击 pushButton_3 触发 旋转图像
        print("pushButton_3")
        height, width = self.img1.shape[:2]  # 图片的高度和宽度
        pointList = self.label_1.getGlobalPos()  # 获取坐标点集
        if len(pointList) < 2:
            print("Points number < 2")
            return
        else:
            pts = np.array(pointList)  # 转为 Numpy
            print(pts)
            # 计算倾斜角 angle
            radian = np.arctan((pts[1][1] - pts[0][1]) / (pts[1][0] - pts[0][0]))  # arctan((y2-y1)/(x2-x1))
            angle = radian * 180 / 3.1415926  # 角度制
            print(pts, angle)
            x0, y0 = width//2, height//2  # 以图像中心作为旋转中心
            MARot = cv.getRotationMatrix2D((x0, y0), angle, 1.0)  # 计算旋转变换矩阵
            self.img2 = cv.warpAffine(self.img1, MARot, (height, width))  # 旋转图像

        self.refreshShow(self.img2, self.label_2)  # 刷新显示
        return

3.2.3 信号与槽的连接

        # 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
        self.pushButton_1.clicked.connect(self.click_pushButton_1)  # 按钮触发:导入图像
        self.pushButton_2.clicked.connect(self.click_pushButton_2)  # # 按钮触发:灰度显示
        self.pushButton_3.clicked.connect(self.click_pushButton_3)  # # 按钮触发:旋转图像
        self.pushButton_4.clicked.connect(self.trigger_actHelp)  # # 按钮触发
        self.pushButton_5.clicked.connect(self.close)  # 点击 # 按钮触发:关闭

3.3 完整例程 OpenCVPyqt09.py

# OpenCVPyqt09.py
# Demo07 of GUI by PyQt5
# Copyright 2023 Youcans, XUPT
# Crated:2023-02-16

import sys
import cv2 as cv
import numpy as np
from PyQt5.QtCore import QObject, pyqtSignal, QPoint, QRect, qDebug, Qt
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from uiDemo9 import Ui_MainWindow  # 导入 uiDemo8.py 中的 Ui_MainWindow 界面类


class MyLabel(QLabel):
    def __init__(self, parent=None):
        super(MyLabel, self).__init__(parent)
        self.points = []

    def paintEvent(self, event):
        super().paintEvent(event)
        painter = QPainter()
        painter.begin(self)
        painter.setPen(QPen(Qt.blue, 4, Qt.SolidLine))  # 实线画笔,蓝色
        if len(self.points)==2:
            painter.drawLine(self.points[0][0], self.points[0][1], self.points[1][0], self.points[1][1])
        painter.setPen(QPen(Qt.red, 10))  # 画点,红色
        for k in range(len(self.points)):
            painter.drawPoint(self.points[k][0], self.points[k][1])
        painter.end()

    def mousePressEvent(self, event):
        if event.buttons() == Qt.LeftButton:  # 左键点击
            if len(self.points)==2:
                self.points.clear()  # 清空绝对坐标
            x0 = event.x()
            y0 = event.y()
            self.points.append([x0, y0])
            self.update()  # 获取鼠标点击的点之后,通知画线
        elif event.buttons() == Qt.RightButton:  # 右键点击
            self.points.clear()  # 清空绝对坐标
            print("Clear selected points!")

    def getGlobalPos(self):  # 返回绝对坐标
        return self.points


class MyMainWindow(QMainWindow, Ui_MainWindow):  # 继承 QMainWindow 类和 Ui_MainWindow 界面类
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)  # 初始化父类
        self.setupUi(self)  # 继承 Ui_MainWindow 界面类
        self.label_1 = MyLabel(self.centralwidget)
        self.label_1.setGeometry(QRect(20, 20, 400, 320))
        self.label_1.setAlignment(Qt.AlignCenter)
        self.label_1.setObjectName("label_1")

        # 菜单栏
        self.actionOpen.triggered.connect(self.openSlot)  # 连接并执行 openSlot 子程序
        self.actionSave.triggered.connect(self.saveSlot)  # 连接并执行 saveSlot 子程序
        self.actionHelp.triggered.connect(self.trigger_actHelp)  # 连接并执行 trigger_actHelp 子程序
        self.actionQuit.triggered.connect(self.close)  # 连接并执行 trigger_actHelp 子程序

        # 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
        self.pushButton_1.clicked.connect(self.click_pushButton_1)  # 按钮触发:导入图像
        self.pushButton_2.clicked.connect(self.click_pushButton_2)  # # 按钮触发:灰度显示
        self.pushButton_3.clicked.connect(self.click_pushButton_3)  # # 按钮触发:旋转图像
        self.pushButton_4.clicked.connect(self.trigger_actHelp)  # # 按钮触发
        self.pushButton_5.clicked.connect(self.close)  # 点击 # 按钮触发:关闭

        # 初始化
        self.img1 = np.ndarray(())  # 初始化图像 ndarry,用于存储图像
        self.img2 = np.ndarray(())  # 初始化图像 ndarry,用于存储图像
        self.img1 = cv.imread("../images/Lena.tif")  # OpenCV 读取图像
        self.refreshShow(self.img1, self.label_1)
        # self.refreshShow(self.img1, self.label_2)
        return

    def click_pushButton_1(self):  # 点击 pushButton_1 触发
        self.img1 = self.openSlot()  # 读取图像
        print("click_pushButton_1", self.img1.shape)
        self.refreshShow(self.img1, self.label_1)  # 刷新显示
        return

    def click_pushButton_2(self):  # 点击 pushButton_2 触发
        print("pushButton_2")
        self.img2 = self.img1.copy()
        self.img2 = cv.cvtColor(self.img2, cv.COLOR_BGR2GRAY)  # 图片格式转换:BGR -> Gray
        self.refreshShow(self.img2, self.label_2)  # 刷新显示
        return

    def click_pushButton_3(self):  # 点击 pushButton_3 触发 旋转图像
        print("pushButton_3")
        height, width = self.img1.shape[:2]  # 图片的高度和宽度
        pointList = self.label_1.getGlobalPos()  # 获取坐标点集
        if len(pointList) < 2:
            print("Points number < 2")
            return
        else:
            pts = np.array(pointList)  # 转为 Numpy
            print(pts)
            # 计算倾斜角 angle
            radian = np.arctan((pts[1][1] - pts[0][1]) / (pts[1][0] - pts[0][0]))  # arctan((y2-y1)/(x2-x1))
            angle = radian * 180 / 3.1415926  # 角度制
            print(pts, angle)
            x0, y0 = width//2, height//2  # 以图像中心作为旋转中心
            MARot = cv.getRotationMatrix2D((x0, y0), angle, 1.0)  # 计算旋转变换矩阵
            self.img2 = cv.warpAffine(self.img1, MARot, (height, width))  # 旋转图像

        self.refreshShow(self.img2, self.label_2)  # 刷新显示
        return

    def refreshShow(self, img, label):
        print(img.shape, label)
        qImg = self.cvToQImage(img)  # OpenCV 转为 PyQt 图像格式
        # label.setScaledContents(False)  # 需要在图片显示之前进行设置
        label.setPixmap((QPixmap.fromImage(qImg)))  # 加载 PyQt 图像
        return

    def openSlot(self, flag=1):  # 读取图像文件
        # OpenCV 读取图像文件
        fileName, _ = QFileDialog.getOpenFileName(self, "Open Image", "../images/", "*.png *.jpg *.tif")
        if flag==0 or flag=="gray":
            img = cv.imread(fileName, cv.IMREAD_GRAYSCALE)  # 读取灰度图像
        else:
            img = cv.imread(fileName, cv.IMREAD_COLOR)  # 读取彩色图像
        print(fileName, img.shape)
        return img

    def saveSlot(self):  # 保存图像文件
        # 选择存储文件 dialog
        fileName, tmp = QFileDialog.getSaveFileName(self, "Save Image", "../images/", '*.png; *.jpg; *.tif')
        if self.img1.size == 1:
            return
        # OpenCV 写入图像文件
        ret = cv.imwrite(fileName, self.img1)
        if ret:
            print(fileName, self.img.shape)
        return

    def cvToQImage(self, image):
        # 8-bits unsigned, NO. OF CHANNELS=1
        if image.dtype == np.uint8:
            channels = 1 if len(image.shape) == 2 else image.shape[2]
        if channels == 3:  # CV_8UC3
            # Create QImage with same dimensions as input Mat
            qImg = QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_RGB888)
            return qImg.rgbSwapped()
        elif channels == 1:
            # Create QImage with same dimensions as input Mat
            qImg = QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_Indexed8)
            return qImg
        else:
            qDebug("ERROR: numpy.ndarray could not be converted to QImage. Channels = %d" % image.shape[2])
            return QImage()

    def qPixmapToCV(self, qPixmap):  # PyQt图像 转换为 OpenCV图像
        qImg = qPixmap.toImage()  # QPixmap 转换为 QImage
        shape = (qImg.height(), qImg.bytesPerLine() * 8 // qImg.depth())
        shape += (4,)
        ptr = qImg.bits()
        ptr.setsize(qImg.byteCount())
        image = np.array(ptr, dtype=np.uint8).reshape(shape)  # 定义 OpenCV 图像
        image = image[..., :3]
        return image

    def trigger_actHelp(self):  # 动作 actHelp 触发
        QMessageBox.about(self, "About",
                          """数字图像处理工具箱 v1.0\nCopyright YouCans, XUPT 2023""")
        return

if __name__ == '__main__':
    app = QApplication(sys.argv)  # 在 QApplication 方法中使用,创建应用程序对象
    myWin = MyMainWindow()  # 实例化 MyMainWindow 类,创建主窗口
    myWin.show()  # 在桌面显示控件 myWin
    sys.exit(app.exec_())  # 结束进程,退出程序


运行结果:

在这里插入图片描述


在这里插入图片描述


【本节完】


版权声明:

Copyright 2023 youcans, XUPT

Crated:2023-2-16


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

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

相关文章

信创引领丨呼叫中心加速适配国产化

随着信创产业的高速发展&#xff0c;企业服务软件高度适配国产操作系统成为大势所趋。早在2020年&#xff0c;佳信客服平台就正式通过“华为云鲲鹏云服务”平台系统的兼容性测试与认证&#xff0c;成为鲲鹏凌云伙伴&#xff0c;也意味着佳信客服平台正式与国产硬件平台及操作系…

【Kubernetes 企业项目实战】07、最新一代微服务网格 Istio 入门到企业实战(下)

目录 一、istio 核心资源解读 1.1 Gateway 总结&#xff1a; 1.2 VirtualService 1.2.1 VirtualService 主要由以下部分组成 1.2.2 virtualservice 配置路由规则 1.2.3 路由规则优先级 1.2.4 多路由规则解读 1.3 DestinationRule 二、istio 核心功能演示 2.1 断路器…

【离散数学】1. 数理逻辑

1.数理逻辑 2. 集合论 3. 代数系统 4. 图论 离散数学&#xff1a;研究离散量结构及相互关系的学科 数理逻辑集合论代数系统图论 逻辑&#xff1a;研究推理的科学 数学方法&#xff1a;引进一套符号系统的方法 数理逻辑是用数学方法研究形式逻辑的科学&#xff0c;即使用符号化…

vue环境总结

因将node.js升级后&#xff0c;打包运行出错了。后来加班重新改好。 一、用nvm管理可以用命令将node和npm对应安装 1.首先在控制台输入where node查看之前本地安装的node的路径 2.将node目录删除或者卸载 二、1.安装nvm 从官网下载安装包 https://github.com/coreybutler/nvm…

JDK定时器Timer原理

前言 前些时间想到利用redis实现延时队列&#xff0c;但是底层的定时器不止如何实现好些&#xff0c;故此研究了一下jdk的Timer。 Timer是一个用于执行定时任务的类&#xff0c;可以单次执行或按指定时间间隔循环执行&#xff08;直到主动cancel或线程被杀掉&#xff09;。Ti…

大数据之---Nifi-Nifi模板_具体使用方法---大数据之Nifi工作笔记0009

然后我们来看看,如果好不容易设计了一个流程,那么是可以通过 使用模板来让流程复用的 可以看到可以创建模板,一会说怎么用具体,上面已经 写清楚了,如何创建模板 我们看一下左侧的operate,这里可以看到这里就可以创建模板 可以看到小手那个地方,点击就可以创建模板了 可以看到…

python k8s库,read_namespaced_config_map:maximum recursion depth exceeded

使用背景 在python中&#xff0c;调用了gevent库&#xff0c;同时引用了官方的k8s库接口&#xff1a; GitHub - kubernetes-client/python: Official Python client library for kubernetesOfficial Python client library for kubernetes. Contribute to kubernetes-client/…

Node.js安装配置及Angular CLI的安装

NodeJS的安装node.js官网下载地址: https://nodejs.org/en/download/在node.js的官网上面下载适合自己机型的&#xff0c;如果是Windows系统的话&#xff0c;建议下载对应的 Windows Installer (.msi) 。下载完成后&#xff0c;双击打开安装&#xff0c;安装路径最好自定义&…

Melis4.0[D1s]:1.启动流程(与adc按键初始化相关部分)跟踪笔记

文章目录1.启动流程1.1 最先进入的文件&#xff1a;head_s.S1.2 start_kernel()函数所在的文件&#xff1a;init.c1.3 input_init()函数所在文件&#xff1a;sys_input.c1.4 INPUT_LKeyDevInit()所在文件&#xff1a;keyboarddev.c1.5 esINPUT_RegLdev()所在文件&#xff1a;in…

LVS负载均衡

文章目录前言一、LVS模式-DR二、ipvsadm配置参数三、DR模式的部署server1:调度器&#xff08;VS&#xff09;server2:真实服务器&#xff08;RS&#xff09;server3:真实服务器&#xff08;RS&#xff09;真实服务器(server2和server3)屏蔽客户端测试&#xff1a;纯代码步骤演示…

SpringCloud保姆级搭建教程六---ElasticSearch

es下载地址&#xff1a;https://www.elastic.co/cn/downloads/elasticsearch 最新版本或者 https://github.com/elastic/elasticsearch 7.17.9kibana下载地址&#xff1a;https://github.com/elastic/kibana 各个版本jdk8 对应的es应该是7.*版本&#xff0c;最新的es应该对应的…

【论文及代码详解】BEIT: BERT Pre-Training of Image Transformers

记录下论文《BEIT: BERT Pre-Training of Image Transformers》&#xff0c;这是一篇将Transformer应用于图像领域&#xff0c;并使用自监督方法进行参数初始化的文章。 论文链接 整体概要 由于网络整体流程图没有标注好模型的运行过程&#xff0c;结合论文的描述&#xff1a…

收藏,核心期刊的投稿、审稿、出刊流程详解

学术期刊论文&#xff08;核心和普刊&#xff09;的发表流程总的来说其实是一样的&#xff0c;整个流程包括&#xff1a;1写作-2选择刊物-3投稿-4审稿-5返修或拒稿-6录用-7出刊-8上网检索。 其中1和2其实顺序是可以调换的&#xff0c;可以选择好刊物再写作&#xff0c;根据刊物…

麦克风阵列波束基本概念理解

波束形成 本质上是设计合适的滤波器&#xff0c;对于一类固定滤波器系数的阵列来说&#xff0c;无论输入信号或者噪声信号的统计特征如何&#xff0c;其滤波器系数固定不变&#xff0c;此类波束形成叫Fixed Beamforming&#xff0c;固定波束形成好比传统数字信号处理里面的经典…

TCP并发服务器(多进程与多线程)

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 TCP并发服务器&#xff08;多进程与多线程&#xff09;1. 多进程并发服务器&#xff08;1&#xff09;…

NPDP认证|2023年,0基础转行产品经理可以吗?

2023年&#xff0c;告别了疫情&#xff0c;各个行业正在快速回暖&#xff0c;很多企业都在高薪招聘产品经理岗位&#xff0c;这让很多其他岗位的朋友也想转行做产品经理&#xff0c;那没有基础&#xff0c;没有经验能转行做产品经理吗&#xff1f; 0基础转行产品经理是可能的&a…

Redis 删除策略

过期数据Redis中的数据特征 Redis是一种内存级数据库&#xff0c;所有数据均存放在内存中&#xff0c;内存中的数据可以通过TTL指令获取其状态XX &#xff1a;具有时效性的数据-1 &#xff1a;永久有效的数据-2 &#xff1a;已经过期的数据 或 被删除的数据 或 未定义的数据数…

Windows出现0xc00d36e5错误怎么办?

当我们使用Windows Media Player来播放视频文件时&#xff0c;可能会出现无法播放&#xff0c;并显示0xc00d36e5错误代码。该错误可能是因为Windows Media Player不支持视频格式、注册表项损坏、系统配置问题、第三方应用程序冲突等。下面将开始介绍0xc00d36e5错误的解决方法&a…

K_A12_014 基于STM32等单片机驱动S12SD紫外线传感器模块 串口与OLED0.96双显示

K_A12_014 基于STM32等单片机驱动S12SD紫外线传感器模块 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:数据对比&#xff1a;四、部分代码说明1、接线引脚定义1.1、STC89C52RCS12SD紫外线传感器模块1.2、STM32F103…

【数据结构】P0 三要素与五个特征

三要素与五个特征什么是数据结构数据结构的三要素逻辑结构存储结构数据的运算算法的五个特征时间复杂度什么是数据结构 数据元素之间存在着一种或者多种关系&#xff0c;这种关系称为结构。 数据结构的三要素 数据结构的三要素&#xff1a;逻辑结构、存储结构、数据的运算。 …