学习使用 ArUco 标记

2023-05-16

在本文中,我们将研究使用 Python 和 OpenCV 检测和估计 ArUco 标记的方向。

13f29cbd18599fbe21358ca54811f654.jpeg

首先,我们将从生成 ArUco 标记开始。你可以使用特定网站一个一个地创建单个标签,也可以使用我的程序生成整个页面的标记。

一旦你创建了一些标记,我将向你展示另一个检测这些标记的程序。该程序还可以确定这些 ArUco 标记的位姿轴(位姿代表位置和姿态)。

我在这里编写的代码是用 Python 编写的,但是对于更高级的检测和姿态估计应用程序,你可能希望使用 C++ 来实现它们。

生成 ArUco 标记

如果你想一个一个地创建 ArUco 标记,那么你可以使用 Oleg Kalachev 的这个网站:https://chev.me/arucogen/。该网站提供了一个简单的界面,如下所示:

def3dde3944189957ed1fbb884ec43c6.png

选择 ArUco 字典、标记的 id 和大小。然后下载标记并打印出来。

由于想用 ArUco 标记打印整个页面,所以这个网站对这个没有帮助。

现在,OpenCV 提供了两个名为cv.aruco.GridBoard.create()cv.aruco.GridBoard.draw()的函数——创建并随后绘制一整页的 ArUco 标记。

你可以在此处阅读有关这些功能的更多信息:https://docs.opencv.org/4.x/de/d05/classcv_1_1aruco_1_1GridBoard.html

然而,在尝试这些功能时,对结果不满意。打印时 ArUco 标记的大小不正确,一些标记未正确放置在页面边界内,并且无法添加标记的 id。

因此,决定编写自己的程序来生成 ArUco 标记页面。你可以在下面找到它:

import argparse
import cv2
import sys
import numpy as np

ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", required=True, help="path to output image containing ArUCo tag")
ap.add_argument("-i", "--id", type=int, required=True, help="ID of first ArUCo tag to generate")
ap.add_argument("-t", "--type", type=str, default="DICT_ARUCO_ORIGINAL", help="type of ArUCo tag to generate")
ap.add_argument("-d", "--dpi", type=str, default="72", help="the DPI of the output print")
ap.add_argument("-s", "--size", type=int, default=50, help="the size in mm of the ArUco tag")
ap.add_argument("-m", "--margin", type=int, default=5, help="the size in mm of the margins between the ArUco tags")
ap.add_argument("-x", "--x", type=int, default=3, help="number of ArUco tags in the X direction")
ap.add_argument("-y", "--y", type=int, default=4, help="number of ArUco tags in the Y direction")
ap.add_argument("--write-id", default=True, action=argparse.BooleanOptionalAction, help="write the id of the tag or not")
args = vars(ap.parse_args())

ARUCO_DICT = {
 "DICT_4X4_50": cv2.aruco.DICT_4X4_50,
 "DICT_4X4_100": cv2.aruco.DICT_4X4_100,
 "DICT_4X4_250": cv2.aruco.DICT_4X4_250,
 "DICT_4X4_1000": cv2.aruco.DICT_4X4_1000,
 "DICT_5X5_50": cv2.aruco.DICT_5X5_50,
 "DICT_5X5_100": cv2.aruco.DICT_5X5_100,
 "DICT_5X5_250": cv2.aruco.DICT_5X5_250,
 "DICT_5X5_1000": cv2.aruco.DICT_5X5_1000,
 "DICT_6X6_50": cv2.aruco.DICT_6X6_50,
 "DICT_6X6_100": cv2.aruco.DICT_6X6_100,
 "DICT_6X6_250": cv2.aruco.DICT_6X6_250,
 "DICT_6X6_1000": cv2.aruco.DICT_6X6_1000,
 "DICT_7X7_50": cv2.aruco.DICT_7X7_50,
 "DICT_7X7_100": cv2.aruco.DICT_7X7_100,
 "DICT_7X7_250": cv2.aruco.DICT_7X7_250,
 "DICT_7X7_1000": cv2.aruco.DICT_7X7_1000,
 "DICT_ARUCO_ORIGINAL": cv2.aruco.DICT_ARUCO_ORIGINAL,
 "DICT_APRILTAG_16h5": cv2.aruco.DICT_APRILTAG_16h5,
 "DICT_APRILTAG_25h9": cv2.aruco.DICT_APRILTAG_25h9,
 "DICT_APRILTAG_36h10": cv2.aruco.DICT_APRILTAG_36h10,
 "DICT_APRILTAG_36h11": cv2.aruco.DICT_APRILTAG_36h11
}

