当前位置: 首页 > news >正文

相机不动,机构动作----Hands Eyes

最近在研究 手眼标定,发现大家都需付费,搞啥子,说好的开源。。。 

以相机在上固定不动,机械手为 EPSON_Robot 为例,详细的一步一步实例操作指引 EPSON_Robot 的192.168.0.1  2004 Server

详细操作步骤

1. 启动程序

运行以下 Python 代码后,会弹出一个标题为 “手眼标定操作指引” 的 UI 窗口,窗口内顶部首先会显示一个文本标签提示 “当前步骤:0/5”,代表当前处于整个操作流程的第 0 步,预估总共有 5 步操作,下方会看到左右排列的 “实时标定” 和 “图像标定” 两个按钮,以及下方的 “采集手眼数据”、“执行手眼标定”、“显示采集的数据” 以及 “重置操作” 四个按钮(后四个按钮初始时部分功能未绑定,等待选择标定模式后确定具体功能)。

2. 选择标定模式(以下分两种情况说明)

实时标定模式选择及操作

  • 点击 “实时标定” 按钮,此时会先重置所有相关变量和操作步骤状态(通过调用 reset_operation 函数实现),并将标定模式设置为 “实时标定”,然后 “采集手眼数据” 按钮绑定的功能会变为 collect_data_real_time 函数,“执行手眼标定” 按钮绑定的功能会变为 perform_calibration_real_time 函数。

图像标定模式选择及操作

  • 点击 “图像标定” 按钮,同样先重置相关状态并设置标定模式为 “图像标定”,“采集手眼数据” 按钮绑定的功能会变为 collect_data_image 函数,“执行手眼标定” 按钮绑定的功能会变为 perform_calibration_image 函数。
3. 实时标定模式下的具体操作步骤(假设已选择 “实时标定”)

  • 采集第一组数据

    • 点击 “采集手眼数据” 按钮,此时会有以下操作和提示:
      • 首先弹出操作提示框显示 “接下来需要获取 EPSON_Robot 机器人手(末端执行器)的位姿信息,当前代码中只是简单模拟生成了一个单位矩阵(np.eye (4))来表示手的位姿,在实际应用中,你需要通过和 EPSON_Robot 的控制系统进行通信来获取真实的末端执行器的位姿信息,这个位姿信息通常以齐次变换矩阵(4x4)的形式表示,包含了旋转和平移信息,并将其添加到 hand_poses 列表中。”,这里你需要按照 EPSON_Robot 提供的方式(比如通过网络通信、专用 API 等)获取真实的机器人末端位姿来替换模拟代码部分(后续步骤同此情况,暂用模拟数据示意流程)。
      • 然后又会弹出操作提示框显示 “接下来将尝试打开默认的摄像头获取图像中的棋盘格角点坐标,程序会先打开摄像头读取一帧图像,转换为灰度图像后进行角点检测。如果检测到了符合设定棋盘格尺寸的棋盘格,会将角点坐标等相关数据添加;若未检测到或摄像头打开失败会弹出相应提示,请根据提示进行操作。”,程序会尝试打开摄像头,读取一帧图像并进行处理检测棋盘格角点。
      • 如果摄像头成功打开且检测到了符合设定棋盘格尺寸(代码中设定为 board_size=(8, 6))的棋盘格,会将检测到的棋盘格角点坐标(以像素为单位,格式为 Nx2 的 numpy 数组,N 为角点数量)添加到 image_points 列表中,同时对应的真实世界中的棋盘格角点坐标(在 objp 中定义,根据设定的棋盘格方格边长 square_size = 0.025 米和棋盘格布局生成的三维坐标)添加到 object_points 列表中,并且弹出提示框告知 “已成功采集一组手眼数据!”,同时会在一个300 * 300大小且居中的窗口显示当前实时图像 1 秒钟左右(方便你查看图像及棋盘格情况),便于确认采集的数据对应的图像情况。若未检测到棋盘格,会弹出提示框提示 “未检测到棋盘格,请调整相机视角后重新采集。”;若无法打开摄像头,则会弹出提示框提示 “无法打开摄像头,请检查设备连接。”。
  • 采集多组数据
    重复点击 “采集手眼数据” 按钮,按照上述采集第一组数据的流程,操作 EPSON_Robot 使其末端执行器处于不同的位姿(比如通过编程控制机器人运动到不同位置、不同姿态角度等,具体操作依赖 EPSON_Robot 的操作手册和编程接口),同时确保相机能正常拍摄到棋盘格,每次成功采集都会更新 UI 上的步骤文本(如第二次点击变为 “当前步骤:2/5” 等),建议至少采集 4 组不同状态下的数据,确保机器人手和相机相对位置及姿态有足够的变化范围,这样可以提高标定的准确性。

  • 执行标定
    当采集的数据组数满足至少 4 组后,点击 “执行手眼标定” 按钮,此时会发生以下操作及提示:

    • 首先 current_step 变量会再次自增 1,UI 上的步骤文本更新为对应的数字(例如采集了 4 次数据后点击此按钮,就变为 “当前步骤:5/5”),代表进入到执行标定这一关键步骤,同时会弹出操作提示框显示 “首先会检查采集的数据数量是否足够用于标定,需要至少采集 4 组数据,如果不足会弹出错误提示框并终止标定操作,请确保之前已采集足够的数据。” 用于提醒你确认数据数量情况。
    • 程序会检查采集的数据数量,如果不足会弹出错误提示框提示 “采集的数据不足,请至少采集 4 组数据进行标定!” 并终止标定操作,同时步骤文本也停留在当前数字不再变化。
    • 如果数据足够,会弹出操作提示框显示 “接下来将调用 cv2.calibrateHandEye 函数进行手眼标定,采用的是 Tsai-Lenz 算法,该函数需要传入机器人手的旋转矩阵列表(从 hand_poses 中提取每个位姿的前 3x3 部分表示旋转)、平移向量列表(提取每个位姿的前 3 列第 4 行表示平移)、图像中棋盘格角点坐标列表(转换格式并转换数据类型为合适的 numpy 数组形式)以及真实世界中的棋盘格角点坐标列表(object_points)作为参数。” 来告知你标定算法及参数传入相关操作,然后调用 cv2.calibrateHandEye 函数进行手眼标定。
    • 如果标定过程顺利,会将得到的旋转向量通过 cv2.Rodrigues 函数转换为旋转矩阵,并与平移向量组合成一个 4x4 的齐次变换矩阵形式存储在 calibration_result 变量中,表示手眼之间的坐标变换关系,最后弹出提示框展示这个标定得到的变换矩阵内容;若标定过程出现错误(例如数据格式不正确、算法计算出现异常等情况),会弹出错误提示框显示具体的错误信息,步骤文本同样停留在当前执行标定的这一步骤数字上。