if ARUCO_DICT.get(args["type"], None) is None:
 print("[INFO] ArUCo tag of '{}' is not supported".format(args["type"]))
 sys.exit(0)

arucoDict = cv2.aruco.Dictionary_get(ARUCO_DICT[args["type"]])
tag_type = args["type"]

A4_width = 210
A4_height = 297

x = args["x"]
y = args["y"]
size = args["size"]
margin = args["margin"]
text_size = 8

write_id = args["write_id"]

if not(write_id):
 text_size = 0

if x < 1 or y < 1:
 print(f"[INFO] Please make sure that the grid contains at least one tag - i.e. (x > 0) and (y > 0). Currently, x = {x} and y = {y}.")
 sys.exit(0)

rest_x = A4_width - (x * size + (x - 1) * margin)
rest_y = A4_height - (y * size + y * text_size + (y - 1) * margin)

stop = False

if rest_x < 0:
 print(f"[INFO] Please ensure that the grid fits on the page. Consider reducing the number of tags in the x-direction. Currently, x = {x}.")
 stop = True

if rest_y < 0:
 print(f"[INFO] Please ensure that the grid fits on the page. Consider reducing the number of tags in the y-direction. Currently, y = {y}.")
 stop = True

if stop:
 sys.exit(0)

half_rest_x = int(np.floor(rest_x/2))
half_rest_y = int(np.floor(rest_y/2))

A4_DICT = {
 "72": (595, 842),
 "96": (794, 1123)
}

if A4_DICT.get(args["dpi"], None) is None:
 print("[INFO] A4 print of {} DPI is not supported. Please try one of the following: 72, 96.".format(args["dpi"]))
 sys.exit(0)
 
dpi = A4_DICT[args["dpi"]]
 
page = np.ones((dpi[1],dpi[0],3), dtype="uint8")*255

multiplier = np.min([dpi[0]/A4_width, dpi[1]/A4_height])

size_m = int(np.floor(size * multiplier))
text_size_m = int(np.floor(text_size * multiplier))
margin_m = int(np.floor(margin * multiplier))
half_rest_x_m = int(np.floor(half_rest_x * multiplier))
half_rest_y_m = int(np.floor(half_rest_y * multiplier))

tag_id = args["id"]

print(f"[INFO] creating {x*y} tags from the {tag_type} dictionary. Starting with id:{tag_id}")
for i in range(0, y):
 for j in range(0, x):
  img = np.ones((size_m,size_m,3), dtype="uint8")*255
  i_val = half_rest_y_m + i*size_m + i*margin_m + 2*i*text_size_m
  j_val = half_rest_x_m + j*size_m + j*margin_m
  tag = np.zeros((size_m, size_m, 1), dtype="uint8")
  cv2.aruco.drawMarker(arucoDict, tag_id, size_m, tag, 1)
  if write_id:
   if "APRILTAG" in tag_type:
    text_string = f"April id: {tag_id}"
   else:
    text_string = f"ArUco id: {tag_id}"
   cv2.putText(page, text_string, (j_val, i_val-margin_m), 
      fontFace=cv2.FONT_HERSHEY_TRIPLEX, fontScale=0.6, color=(0, 0, 0))
  page[i_val:i_val+size_m, j_val:j_val+size_m] = tag
  tag_id += 1

cv2.imwrite(args["output"], page)
cv2.imshow("ArUCo Tags Page", page)
cv2.waitKey(0)

这个程序的想法是生成一个 A4 页面,其中 ArUco 标记放置在网格上。几个输入参数决定了这个网格的大小:

  • 标记/标签的尺寸,单位为 mm

  • 标记之间的边距大小(以 mm 为单位)

  • X方向标签数

  • Y方向标签个数

  • 标签的id是否应该写在标签上方

该程序将确定所提供的参数是否会生成一个正确保持在 A4 页面范围内的网格。如果不是这种情况,程序将输出错误消息。

除了上述参数,你还可以提供以下其他参数:

  • 图像输出文件的名称

  • 要放在页面上的第一个标签的 id

  • 输出图像的 DPI

  • 要生成的标记或标签的类型

以下是一些如何生成带有标记的页面的示例:

python aruco_gen_page.py -o "aruco_markers.png" -i 0 -t "DICT_5X5_50" -d 72 --write-id -x 3 -y 4

这将产生以下页面:

6ec6d7e9c6428836227af81111c1e6b3.png 16e46a395425801607113442ab0fb9ed.jpeg

左侧是输出图像,右侧可以看到打印时默认尺寸(50 毫米)和边距(5 毫米)是正确的。

python aruco_gen_page.py -o "aruco_markers.png" -i 10 -t "DICT_4X4_50" -d 72 -s 25 -m 10 --no-write-id -x 5 -y7

它给出以下结果:

69b35ede7412122d921a2136022cdded.png eeb42d5c4271b0774758c65f422f8e1b.jpeg

左边是输出图像,右边可以看到打印时尺寸(25mm)和边距(10mm)都是正确的。

为确保在使用 Windows 11 时正确打印生成的图像,最佳打印方法如下:

转到输出带有标记的图像的文件夹。然后右键单击该图标并选择“打印”。你将看到以下对话框(可能不是部分荷兰语,就像我的一样):

02e76a7afe35609fba609826d6ce226f.png

在这里选择你的打印机,将纸张设置为 A4,然后选择“标准”质量和“普通”纸(尽管我怀疑这些设置可能因打印机而异)。确保选中“整页照片”并选中“使图片适合框架”。

没有用其他操作系统测试过这个程序。

检测和估计我们的 ArUco 标记的姿势

在我们可以检测和估计标记的姿势之前,我们需要校准我们的相机。有关如何做到这一点,请参阅下面的文章。

https://betterprogramming.pub/how-to-calibrate-a-camera-using-python-and-opencv-23bab86ca194

校准相机后,你需要获取相机矩阵和畸变系数。正如我在文章中所展示的,我已将它们放在一个 JSON 文件中。

下面是用于检测和估计的程序。

from imutils.video import VideoStream
import argparse
import imutils
import time
import cv2
import sys
import json
import numpy as np


ap = argparse.ArgumentParser()
ap.add_argument("-t", "--type", type=str,
 default="DICT_ARUCO_ORIGINAL",
 help="type of ArUCo tag to detect")
args = vars(ap.parse_args())

ARUCO_DICT = {
 "DICT_4X4_50": cv2.aruco.DICT_4X4_50,
 "DICT_4X4_100": cv2.aruco.DICT_4X4_100,
 "DICT_4X4_250": cv2.aruco.DICT_4X4_250,
 "DICT_4X4_1000": cv2.aruco.DICT_4X4_1000,
 "DICT_5X5_50": cv2.aruco.DICT_5X5_50,
 "DICT_5X5_100": cv2.aruco.DICT_5X5_100,
 "DICT_5X5_250": cv2.aruco.DICT_5X5_250,
 "DICT_5X5_1000": cv2.aruco.DICT_5X5_1000,
 "DICT_6X6_50": cv2.aruco.DICT_6X6_50,
 "DICT_6X6_100": cv2.aruco.DICT_6X6_100,
 "DICT_6X6_250": cv2.aruco.DICT_6X6_250,
 "DICT_6X6_1000": cv2.aruco.DICT_6X6_1000,
 "DICT_7X7_50": cv2.aruco.DICT_7X7_50,
 "DICT_7X7_100": cv2.aruco.DICT_7X7_100,
 "DICT_7X7_250": cv2.aruco.DICT_7X7_250,
 "DICT_7X7_1000": cv2.aruco.DICT_7X7_1000,
 "DICT_ARUCO_ORIGINAL": cv2.aruco.DICT_ARUCO_ORIGINAL,
 "DICT_APRILTAG_16h5": cv2.aruco.DICT_APRILTAG_16h5,
 "DICT_APRILTAG_25h9": cv2.aruco.DICT_APRILTAG_25h9,
 "DICT_APRILTAG_36h10": cv2.aruco.DICT_APRILTAG_36h10,
 "DICT_APRILTAG_36h11": cv2.aruco.DICT_APRILTAG_36h11
}