4. 图像标定模式下的具体操作步骤(假设已选择 “图像标定”)

  • 采集第一组数据

    • 点击 “采集手眼数据” 按钮,会弹出操作提示框显示 “接下来将生成一个模拟的棋盘格图像作为示例图像用于采集数据,程序会自动创建并保存图像文件到 C:\BD.png,然后提取棋盘格角点坐标以及对应的机器人手位姿信息(这里假设你已经有相关对应关系的数据,实际需完善获取及关联逻辑),然后添加到相应列表中用于后续标定。”。
    • 程序会自动生成一个简单的 4 * 4 棋盘格样式的图像(以白色方格和黑色背景组成,模拟棋盘格),并将其存储在 C:\BD.png,然后在一个 300 * 300 大小且居中的窗口显示该图像 1 秒钟左右(方便你查看图像情况),之后模拟添加一组数据(这里暂时只是简单模拟添加,实际需要替换为真实从图像读取并关联对应机器人手位姿等逻辑),即添加一个模拟的机器人手位姿(np.eye(4) 模拟,实际要替换)到 hand_poses 列表,模拟的图像中的角点坐标(corners = np.array([[100, 200], [110, 210], [120, 220], [130, 230]]),实际要替换为真实从图像读取检测到的角点)到 image_points 列表,以及对应的真实世界中的棋盘格角点坐标(objp[0])到 object_points 列表,最后弹出提示框告知 “已成功采集一组手眼数据(从图像文件)!”。
  • 采集多组数据
    重复点击 “采集手眼数据” 按钮,按照上述采集第一组数据的流程,每次点击都会模拟添加一组数据(实际需要你准备多组包含棋盘格的图像文件,并且有对应的机器人手位姿信息,通过相应代码逻辑读取图像、提取角点坐标以及关联正确的手位姿添加到对应列表中),每次成功采集都会更新 UI 上的步骤文本(如第二次点击变为 “当前步骤:2/5” 等),建议至少采集 4 组不同状态下的数据,确保机器人手和相机相对位置及姿态有足够的变化范围(这里体现为不同图像中棋盘格与模拟的机器人手位姿的对应关系多样性),这样可以提高标定的准确性。

  • 执行标定
    当采集的数据组数满足至少 4 组后,点击 “执行手眼标定” 按钮,操作流程和提示信息基本与实时标定模式下执行标定类似,会有步骤更新提示、数据数量检查、标定算法及参数传入提示等,若数据足够会进行标定计算,成功则展示标定结果,出现错误则弹出相应错误提示框,步骤文本也会根据操作状态停留在相应数字上。