detectgray = True
drawaxes = True

if ARUCO_DICT.get(args["type"], None) is None:
 print("[INFO] ArUCo tag of '{}' is not supported".format(
  args["type"]))
 sys.exit(0)

print("[INFO] detecting '{}' tags...".format(args["type"]))
arucoDict = cv2.aruco.Dictionary_get(ARUCO_DICT[args["type"]])
arucoParams = cv2.aruco.DetectorParameters_create()

print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)

with open('camera.json', 'r') as json_file:
 camera_data = json.load(json_file)
dist = np.array(camera_data["dist"])
mtx = np.array(camera_data["mtx"])

frame = vs.read()
h, w = frame.shape[:2]

newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (h, w), 0, (h, w))
mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w, h), cv2.CV_32FC1)
x, y, w1, h1 = roi
yh1 = y + h1
xw1 = x + w1

while True:
 frame = vs.read()
 
 dst1 = cv2.remap(frame, mapx, mapy, cv2.INTER_LINEAR)
 frame = dst1[y:yh1, x:xw1]

 if detectgray:
  gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  (corners, ids, rejected) = cv2.aruco.detectMarkers(gray, arucoDict, parameters=arucoParams)
 else:
  (corners, ids, rejected) = cv2.aruco.detectMarkers(frame, arucoDict, parameters=arucoParams)

 if len(corners) > 0:
  if drawaxes:
   for i in range(0, len(ids)):
    rvec, tvec, markerPoints = cv2.aruco.estimatePoseSingleMarkers(corners[i], 0.02, mtx, dist)
    cv2.drawFrameAxes(frame, mtx, dist, rvec, tvec, 0.02) 

  ids = ids.flatten()
  cv2.aruco.drawDetectedMarkers(frame, corners, ids)

 cv2.imshow("Frame", frame)
 key = cv2.waitKey(1) & 0xFF

 if key == ord("q"):
  break

cv2.destroyAllWindows()
vs.stop()

首先,从 JSON 文件中加载相机矩阵和畸变系数。

接下来,从摄像头读取一帧以确定视频流中图像的宽度和高度。

然后,使用 OpenCV 函数cv2.getOptimatlNewCameraMatrix()cv2.unitUndistortRectifyMap()确定感兴趣区域roimapxmapy参数。

在无限循环中,我们从视频流中读取一帧。使用我们刚刚找到的mapxmapy参数重新映射的。此外,只裁剪图像以包含感兴趣的区域。

现在我们可以开始使用 OpenCV 函数 cv2.aruco.detectMarkers()检测标记。还包括使用当前图像帧的灰度版本的可能性。

然后,如果检测到一些标记(通过它们的角来标记),我们可以使用函数 cv2.aruco.drawDetectedMarkers()在视频帧中的标记周围绘制一个框,包括 id。

或者,我们还可以使用cv2.estimatePoseSingleMarkers()cv2.aruco.drawFrameAxes()绘制显示帧中每个标记姿态的轴。

最后,使用cv2.imshow()我们在屏幕上的 GUI 中显示框架。

下面是来自 GUI 的两个屏幕截图,显示程序正确地确定了姿势的轴和我们之前生成的页面上的每个标记的 id。

f765100d0494de46f2fa79e5fbb49c5f.png c670a276bc10380a65ab5615aad3bf03.png