5. 查看采集的数据(可选步骤,两种标定模式通用)

在采集了一定组数的数据后,你可以点击 “显示采集的数据” 按钮,会弹出一个新的提示框,里面展示了已采集的数据组数、手的位姿示例(展示第一个采集的手位姿矩阵)以及图像点坐标示例(展示第一个采集的图像中棋盘格角点坐标数组)等信息,方便你确认采集的数据是否合理以及是否符合预期,此操作步骤文本不会改变。

6. 重置操作(可选步骤,两种标定模式通用)

如果想要重新开始手眼标定流程,例如采集的数据不理想或者想要重新进行整个操作演示等情况,可以点击 “重置操作” 按钮,程序会执行以下操作:
内部会将所有相关的全局变量(hand_posesimage_pointsobject_pointscalibration_result 以及 current_step)恢复到初始状态,清空之前采集的数据以及重置步骤计数为 0,然后通过 update_step_text 函数将 UI 上的步骤文本更新回 “当前步骤:0/5”,同时弹出提示框告知 “已重置操作,可重新开始手眼标定流程。”,之后就可以再次按照上述步骤重新进行手眼标定操作了。


import cv2
import numpy as np
import tkinter as tk
from tkinter import messagebox, Label, Button
import socket
import struct
import os
import glob# 全局变量
hand_poses = []  # 存储机器人手(末端执行器)的位姿,以齐次变换矩阵形式(4x4)
image_points = []  # 存储图像中对应的棋盘格角点坐标(Nx2,N为角点数量)
object_points = []  # 存储真实世界中的棋盘格角点坐标(Nx3)
calibration_result = None  # 存储标定结果
current_step = 0  # 当前操作步骤计数
total_steps = 5  # 预估的总操作步骤数(可根据实际情况调整)# 棋盘格尺寸(内角点数,例如8x6)
board_size = (8, 6)
square_size = 0.025  # 棋盘格方格边长,单位米(根据实际情况设置)# 生成真实世界中的棋盘格角点坐标
objp = np.zeros((board_size[0] * board_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:board_size[0], 0:board_size[1]].T.reshape(-1, 2) * square_size
objp = [objp]def update_step_text():"""更新UI上显示的步骤文本"""step_text.set(f"当前步骤:{current_step}/{total_steps}")# 通过Socket通信获取EPSON_Robot机器人手位姿信息(根据给定协议模拟,实际需按详细规范调整)
def get_robot_pose_via_socket():"""通过Socket通信按照指定的IP、端口以及指令格式获取机器人末端执行器位姿信息"""try:# 创建Socket连接client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client_socket.connect(("192.168.0.1", 2004))# 发送获取位姿数据的指令(按照给定格式)request_command = "Print #205, \"send data to pc\""client_socket.send(request_command.encode())# 接收数据(假设返回的数据格式是按一定顺序排列的浮点数表示4x4齐次变换矩阵,这里按此模拟解析,实际需按准确协议)received_data = client_socket.recv(1024)# 这里假设接收到的数据直接就是16个连续的浮点数表示位姿矩阵元素,实际可能需要更复杂的解析pose_data = struct.unpack('16f', received_data)pose_matrix = np.array(pose_data).reshape(4, 4)client_socket.close()return pose_matrixexcept socket.error as e:messagebox.showerror("Socket通信错误", f"Socket通信出现错误: {str(e)},请检查网络连接及机器人配置。")return np.eye(4)  # 如果出现错误,返回单位矩阵作为占位(可根据实际情况调整错误处理方式)# 采集数据函数(用于实时标定)
def collect_data_real_time():"""实时采集手眼数据,包括获取EPSON_Robot机器人手的位姿和对应的图像中棋盘格角点坐标"""global current_stepcurrent_step += 1update_step_text()# 通过Socket通信获取机器人手位姿hand_pose = get_robot_pose_via_socket()hand_poses.append(hand_pose)# 提醒获取图像中棋盘格角点坐标相关操作messagebox.showinfo("操作提示", "接下来将尝试打开默认的摄像头获取图像中的棋盘格角点坐标,程序会先打开摄像头读取一帧图像,转换为灰度图像后进行角点检测。如果检测到了符合设定棋盘格尺寸的棋盘格,会将角点坐标等相关数据添加;若未检测到或摄像头打开失败会弹出相应提示,请根据提示进行操作。")# 打开摄像头获取图像中的棋盘格角点坐标cap = cv2.VideoCapture(0)found, frame = cap.read()if found:gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)ret, corners = cv2.findChessboardCorners(gray, board_size, None)if ret:image_points.append(corners)object_points.append(objp[0])messagebox.showinfo("提示", "已成功采集一组手眼数据!")# 显示实时图像在300*300窗口且居中display_image(frame)else:messagebox.showerror("错误", "未检测到棋盘格,请调整相机视角后重新采集。")else:messagebox.showerror("错误", "无法打开摄像头,请检查设备连接。")cap.release()def display_image(frame):"""在300*300窗口且居中显示图像"""height, width = frame.shape[:2]max_dim = max(height, width)scale = 300 / max_dimnew_width = int(width * scale)new_height = int(height * scale)resized_frame = cv2.resize(frame, (new_width, new_height))top = (300 - new_height) // 2left = (300 - new_width) // 2centered_frame = np.zeros((300, 300, 3), dtype=frame.dtype)centered_frame[top:top + new_height, left:left + new_width] = resized_framecv2.imshow('实时图像', centered_frame)cv2.waitKey(1000)  # 显示1秒,可根据需要调整时间cv2.destroyAllWindows()# 执行实时标定函数
def perform_calibration_real_time():"""执行实时手眼标定操作,利用采集的数据计算手眼之间的变换关系"""global current_step, calibration_resultcurrent_step += 1update_step_text()# 提醒检查数据数量是否足够messagebox.showinfo("操作提示", "首先会检查采集的数据数量是否足够用于标定,需要至少采集4组数据,如果不足会弹出错误提示框并终止标定操作,请确保之前已采集足够的数据。")if len(hand_poses) < 4 or len(image_points) < 4:messagebox.showerror("错误", "采集的数据不足,请至少采集4组数据进行标定!")returntry:# 使用OpenCV的手眼标定函数(这里以Tsai-Lenz算法为例,实际可能有多种选择)# 提醒关于标定算法及参数传入相关操作messagebox.showinfo("操作提示", "接下来将调用cv2.calibrateHandEye函数进行手眼标定,采用的是Tsai-Lenz算法,该函数需要传入机器人手的旋转矩阵列表(从hand_poses中提取每个位姿的前3x3部分表示旋转)、平移向量列表(提取每个位姿的前3列第4行表示平移)、图像中棋盘格角点坐标列表(转换格式并转换数据类型为合适的numpy数组形式)以及真实世界中的棋盘格角点坐标列表(object_points)作为参数。")retval, rotation_vector, translation_vector = cv2.calibrateHandEye([pose[:3, :3] for pose in hand_poses],[pose[:3, 3] for pose in hand_poses],[points.reshape(-1, 2).astype(np.float64) for points in image_points],object_points)# 将旋转向量和平移向量转换为变换矩阵形式方便后续使用rotation_matrix, _ = cv2.Rodrigues(rotation_vector)calibration_result = np.hstack((rotation_matrix, translation_vector.reshape(3, 1)))calibration_result = np.vstack((calibration_result, np.array([0, 0, 0, 1])))messagebox.showinfo("提示", "手眼标定完成,得到变换矩阵:\n{}".format(calibration_result))except Exception as e:messagebox.showerror("错误", "标定过程出现错误:{}".format(str(e)))# 采集数据函数(用于图像标定)
def collect_data_image():"""从图像文件中采集手眼数据,读取真实图像及关联对应的机器人手位姿信息"""global current_stepcurrent_step += 1update_step_text()image_files = glob.glob("*.jpg") + glob.glob(r"c:\*.png")  # 获取当前目录下所有图像文件(可按实际指定路径)if not image_files:messagebox.showerror("错误", "未找到可用的图像文件,请确保当前目录下有包含棋盘格的图像文件(支持jpg、png格式)。")returnfor image_file in image_files:image = cv2.imread(image_file)gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)ret, corners = cv2.findChessboardCorners(gray, board_size, None)if ret:# 假设对应的机器人手位姿信息存储在同名的.txt文件中(格式自定义,这里简单按行读取模拟解析)pose_file = os.path.splitext(image_file)[0] + ".txt"if os.path.exists(pose_file):with open(pose_file, 'r') as f:pose_data = [float(line.strip()) for line in f.readlines()]pose_matrix = np.array(pose_data).reshape(4, 4)hand_poses.append(pose_matrix)image_points.append(corners)object_points.append(objp[0])messagebox.showinfo("提示", f"已成功采集一组手眼数据(从 {image_file})!")else:messagebox.showerror("错误", f"未找到对应的机器人手位姿文件 {pose_file},请检查文件是否存在及命名规范。")else:messagebox.showerror("错误", f"在图像 {image_file} 中未检测到棋盘格,请检查图像内容。")if not hand_poses or not image_points:messagebox.showerror("错误", "采集的数据不完整,无法进行标定,请检查图像及对应位姿文件情况。")# 执行图像标定函数
def perform_calibration_image():"""执行基于图像文件的手眼标定操作,利用采集的数据计算手眼之间的变换关系"""global current_step, calibration_resultcurrent_step += 1update_step_text()# 提醒检查数据数量是否足够messagebox.showinfo("操作提示", "首先会检查采集的数据数量是否足够用于标定,需要至少采集4组数据,如果不足会弹出错误提示框并终止标定操作,请确保之前已采集足够的数据。")if len(hand_poses) < 4 or len(image_points) < 4:messagebox.showerror("错误", "采集的数据不足,请至少采集4组数据进行标定!")returntry:# 使用OpenCV的手眼标定函数(这里以Tsai-Lenz算法为例,实际可能有多种选择)# 提醒关于标定算法及参数传入相关操作messagebox.showinfo("操作提示", "接下来将调用cv2.calibrateHandEye函数进行手眼标定,采用的是Tsai-Lenz算法,该函数需要传入机器人手的旋转矩阵列表(从hand_poses中提取每个位姿的前3x3部分表示旋转)、平移向量列表(提取每个位姿的前3x3列第4行表示平移)、图像中棋盘格角点坐标列表(转换格式并转换数据类型为合适的numpy数组形式)以及真实世界中的棋盘格角点坐标列表(object_points)作为参数。")retval, rotation_vector, translation_vector = cv2.calibrateHandEye([pose[:3, :3] for pose in hand_poses],[pose[:3, 3] for pose in hand_poses],[points.reshape(-1, 2).astype(np.float64) for points in image_points],object_points)# 将旋转向量和平移向量转换为变换矩阵形式方便后续使用rotation_matrix, _ = cv2.Rodrigues(rotation_vector)calibration_result = np.hstack((rotation_matrix, translation_vector.reshape(3, 1)))calibration_result = np.vstack((calibration_result, np.array([0, 0, 0, 1])))messagebox.showinfo("提示", "手眼标定完成(基于图像文件),得到变换矩阵:\n{}".format(calibration_result))except Exception as e:messagebox.showerror("错误", "标定过程出现错误:{}".format(str(e)))# 显示采集的数据函数(可用于查看已采集的数据情况,方便调试等)
def show_collected_data():"""在UI中以文本形式简单展示已采集的数据组数、手的位姿示例、图像点坐标示例等信息"""data_info = "已采集数据组数:{}\n\n".format(len(hand_poses))if hand_poses:data_info += "手的位姿示例(第一个):\n{}\n\n".format(hand_poses[0])if image_points:data_info += "图像点坐标示例(第一个):\n{}\n\n".format(image_points[0])messagebox.showinfo("已采集数据详情", data_info)# 重置操作函数,用于重新开始整个手眼标定流程
def reset_operation():"""重置所有相关变量,重新开始手眼标定流程"""global hand_poses, image_points, object_points, calibration_result, current_stephand_poses = []image_points = []object_points = []calibration_result = Nonecurrent_step = 0update_step_text()messagebox.showinfo("提示", "已重置操作,可重新开始手眼标定流程。")root = tk.Tk()
root.title("手眼标定操作指引")
step_text = tk.StringVar()# 在UI上显示步骤文本的标签
step_label = Label(root, textvariable=step_text)
step_label.pack(pady=10)# 实时标定选择按钮
real_time_btn = Button(root, text="实时标定", command=lambda: (reset_operation(), set_calibration_mode('real_time')))
real_time_btn.pack(side=tk.LEFT, padx=10, pady=10)# 图像标定选择按钮
image_btn = Button(root, text="图像标定", command=lambda: (reset_operation(), set_calibration_mode('image')))
image_btn.pack(side=tk.RIGHT, padx=10, pady=10)# 用于记录当前选择的标定模式的变量
calibration_mode = Nonedef set_calibration_mode(mode):"""设置当前标定模式,并更新相关按钮的命令绑定"""global calibration_modecalibration_mode = modeif mode == 'real_time':collect_btn.config(command=collect_data_real_time)calibrate_btn.config(command=perform_calibration_real_time)elif mode == 'image':collect_btn.config(command=collect_data_image)calibrate_btn.config(command=perform_calibration_image)# 采集数据按钮(初始时无具体绑定,后续根据选择的标定模式绑定相应函数)
collect_btn = Button(root, text="采集手眼数据", command=None)
collect_btn.pack(pady=10)# 执行标定按钮(初始时无具体绑定,后续根据选择的标定模式绑定相应函数)
calibrate_btn = Button(root, text="执行手眼标定", command=None)
calibrate_btn.pack(pady=10)# 显示采集数据按钮
show_data_btn = Button(root, text="显示采集的数据", command=show_collected_data)
show_data_btn.pack(pady=10)# 重置操作按钮
reset_btn = Button(root, text="重置操作", command=reset_operation)
reset_btn.pack(pady=10)update_step_text()
root.mainloop()

相关文章:

相机不动,机构动作----Hands Eyes

最近在研究 手眼标定&#xff0c;发现大家都需付费&#xff0c;搞啥子&#xff0c;说好的开源。。。 以相机在上固定不动&#xff0c;机械手为 EPSON_Robot 为例&#xff0c;详细的一步一步实例操作指引 EPSON_Robot 的192.168.0.1 2004 Server 详细操作步骤 1. 启动程序 运…...

Scala的导入

//导入 //(1) 创建包&#xff1a;在src上右键&#xff0c;新建软件包 //(2)填写包名&#xff1a;小写 //(3)在包上右键&#xff0c;创建类。自动加入包名 //(4)导入。import 包名.类名 //导入多个类 //import jh.yuanlixueyuan.bigdata.scala03.{A,B,C} //导入包下的所有的类 /…...

vue2中父子组件传值案例总结

在 Vue 2 中&#xff0c;父子组件之间的传值是通过 props 和事件来实现的。下面是详细的解释和总结&#xff1a; 1. 父组件向子组件传值 父组件可以通过 props 向子组件传递数据。以下是一个简单的示例&#xff1a; 父组件 (Parent.vue) <template><div><h1…...

功能篇:springboot中实现文件导出

### Spring Boot 中实现文件导出功能 #### 概述 在现代Web应用程序中&#xff0c;文件导出是一个常见的需求&#xff0c;允许用户将数据以特定格式&#xff08;如CSV、Excel、PDF等&#xff09;下载到本地。本文将详细介绍如何使用Spring Boot实现文件导出功能&#xff0c;并…...

Redis客户端(Jedis、RedisTemplate、Redisson)

1. 简介 Redis作为一个当下很火热的非关系型数据库&#xff0c;Java从业人员基本都离不开对Redis的使用。在Java程序中该数据库&#xff0c;需要借助于市面上的开源客户端&#xff0c;如Jedis、Spring Data Redis、Redisson&#xff0c;它们可以作为操作Redis非关系型数据库的桥…...

Mybatis中SQL的执行过程

文章目录 Mybatis 框架SQL执行过程数据库操作映射方式SQL的执行过程- SQL解析- SQL参数映射- SQL预编译- SQL执行- 结果映射- 事务处理- 缓存处理- 日志记录与监控 扩展#与$的区别- $ 符号- # 符号总结示例 Mybatis SQL分类- 动态 SQL- 静态 SQL静态SQL和动态SQL选择${}、#{}与…...

【数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 测试说明 我的通关代码: 测试结果&#xff1a; 任务描述 本关任务&#xff1a;编写一个程序实现顺序栈的基本运算。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 初始化栈、销毁栈、判断栈是否为空、进栈、出栈、取…...

【论文阅读】PRIS: Practical robust invertible network for image steganography

内容简介 论文标题&#xff1a;PRIS: Practical robust invertible network for image steganography 作者&#xff1a;Hang Yang, Yitian Xu∗, Xuhua Liu∗, Xiaodong Ma∗ 发表时间&#xff1a;2024年4月11日 Engineering Applications of Artificial Intelligence 关键…...

在Linux桌面系统普及化方面的一些建议

在推动Linux桌面系统普及化的过程中&#xff0c;可以考虑以下几个方案和策略&#xff1a; 用户友好性改进&#xff1a; 界面设计&#xff1a;提升用户界面的美观性和易用性&#xff0c;使其更接近或超越主流操作系统的用户体验。软件兼容性&#xff1a;确保常用软件&#xff08…...

LLM - 多模态大模型的开源评估工具 VLMEvalKit 部署与测试 教程

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/144353087 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 VLMEva…...

数据结构(Queue队列)

前言&#xff1a; 在计算机科学中&#xff0c;数据结构是构建高效算法和程序的基础&#xff0c;而队列&#xff08;Queue&#xff09;作为一种经典的线性数据结构&#xff0c;具有重要的地位。与栈&#xff08;Stack&#xff09;不同&#xff0c;队列遵循“先进先出”&#xf…...

Qt 图形框架下图形拖动后位置跳动问题

在使用Qt 的图形框架QGraphicsScene&#xff0c;QGraphicsView实现图形显示时。遇到一个很棘手的BUG。 使用的图形是自定义的QGraphicsObject的子类。 现象是将图形添加到画布上之后&#xff0c;用鼠标拖动图形&#xff0c;图形能正常改变位置&#xff0c;当再次用鼠标点击图…...

【Linux篇】走进Linux — 开启开源操作系统之旅

文章目录 初识Linux一.Linux的起源与发展二.Linux的特点三.Linux的应用四.Linux的发行版本 Linux环境搭建一.Linux环境的搭建方式二.购买云服务器三.使用XShell远程登陆到Linux 初识Linux 一.Linux的起源与发展 1.初始动机&#xff1a; Linux是一个功能强大的开源操作系统&am…...

如何利用DBeaver配置连接MongoDB和人大金仓数据库

最近根据国产化要求&#xff0c;需要使用国产数据库&#xff0c;但习惯使用DBeaver连接各种成熟的商业或开源数据库。因此&#xff0c;就想着如何继续基于该工具&#xff0c;连接MongoDB和人大金仓数据库&#xff0c;查了半天很多地方说法不统一&#xff0c;所以自己就简单整理…...

Android 车载虚拟化底层技术-Kernel 5.10 -Android12(multi-cards)技术实现

详细代码实现见 Android Display Graphics系列文章-汇总​​​​​​Android Display Graphics系列文章-汇总 Android Display Graphics系列文章-汇总 Android Display Graphics系列文章-汇总 本文主要包括部分&#xff1a; 一、Android12的Kernel 5.10版本 1.1 Kernel 5…...

Qt之点击鼠标右键创建菜单栏使用(六)

Qt开发 系列文章 - menu&#xff08;六&#xff09; 目录 前言 一、示例演示 二、菜单栏 1.MenuBar 2.Menu 总结 前言 QMainWindow是一个为用户提供主窗口程序的类&#xff0c;包含一个菜单栏&#xff08;menubar&#xff09;、多个工具栏(toolbars)、一个状态栏(status…...

开发一套SDK 第一弹

自动安装依赖包 添加条件使能 #ex: filetypesh bash_ls 识别 达到预期,多个硬件环境 等待文件文件系统挂在完成 或者创建 /sys/class/ 属性文件灌入配置操作 AI 提供的 netlink 调试方法,也是目前主流调用方法,socket yyds #include <linux/module.h> #include <linux…...

sftp+sshpass

实现场景&#xff0c;要求客户端定时将本地的日志文件传输到服务器。 工作环境ubuntu&#xff0c;注意不通操作系统的版本不通&#xff0c;依赖的工具的版本也有所不同 实现目标需要客户端满足安装工具&#xff1a; 1、下载安装sshpass ---安装命令&#xff1a;sudo apt-ge…...

【机器学习与数据挖掘实战】案例01:基于支持向量回归的市财政收入分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支&#xff0c;专注于让计算机系统通过数据学习和改进。它利用统计和计算方法&#xff0c;使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数…...

Idea实现定时任务

定时任务 什么是定时任务&#xff1f; 可以自动在项目中根据设定的时长定期执行对应的操作 实现方式 Spring 3.0 版本之后自带定时任务&#xff0c;提供了EnableScheduling注解和Scheduled注解来实现定时任务功能。 使用SpringBoot创建定时任务非常简单&#xff0c;目前主要…...

Linux 安装NFS共享文件夹

程序默认使用2049端口&#xff0c;如果被占用需要修改端口104设置为服务端 122设置为客户端 一、在线安装&#xff08;服务端和客户端执行&#xff09; yum install nfs-utils rpcbind -y二、配置启动参数&#xff08;服务端执行&#xff09; 104服务器/mnt路径下创建shareda…...

bash 判断内存利用率是否高于60%

在 Bash 脚本中&#xff0c;可以通过 free 命令获取内存利用率&#xff0c;然后结合 awk 和条件判断语句实现监控内存利用率是否高于 60%。以下是一个示例脚本&#xff1a; 1. 示例脚本 #!/bin/bash# 获取总内存和已使用内存 total_mem$(free | awk /Mem:/ {print $2}) used_…...

推送(push)项目到gitlab

文章目录 1、git init1.1、在当前目录中显示隐藏文件&#xff1a;1.2、查看已有的远程仓库1.3、确保你的本地机器已经生成了 SSH 密钥&#xff1a;1.4、将生成的公钥文件&#xff08;通常位于 ~/.ssh/id_rsa.pub&#xff09;复制到 GitLab 的 SSH 设置中&#xff1a;1.5、测试 …...

centos9升级OpenSSH

需求 Centos9系统升级OpenSSH和OpenSSL OpenSSH升级为openssh-9.8p1 OpenSSL默认为OpenSSL-3.2.2&#xff08;根据需求进行升级&#xff09; 将源码包编译为rpm包 查看OpenSSH和OpenSSL版本 ssh -V下载源码包并上传到服务器 openssh最新版本下载地址 wget https://cdn.openb…...

硬件成本5元-USB串口采集电表数据完整方案-ThingsPanel快速入门

ThingsPanel开源物联网平台支持广泛的协议&#xff0c;灵活自由&#xff0c;本文介绍ThingsPanel通过串口来采集电表数据&#xff0c;简单易行&#xff0c;成本低廉&#xff0c;适合入门者学习试验&#xff0c;也适合一些特定的应用场景做数据采集。 适用场景&#xff1a; 降低…...

在AWS EMR上用Hive、Spark、Airflow构建一个高效的ETL程序

在AWS EMR&#xff08;Elastic MapReduce&#xff09;上构建一个高效的ETL程序&#xff0c;使用Hive作为数据仓库&#xff0c;Spark作为计算引擎&#xff0c;Airflow作为调度工具时&#xff0c;有几个关键的设计与实施方面需要注意。 在AWS EMR上构建高效的ETL程序&#xff0c;…...

前端(四)css选择器、css的三大特性

css选择器、css的三大特性 文章目录 css选择器、css的三大特性一、css介绍二、css选择器2.1 基本选择器2.2 组合选择器2.3 交集并集选择器2.4序列选择器2.5属性选择器2.6伪类选择器2.7伪元素选择器 三、css三大特性3.1 继承性3.2 层叠性3.3 优先级 一、css介绍 CSS全称为Casca…...

vscode 打开 setting.json

按下Ctrl Shift P&#xff08;Windows/Linux&#xff09;或Cmd Shift P&#xff08;Mac&#xff09;来打开命令面板。输入open settings&#xff0c;然后选择 Open User Settings(JSON)。打开settings.json文件 ------修改设置-----&#xff1a; 1、 html代码的行长度&am…...

关于网络安全攻防演化博弈的研究小议

1. 拉高视角&#xff0c;从宏观看网络安全攻防 伴随着信息化的发展&#xff0c;网络安全的问题就一直日益突出&#xff0c;与此同时&#xff0c;网络安全技术也成为研究热点&#xff0c;直到今日也没有停止。 从微观来看&#xff0c;网络安全技术研究指的是针对某项或某几项…...

【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(7)

1.问题描述&#xff1a; 推送通知到手机&#xff0c;怎么配置拉起应用指定的页面&#xff1f; 解决方案&#xff1a; 1、如果点击通知栏打开默认Ability的话&#xff0c; actionType可以设置为0&#xff0c; 同时可以在.clickAction.data中&#xff0c;指定待跳转的page页面…...

wordpress修改地址无法访问/有哪些搜索引擎

报错今天线上遇到故障&#xff0c;php进行因为段错误退出了&#xff0c;系统日志中的kernel报错如下&#xff1a;Feb 25 22:25:11 web_server_01 kernel: __ratelimit: 250 callbacks suppressedFeb 25 22:25:11 web_server_01 kernel: php-fpm[25942]: segfault at 2c6 ip 000…...

郑州微科网站建设/今日油价92汽油价格

随着生活水平的不断提高&#xff0c;消费者们买车已经不仅仅局限于代步&#xff0c;而是希望能够拥有更多、更好的驾乘体验&#xff0c;所以原本知识用于车内照明的灯&#xff0c;发展到了用于调节氛围的灯具&#xff0c;并且还赋予了个性化等。而且这样的需求几乎已经涵盖了整…...

网站开发工作平时做什么/爱站网挖掘关键词

简介&#xff1a; 挺不错的一个简约导航模板 网盘下载地址&#xff1a; http://kekewl.org/XLCQkWrvFdi0 图片&#xff1a;...

网站建设外包行业/企业推广是什么职业

XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。恶意攻击者往Web页面里插入恶意html代码&#xff0c;当用户浏览该页之时&#xff0c;嵌入当中Web里面的html代码会被运行&#xff0c;从而达到恶意攻击用户的特殊目的。 from:http://www.incapsula.com/blog/world-largest-site…...

基于ASP.NET的购物网站建设/地推拉新app推广平台有哪些

阅读整理自《MySQL 必知必会》- 朱晓峰&#xff0c;详细内容请登录 极客时间 官网购买专栏。 文章目录安装与配置1.选择安装类型2.安装服务器及相关组件3.配置服务器4.身份验证5.设置密码和用户权限6.配置 Windows 服务图形化管理工具 Workbench创建数据表录入 Excel 数据编码转…...

学做网站论坛vip码/网站排名优化培训哪家好

思路1 遍历棋盘中的每一个位置&#xff0c;对于空位置&#xff0c;把1-9都往里面填&#xff0c;假设当前填入1没有打破条件&#xff08;横向没有重复的点&#xff0c;纵向没有重复的点&#xff0c;方格里也没重复的点&#xff09;&#xff0c;那么当前位置就填1&#xff0c;再…...