当相对静止或轻微移动页面时,会检测到大部分或所有标记。另一方面,如果将页面更快地移过相机,那么在某些时候,将不会检测到任何标记。猜测是,我们所做的 Python 实现运行速度不够快,程序无法“跟随镜头”。

如果这是正确的,并且如果我们需要检测 ArUco 标记以供例如自动驾驶汽车使用,那么应该用 C++ 实现更快地工作。

参考

https://pyimagesearch.com/2020/12/14/generating-aruco-markers-with-opencv-and-python/

https://pyimagesearch.com/2020/12/21/detecting-aruco-markers-with-opencv-and-python/

https://programming.vip/docs/3d-pose-estimation-using-aruco-tag-in-python.html

https://www.programcreek.com/python/example/89319/cv2.initUndistortRectifyMap

☆ END ☆

如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文。

扫描二维码添加小编↓

f07f83fe5a5ed307ade59a8db436c91c.jpeg

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

学习使用 ArUco 标记 的相关文章

  • QGC参数请求流程(第一集)

    xff31 xff27 xff23 参数请求流程 xff08 第一集 xff09 联系作者 QQ 843230304 如流程图所示 xff1a 对应 xff31 xff27 xff23 的ParameterManager模块 xff0c 这
  • 航模螺旋桨型号

    1 有两个重要的参数 xff0c 桨直径和桨螺距 xff0c 单位均为英寸 比如8060桨 xff0c 就是说这个桨直径是8英寸 即8 2 54 xff1d 20 32厘米 螺距则为6英寸 螺距则代表桨旋转一周前进的距离
  • 用Java代码实现选择排序法

    package com hu controller public class Test public static void main String args 声明一个整形的数组 并手动输入几个数 int arr 61 11 665 985
  • C语言递归的方法实现斐波那契

    int fib int n void main int n 61 10 int result 61 fib n printf 34 d 34 result int fib int n if n gt 61 3 原题目这里是if n gt 6
  • 支持ie7,ie8,ff,不完全支持ie6的js日期控件

    var MonthDNum 61 new Array 0 31 28 31 30 31 30 31 31 30 31 30 31 var MonthText 61 new Array 34 34 34 一月 34 34 二月 34 34 三
  • oracle主键生成方式

    oracle主键 两种方法 自增主键sequence SYS GUID 生成唯一序列 一 自增主键 创建一个表 create table test NID int PRIMARY KEY oracle主键 两种方法 自增主键sequence
  • Vmware vSphere(一)安装vSphere client 以及 ubuntu

    大致流程见附件 VMware Tools 安装 xff0c 使用 xff0c 命令 xff1a vmware toolbox http blog csdn net dzassn article details 1633577 vmware
  • syslog 协议及格式

    官方文档 xff1a http tools ietf org html rfc5424 6 Syslog Message Format 6 2 HEADER 6 2 1 PRI PRI 61 lt Facility 0 23 8 43 Se
  • chm打不开

    chm文件打开看不到右边的内容 1 操作系统为了安全对下载的chm文件进行了锁定 xff0c 只需要在打开前右键单击该chm文件选择 属性 xff0c 然后在 常规 选项卡的下方单击 解除锁定 按钮就可以了 2 如果还是不能看 xff0c
  • 形式语言与自动机笔记

  • 关于Keil开发C51单片机的头文件问题

    我用的德飞莱的资料 在学习STM32中回想起学C51单片机时 xff0c 有个问题一直没解决 xff0c 就是头文件regx52 h和reg52 h的区别 因为在引用regx52 h时 xff0c 可以直接用P1 1 P3 2这些小口 但是
  • JAXB(二)Map属性映射

    JAXB support Collection List Set does not support Map not Collection XmlAdapter lt ValueType BoundType gt use List to im
  • JAXB(三)xsd 验证

    现在只有最简单的关联映射验证 关键点 xff1a jaxbMarshaller setSchema sch 还不会验证集合类型 xff1a List Set Map 以后再把JAXB xff08 二 xff09 的例子加上 xff0c 64
  • jstat

    http blog csdn net swpihchj article details 8197204
  • Effctive Java 笔记

    8 重写equals xff0c 只适合值类 xff08 枚举类除外 xff09 自反性 xff1a x equals x 61 61 true 对称性 x equals y 61 61 true 必然 y equals x 61 61 t
  • maven

    http blog csdn net zjf280441589 article details 53044308 http www infoq com maven Porject groupId 43 artifactId 43 versi
  • Linux第二课:Ubuntu 操作入门(内含:1Ubuntu 下打开终端+2 Linux 文件属性+3 设置屏幕+4 系统关机与重启+5.文件浏览器)

    Ubuntu 操作入门 2 2 1Ubuntu 下打开终端 方法1 点击 Ubuntu 桌面左上角图标进入搜索框 xff0c 输入 term 可以弹出终端 Terminal 程序 方法2 xff1a 桌面或者在文件浏览器的任何目录下右键鼠标
  • 堆中存什么?栈中存什么?

    堆中存的是对象 栈中存的是基本数据类型 和堆中对象的引用 一个对象的大小是不可估计的 xff0c 或者说是可以动态变化的 xff0c 但是在栈中 xff0c 一个对象只对应了一个4btye的引用 xff08 堆栈分离的好处 xff1a xf
  • 计算一个数的N次方

    计算一个数的N次方时 xff0c 我们先设定两个参数n和k xff0c n表示你要输入的数 xff0c k表示这个数的次方 这个时候我们必须对次方数k作出分类 xff1a k 61 0 return 1 其他 xff1a return n
  • 用结构体编写电话通讯录

    用结构体数组编写电话通讯录 xff0c 必须得知道结构体的形式 xff0c 那先把结构体定义回顾一下 xff1a 一般形式为 xff1a xff08 1 xff09 struct 结构体名称 成员表列 数组名 数组长度 如 xff1a st

随机推荐

  • linux(centos)下安装git并上传代码些许步骤(亲自验证过的步骤)

    以前听说了好多次github xff0c 但直到最近才第一次学习使用github来托管自己在linux下的代码 xff01 说实话 xff0c 我自己在使用的时候从网上查了好多教程 xff0c 但总觉得难以掌握 xff08 步骤过于繁琐 x
  • shell具体执行过程及自主实现shell解释器

    在编写shell 解释器之前 xff0c 先来分析几个知识点 xff1a xff08 1 xff09 shell 执行命令时步骤 xff1a xff08 如下图 xff09 xff08 2 xff09 shell 执行脚本时的步骤 xff1
  • Linux下的桥接模式和Nat模式的区别

    先来看一下linux在的桥接模式和Nat模式的差别 xff1a 桥接模式 xff1a Nat模式 xff1a 真正的接触这个问题是因为同学要给我远程传输文件 xff0c 这个时候就调节至桥接模式下 xff0c 进行ping 尽管我们用的是同
  • C知识点整合

    C语言总结 一 语法 1 常见的数据内置类型所占字节 xff08 64 位下 xff09 xff1a char 1 int 4 float 4 long 4 double 8 Longlong 8 2 变量 xff1a xff08 1 xf
  • 判断一棵二叉树是否为完全二叉树

    1 完全二叉树的特点 xff08 来自专业定义 xff09 看到上面完全二叉树的特点 xff0c 我可以将其特点按照自己的 理解归纳为以下几点 xff1a xff08 1 xff1a 若二叉树最下面一层有节点出现 xff0c 那么这个节点一
  • 深入理解JNI技术

    一 JNI是什么 xff1f JNI是Java Native Interface的缩写 xff0c 译为Java本地调用 JNI是一种技术 二 JNI技术的用途 xff1f Java程序中的函数调用Native程序中的函数 Native一般
  • HTTP基本认证(Basic Authentication)

    在浏览网页时候 xff0c 浏览器会弹出一个登录验证的对话框 xff0c 如下图 xff0c 这就是使用HTTP基本认证 1 客户端发送http request 给服务器 服务器验证该用户是否已经登录验证过了 xff0c 如果没有的话 xf
  • 将字符串以单词为单位逆序"I am a Student" 解法

    网上有个题目 xff0c 将字符串以单词为单位逆序 例如 34 I am a Student 34 要变成 34 Student a am I 34 解法大致为 xff1a 先将字符串整体逆序第一个字符和最后一个交换 xff0c 第二个与倒
  • 堆排序查找前N个最大数和二分查找算法

    先了解堆排序概念 堆排序利用了大根堆 xff08 或小根堆 xff09 堆顶记录的关键字最大 xff08 或最小 xff09 这一特征 xff0c 使得在当前无序区中选取最大 xff08 或最小 xff09 关键字的记录变得简单 xff08
  • 构建hash表和两种处理冲突方法

    hash表定义 hashing定义了一种将字符组成的字符串转换为固定长度 xff08 一般是更短长度 xff09 的数值或索引值的方法 xff0c 称为散列法 xff0c 也叫哈希法 由于通过更短的哈希值比用原始值进行数据库搜索更快 xff
  • 用hash_map统计出现次数最多的前N个URL

    海量数据统计频率最高词汇的常规办法之一是先通过一个hash函数处理数据然后取模N xff0c 拆分为N个小文件 xff0c 对每一个小文件进行词频统计和排序处理 xff0c 然后归并N个小文件取频率最大的M个数 下面程序是利用hash ma
  • C++与java语法的异同整理

    文章目录 Java与C 43 43 与基础语法异同java的认知 amp java与C 43 43 的异同C 43 43 中的虚函数和JAVA中的抽象方法区别C 43 43 虚函数与JAVA中抽象函数比较关于接口与抽象类 xff1a Jav
  • 微信公众平台-股票行情查询

    微信公众平台 股票行情查询 php实现的获取上证 xff0c 深证 A B股实时行情的接口 xff0c 只实现了文本消息回复 xff0c K线图可以在图文消息中加上接口url地址就可以显示 xff0c 具体的接口地址网上可以找 xff0c
  • PELCO-D与PELCO-P协议介绍

    一般控制协议都由硬件或软件商编制在程序里面 xff0c 我们只需要通过相关的控制设备来进行操作 但是作为一个从事监控行业的技术人员 xff0c 往往会遇到除了电脑和协议转换器以外根本没有任何控制设备的情况 xff0c 此时 xff0c 协议
  • ROS 问题(topic types do not match、topic datatype/md5sum not match、msg xxx have changed. rerun cmake)

    1 topic types 不匹配 使用 roslaunch 命令 roslaunch carla ros bridge carla ros bridge with example ego vehicle launch 启动官方 demo
  • Ubuntu中查看安装的Python版本以及不同版本之间切换

    查看系统中已安装的所有Python版本 使用 ls 命令来查看你的系统中都有那些 Python 的二进制文件可供使用 xiyou 64 span class token property xiyou virtual machine span
  • Ubuntu Python 多版本安装

    概述 由于 Python 3 有几次较为跳跃的更新 xff0c 导致大量使用 Python 3 作为开发工具的软件会对 Python 3 的版本进行严格限制 xff0c 如限制使用 Python 3 8 Python 3 9 版本 这要求开
  • 怒爬某 Hub 资源就为撸了一个鉴黄平台

    来源 xff1a 码匠笔记公号 黄色已经是我们所不容然而却防不胜防的 xff0c 尤其是对于做内容的工具和平台 xff0c 所以花了30分钟搭建了一个鉴黄平台 xff0c 分享给大家 数据准备 找了 N 多资源都不能解决问题 xff0c 于
  • ROSERROR : datatype/md5sum

    出错原因是 xff1a 自定义消息 xff0c 发送话题的消息类型和接受话题的消息类型不一样 但是我的代码真的是一样的 所以 xff0c 解决办法是 xff1a 清空工作空间的build devel文件夹 xff0c 重新编译运行 成功 x
  • 学习使用 ArUco 标记

    在本文中 xff0c 我们将研究使用 Python 和 OpenCV 检测和估计 ArUco 标记的方向 首先 xff0c 我们将从生成 ArUco 标记开始 你可以使用特定网站一个一个地创建单个标签 xff0c 也可以使用我的程序生成整个