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

使用 TensorFlow、Keras-OCR 和 OpenCV 从技术图纸中获取信息

0676f66128cf1b3b4ee6d418a91845a9.jpeg

简单介绍

输入是技术绘图图像。对象检测模型获取图像后对其进行分类,找到边界框,分配维度,计算属性。

3a8247d6c82fdebd33b07e3dafee9d64.jpeg

示例图像(输入)

分类后,找到“IPN”部分。之后,它计算属性,例如惯性矩。它适用于不同类型的部分(IPN、UPN、相等或不相等的支路、组合)。

311defa98e52c586a676568129229a1a.jpeg

结果(输出)

你可以从这里查看相关的 github 存储库:https://github.com/ramazanaydinli/Steel-AI/tree/main/final

摘要

这项工作的目的是从与钢结构相关的技术图纸中获取尺寸信息。然而,本文的目的是解释工作的细节,任何感兴趣的人都可以理解背后的想法,并使用类似的技术来解决他们的问题。它仅涵盖一些案例,以证明可以将计算机视觉方法应用于该领域。如果你需要,可以在之后进行一些改进。

要求

288edb1e544ab377bd170633d081ecbe.jpeg

深度学习

你必须至少了解一种深度学习框架。就个人而言,使用 TensorFlow,但其他人(例如 PyTorch)也可以完成这项工作。如果你想学习 TensorFlow ,建议:

  1. TensorFlow 简介:https://www.coursera.org/learn/introduction-tensorflow

  2. Tensorflow 高级技术:https://www.coursera.org/specializations/tensorflow-advanced-techniques

光学字符识别

有许多可用的光学字符识别工具,请确保根据你的目标选择最合适的工具。在备选方案中,Keras-OCR 和 Tesseract-OCR 是最受欢迎的。但由于 Tesseract 不支持自定义训练,我们将使用Keras(此功能的优势将在本文的后期详细介绍)。

OpenCV

我相信官方文档绰绰有余,但你需要了解更多信息。

介绍

如果你是一名土木工程师,对你来说,下图应该比较容易看懂。但是考虑到不是每个人都有这方面的知识,在这里提供简单的描述,以便非土木工程师可以看到他们的领域与这个领域之间的相似之处,使用相同的技术,通过稍微调整代码来解决他们的问题。

465c2ca251655c70cc2ada9ffed3488e.jpeg

简单描述一下:你可能会以文本或图像的形式,得到不同的形状、材料或属性,你需要根据这个给定的数据计算指定的属性。

所有的计算都是按规格规范化的,所以如果你知道你需要计算什么,你就可以猜出该计算需要哪些属性。

我们该怎么做?

阅读问题

首先我们需要阅读问题。此时,使用任何OCR读取文本并提取所需内容非常容易。以下示例将帮助你理解:

639bc89bbbf51e80bdf41e2ede2df815.jpeg

为简单起见,输入图像被裁剪

上图是我们的输入。我们将使用 Keras-OCR 通过使用下面的代码块来阅读文本:

import keras_ocrimage_path = "Path of the image" # Something like C:\..\image.png
pipeline = keras_ocr.pipeline.Pipeline()
image = keras_ocr.tools.read(image_path)
prediction = pipeline.recognize([image])[0]
boxes = [value[1] for value in prediction]
canvas = keras_ocr.tools.drawBoxes(image=image, boxes=boxes, color=(255, 0, 0), thickness=1)
fa242cf4fe6c934c78fdcbf83e548418.jpeg

阅读结果

此外,我们可以使用以下方式访问图像的内容:

for text, box in prediction:print(text)
6f3de5e97ba1ab3b27c6134d42124cc7.jpeg

文本的输出

我觉得思路很清晰。你将图像提供给 ocr,ocr 读取它并将输出返回给你。之后我们可以处理这个输出来学习属性。

NLP(自然语言处理——机器阅读文本、理解文本并返回响应)不是这里的主要主题,因此在本文中我们不会对其进行详细介绍,但我们可以使用简单的正则表达式方法将关键字与值匹配。

如果你听说过 ChatGPT——一种最近非常流行的高级聊天机器人,你可以猜到将文本理解为机器并不是这里的大问题。

到目前为止,我们为与读数相关的假设提供了一些基础。接下来我们需要为我们的对象检测做一些准备。

对象检测

55ee5b7bb035424c1a73453f0a3c6822.jpeg

我们需要识别绘图和获取尺寸

由于我们在前一部分从文本中获取了信息,因此我们继续分析绘图。但在继续之前,请先看看这篇文章:https://arxiv.org/ftp/arxiv/papers/2205/2205.02659.pdf

我们可以看到,更复杂的绘图在形状和注释方面的识别准确率为 80%。要点是:

Faster-RCNN ResNet50为绘图识别提供了良好的结果。

由于这类作品缺乏数据,人工生成图像是个好主意。

由于支持自定义训练,Keras-OCR非常适合此类工作。例如,如果我们想做一些与基础工程相关的项目,我们需要训练 Keras 学习普通 ocr 目前不知道的地下水位符号。

28f66996d92358e2cc6717753da5cb14.jpeg

GWT 级别的字符(红色框内)

根据这些信息,下一步是生成人工数据。PIL(Python 图像库)用于此目的。使用此工具,可以创建包含注释的形状。同样,使用最简单的方法,每个形状都是由不同数量的矩形组成的。

创建了三个不同的主要形状。将这些形状彼此相加称为“组合”形状。如果要检查,可以使用此链接访问代码:https://github.com/ramazanaydinli/Steel-AI/blob/main/final/data_generator.py

下面给出了代码生成的一些示例:

6264c53081bd5b7353b19b168ac498d5.jpeg

没有注释的形状

e6559c7869396f8789aafa4c575ff3d2.jpeg

带注释的形状

创建数据后,下一步是安装对象检测环境。按照此处的说明进行操作:https://tensorflow-object-detection-api-tutorial.readthedocs.io/en/latest/install.html

这一步可能出现的错误:

  • ImportError: cannot import name ‘builder’ from ‘google.protobuf.internal’

由于某种原因,此文件已从官方安装文件中删除。从这里(https://raw.githubusercontent.com/protocolbuffers/protobuf/main/python/google/protobuf/internal/builder.py)复制原始文件。创建 builder.py 文件,将原始代码粘贴到其中,保存文件,然后将文件移动到:{your_environment_location}/site-packages/google/protobuf/internal/builder.py

下一步是使用 ResNet50 的推理进行自定义对象检测训练。按照此处的说明进行操作:https://tensorflow-object-detection-api-tutorial.readthedocs.io/en/latest/training.html

直到到达“下载预训练模型”部分。在这部分中,我们将下载 FasterRCNN-ResNet50 640x640 而不是 SSD_ResNet50。应严格遵守其余说明。

这一步可能出现的错误:

  • UTF-8 codec can’t decode …

如果你得到 UTF-8 错误,你应该注意 pbtxt 文件的扩展名,再次检查它。

为简单起见,我们将使用三种不同的形状:

d395f9b76670c3fa170c825271f7c773.jpeg

上面的形状将输入模型

item {id: 1name: 'IPN'
}item {id: 2name: 'Legged'
}item {id: 3name: 'UPN'
}

所以我们的 label_map.pbtxt 文件应该和上面一样。

同样在 pipeline.config 文件中,更改:

...
num_classes = 3 #default value is 90
...train_config: {batch_size: 64  # Lower this value if your computer gave memory errorsync_replicas: truestartup_delay_steps: 0replicas_to_aggregate: 8num_steps: 25000 # It is up to you but this kind of simple drawings even 2000 could get the job doneoptimizer {momentum_optimizer: {learning_rate: {cosine_decay_learning_rate {learning_rate_base: .04total_steps: 25000   # If you changed previous value, change this value toowarmup_learning_rate: .013333warmup_steps: 2000 # Arrange warmup steps, change it into %10 of num_steps}}momentum_optimizer_value: 0.9}use_moving_average: false}fine_tune_checkpoint_version: V2fine_tune_checkpoint: "PATH_TO_BE_CONFIGURED" #Specify the path of ckpt-0 filefine_tune_checkpoint_type: "classification" # Change this value into "detection"data_augmentation_options {random_horizontal_flip {}}...
train_input_reader: {label_map_path: "PATH_TO_BE_CONFIGURED/label_map.txt" # Specify the path of label_maptf_record_input_reader {input_path: "PATH_TO_BE_CONFIGURED/train2017-?????-of-00256.tfrecord" #Specify the path of training tf.record files you created with protobuff}
}
...eval_input_reader: {label_map_path: "PATH_TO_BE_CONFIGURED/label_map.txt" #Again specify label map pathshuffle: falsenum_epochs: 1tf_record_input_reader {input_path: "PATH_TO_BE_CONFIGURED/val2017-?????-of-00032.tfrecord" #Specify the path of testing tf.record files you created with protobuff}
}

如果你在这一步之前所做的一切都正确,你就可以开始训练,这需要一些时间。更强的 GPU 需要更短的训练时间,你也可以调整 pipeline.config 文件中的“step_size”参数来缩短它。更改参数时注意不要过拟合或欠拟合。

图像处理

假设一切正常,我们就可以开始处理图像了。Jupter Notebook 将用于后续步骤。我们将从导入所需的库开始。

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'    # Suppress TensorFlow logging (1)
import pathlib
import tensorflow as tftf.get_logger().setLevel('ERROR')           # Suppress TensorFlow logging (2)# Enable GPU dynamic memory allocation
gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:tf.config.experimental.set_memory_growth(gpu, True)
main_path=os.getcwd()

新建一个目录,粘贴一张图片进去测试,如果需要可以多拍几张。采取它在 jupter 中使用该图像的路径。

image_paths = []
for image_name in os.listdir("{your directory path}"):image_paths.append(os.path.join("{your directory path}", image_name))

上面的循环将获取该目录中的每个图像并获取图像路径。

MODEL_DATE = '20221206'
MODEL_NAME = 'my_resnet'
LABEL_FILENAME = 'label_map.pbtxt'
PATH_TO_LABELS = os.path.join(main_path, "annotations", LABEL_FILENAME)
PATH_TO_MODEL_DIR = os.path.join(main_path, "models")
PATH_TO_CFG = os.path.join(PATH_TO_MODEL_DIR, "my_resnet", "pipeline.config" )
PATH_TO_CKPT = os.path.join(PATH_TO_MODEL_DIR, "my_resnet")

上面的代码块是兼容性所必需的。

import time
from object_detection.utils import label_map_util
from object_detection.utils import config_util
from object_detection.utils import visualization_utils as viz_utils
from object_detection.builders import model_builderprint('Loading model... ', end='')
start_time = time.time()# Load pipeline config and build a detection model
configs = config_util.get_configs_from_pipeline_file(PATH_TO_CFG)
model_config = configs['model']
detection_model = model_builder.build(model_config=model_config, is_training=False)# Restore checkpoint
ckpt = tf.compat.v2.train.Checkpoint(model=detection_model)
ckpt.restore(os.path.join(PATH_TO_CKPT, 'ckpt-3')).expect_partial()@tf.function
def detect_fn(image):"""Detect objects in image."""image, shapes = detection_model.preprocess(image)prediction_dict = detection_model.predict(image, shapes)detections = detection_model.postprocess(prediction_dict, shapes)return detectionsend_time = time.time()
elapsed_time = end_time - start_time
print('Done! Took {} seconds'.format(elapsed_time))

上面,我们导入了所需的模块并加载了我们之前训练的模型。

category_index = label_map_util.create_category_index_from_labelmap(PATH_TO_LABELS,use_display_name=True)
def load_image_into_numpy_array(path):"""Load an image from file into a numpy array.Puts image into numpy array to feed into tensorflow graph.Note that by convention we put it into a numpy array with shape(height, width, channels), where channels=3 for RGB.Args:path: the file path to the imageReturns:uint8 numpy array with shape (img_height, img_width, 3)"""return np.array(Image.open(path))
for image_path in image_paths:print('Running inference for {}... '.format(image_path), end='')image_np = load_image_into_numpy_array(image_path)img_height, img_width = image_np.shape[0], image_np.shape[1]input_tensor = tf.convert_to_tensor(np.expand_dims(image_np, 0), dtype=tf.float32)detections = detect_fn(input_tensor)# All outputs are batches tensors.# Convert to numpy arrays, and take index [0] to remove the batch dimension.# We're only interested in the first num_detections.num_detections = int(detections.pop('num_detections'))detections = {key: value[0, :num_detections].numpy()for key, value in detections.items()}detections['num_detections'] = num_detections# detection_classes should be ints.detections['detection_classes'] = detections['detection_classes'].astype(np.int64)label_id_offset = 1image_np_with_detections = image_np.copy()viz_utils.visualize_boxes_and_labels_on_image_array(image_np_with_detections,detections['detection_boxes'],detections['detection_classes']+label_id_offset,detections['detection_scores'],category_index,use_normalized_coordinates=True,max_boxes_to_draw=200,min_score_thresh=0.3,agnostic_mode=False)plt.figure()plt.imshow(image_np_with_detections)print('Done')
plt.show()

此时你应该看到对象检测结果,即标签和边界框坐标。这里有几个示例结果:

2b95add74ae3cb4a2ac13b57fd1376b8.jpeg

使用边界框检测 IPN 形状

17c01300a349d810c4bde71f486767ef.jpeg

网上随便找的一张图(连手绘都认得)

329ac363c9c1905b4d3af48e79c2e5e6.jpeg

Equal Leg标签和bounding box检测结果

bdc3bba28a56898ae150c193645c7c3b.jpeg

左图是1个IPN和1个UPN的组合图,中间和右边的图是网上的随机图,以前没见过这个模型,但是label和bounding boxes还是可以用的

通过这些测试图像,我们可以说我们的模型可以很好地预测标签和指定边界框。

下一步是从这些图像中获取尺寸。我们会将边界框内部与图像的其余部分隔离开来,这样我们就可以轻松地对其进行处理。

boxes = detections['detection_boxes']# get all boxes from an array
max_boxes_to_draw = boxes.shape[0]# get scores to get a threshold
scores = detections['detection_scores']# this is set as a default but feel free to adjust it to your needs
min_score_thresh=.5# iterate over all objects found
for i in range(min(max_boxes_to_draw, boxes.shape[0])):if scores is None or scores[i] > min_score_thresh:# boxes[i] is the box which will be drawnclass_name = category_index[detections['detection_classes'][i+1]]['name']print ("This box is gonna get used", boxes[i], detections['detection_classes'][i+1])

可以从上面的代码块中找到边界框坐标。需要注意的重要一点是,模型检测到许多边界框,但我们将使用最大的一个。我们还向“i”添加了“1”,因为我们的标签映射从 1 开始,而循环从 0 开始。

top_y = boxes[0][0]*img_height
left_x = boxes[0][1]*img_width
bottom_y = boxes[0][2]*img_height
right_x = boxes[0][3]*img_width

我们分离了边界框的像素值。

由于我们知道标签(IPN、UPN 或 Leg)和边界框坐标,我们可以处理图像以获得尺寸。这里可以使用几种不同的方法。

import cv2
import math
image_path = image_paths[0]
img = cv2.imread(image_path)
extra_pixels = 5
y_top = int(top_y)-extra_pixels
y_bottom = int(bottom_y)+extra_pixels
x_left = int(left_x) - extra_pixels
x_right = int(right_x) + extra_pixels
roi = img[y_top:y_bottom,x_left:x_right]#Hough Line
dst = cv2.Canny(roi, 50, 200, None, 3)
cdst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)
lines = cv2.HoughLines(dst, 1, np.pi/180, 150, None, 0,0)
line_points = []if lines is not None:for i in range(0, len(lines)):rho = lines[i][0][0]theta = lines[i][0][1]a = math.cos(theta)b = math.sin(theta)x0 = a * rhoy0 = b * rhopt1 = (int(x0 + 1000*(-b)), int(y0 + 1000*(a)))pt2 = (int(x0 - 1000*(-b)), int(y0 - 1000*(a)))line_points.append([pt1, pt2])cv2.line(cdst, pt1, pt2, (0,0,255), 1, cv2.LINE_AA)
plt.imshow(cdst)# Probabilistic Hough Line
# edges = cv2.Canny(roi, 50, 150, apertureSize=3)
# linesP = cv2.HoughLinesP(edges, 1, np.pi/180, 50, 100, 2)
# if linesP is not None:
#    for i in range(0, len(linesP)):
#        l = linesP[i][0]
#        cv2.line(roi, (l[0], l[1]), (l[2], l[3]), (0,0,255), 1, cv2.LINE_AA)
# cv2.imwrite("roi.png", roi)
# plt.imshow(roi)

限制

用于这种情况的明显方法是霍夫线。但问题是,正常的霍夫变换和概率霍夫变换都无法检测短线,也就是注释的边界。查看以下示例:

be9644666f58efcb616259c080cf77e4.jpeg

左 — roi,裁剪图像(感兴趣区域),右 — roi 的霍夫线结果

如你所见,检测到所有长线,但未检测到短线。Probabilistic HLine 结果也有同样的问题,查看下图:

ea46eabf7102fdbc9d7eee2509c4e3be.jpeg

如果我们可以获得与长线一起的短线,我们可以将霍夫线坐标与注释边界坐标相匹配。使用一些规则(if-else 块),可以获得非常好的结果。

另一个问题是,通常形状都带有注释,但有时整个形状可以用特定的名称来描述(例如只给出名称“HE300A”,属性应该从部分表中获取),但是几个 if-else 块可以工作。

考虑到整体的局限性和可能性,目前最好的方法是通过区域坐标进行匹配。

import keras_ocr
roi_path = os.path.join(main_path, "roi.png")
pipeline = keras_ocr.pipeline.Pipeline()image = keras_ocr.tools.read(roi_path)
prediction = pipeline.recognize([image])[0]
boxes = [value[1] for value in prediction]canvas = keras_ocr.tools.drawBoxes(image=image, boxes=boxes, color=(255, 0, 0), thickness=1)
60e84f015e1e034397db4157606754d9.jpeg

Keras 读取结果

对于上面的示例,我们获得了所有尺寸及其边界框。计算出边界框后,我们可以将它们放入一个区域并根据该区域进行匹配。

annot_centers = []
readings = [value[0] for value in prediction]
value_center_list = []for box in boxes:x_center = []y_center = []x_sum = 0y_sum = 0for point in box:x_sum += point[0]y_sum += point[1]x_center = int(x_sum/4)y_center = int(y_sum/4)value_center_list.append([x_center, y_center])for i in range(len(value_center_list)):value_center_list[i].append(readings[i])

简而言之,我们假设 y 轴注释位于左四分之一或右四分之一。x 轴注释的方法相同,如果它位于顶部或底部四分之一,我们可以假设它与 x 轴相关。

唯一的例外是中间,如果它的位置不在上述任何区域中,我们将指定该读数作为腹板厚度。

最后,下面的代码块根据分配的属性进行计算。

# Moment of inertia calculations
total_shape_area = (t_web*h_web) + (top_t_flange * b_flange) + (bottom_t_flange * b_flange)# Datum assumed as top left of the shape
# Strong axis will be taken as x axis, so week axis will be y axis
area_moments_x = (top_t_flange * b_flange) * (top_t_flange/2) + (t_web*h_web)*(h_web/2 + top_t_flange)+ (bottom_t_flange * b_flange) * (top_t_flange + h_web + bottom_t_flange/2)
center_of_gravity_x = area_moments_x / total_shape_area
area_moments_y = (top_t_flange * b_flange) * (b_flange/2) + (t_web*h_web)*(b_flange/2)+ (bottom_t_flange * b_flange) * (b_flange/2)
center_of_gravity_y = area_moments_y / total_shape_area# These values are obvious for symmetrical shapes, but just for different cases these should be calculated
moment_of_inertia_x = (1/12) * b_flange * top_t_flange**3 + (top_t_flange * b_flange) * (center_of_gravity_x - top_t_flange/2)**2 + (1/12)* t_web * h_web**3 + (t_web * h_web) * (center_of_gravity_x - (top_t_flange + h_web/2))**2 + (1/12) * b_flange * bottom_t_flange**3 + (b_flange * bottom_t_flange) * ((top_t_flange + h_web + bottom_t_flange/2) - center_of_gravity_x)**2

结果

我们可以使用深度学习和图像处理技术解决钢结构问题,但需要一定的投资。还有其他类型的图纸可以处理,但由于时间和精力所限,这里就不一一列举了。通过一些更改,这项工作可以应用于许多不同的领域。

参考

  • https://arxiv.org/ftp/arxiv/papers/2205/2205.02659.pdf

  • https://arxiv.org/pdf/1506.01497.pdf

☆ END ☆

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

扫描二维码添加小编↓

2fe78172b63a443756d0d0868a4d922b.jpeg

相关文章:

使用 TensorFlow、Keras-OCR 和 OpenCV 从技术图纸中获取信息

简单介绍输入是技术绘图图像。对象检测模型获取图像后对其进行分类,找到边界框,分配维度,计算属性。示例图像(输入)分类后,找到“IPN”部分。之后,它计算属性,例如惯性矩。它适用于不…...

ESP32设备驱动-GUVA-S12SD紫外线检测传感器驱动

GUVA-S12SD紫外线检测传感器驱动 文章目录 GUVA-S12SD紫外线检测传感器驱动1、GUVA-S12SD介绍2、硬件准备3、软件准备4、驱动实现1、GUVA-S12SD介绍 GUVA-S12SD 紫外线传感器芯片适用于检测太阳光中的紫外线辐射。 它可用于任何需要监控紫外线量的应用,并且可以简单地连接到任…...

WIN7下 program file 权限不足?咋整?!!

在WIN7下对Program Files目录的权限问题 [问题点数:40分,结帖人mysunck] 大部分人说要使用manifest,但是其中一个人说: “安装程序要求管理员很正常,你的程序可以在programfiles,但用户数据不能放那里,因…...

119.(leaflet篇)文字碰撞

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>...

cuda编程以及GPU基本知识

目录CPU与GPU的基本知识CPU特点GPU特点GPU vs. CPU什么样的问题适合GPU&#xff1f;GPU编程CUDA编程并行计算的整体流程CUDA编程术语&#xff1a;硬件CUDA编程术语&#xff1a;内存模型CUDA编程术语&#xff1a;软件线程块&#xff08;Thread Block&#xff09;网格&#xff08…...

Python 机器学习/深度学习/算法专栏 - 导读目录

目录 一.简介 二.机器学习 三.深度学习 四.数据结构与算法 五.日常工具 一.简介 Python 机器学习、深度学习、算法主要是博主从研究生到工作期间接触的一些机器学习、深度学习以及一些算法的实现的记录&#xff0c;从早期的 LR、SVM 到后期的 Deep&#xff0c;从学习到工…...

Springboot怎么实现restfult风格Api接口

前言在最近的一次技术评审会议上&#xff0c;听到有同事发言说&#xff1a;“我们的项目采用restful风格的接口设计&#xff0c;开发效率更高&#xff0c;接口扩展性更好...”&#xff0c;当我听到开头第一句&#xff0c;我脑子里就开始冒问号&#xff1a;项目里的接口用到的是…...

Jetpack Compose 深入探索系列六:Compose runtime 高级用例

Compose runtime vs Compose UI 在深入讨论之前&#xff0c;非常重要的一点是要区分 Compose UI 和 Compose runtime。Compose UI 是 Android 的新 UI 工具包&#xff0c;具有 LayoutNodes 的树形结构&#xff0c;它们稍后在画布上绘制其内容。Compose runtime 提供底层机制和…...

23.3.2 Codeforces Round #834 (Div. 3) A~E

FG明天补 A-Yes-Yes? 题面翻译 给定 ttt 个字符串&#xff0c;请判定这些字符串是否分别是 YesYesYesYes…\texttt{YesYesYesYes\dots}YesYesYesYes… 的子串。是则输出 YES&#xff0c;否则输出 NO&#xff08;YES 和 NO 大小写不定&#xff09;。 Translated by JYqwq …...

一次失败的面试经历:我只想找个工作,你却用面试题羞辱我!

金三银四近在咫尺&#xff0c;即将又是一波求职月&#xff0c;面对跳槽的高峰期&#xff0c;很多软件测试人员都希望能拿一个满意的高薪offer&#xff0c;但是随着招聘职位的不断增多&#xff0c;面试的难度也随之加大&#xff0c;而面试官更是会择优录取小王最近为面试已经焦头…...

java版工程管理系统 Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码

java版工程管理系统Spring CloudSpring BootMybatis实现工程管理系统 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和…...

附录3-大事件项目后端-项目准备工作,config.js,一些库的简易用法,main.js

目录 1 一些注意 2 创建数据库 3 项目结构 4 配置文件 config.js 5 参数规则包 hapi/joi与escook/express-joi 5.1 安装 5.2 文档中的demo 5.2.1 定义规则 5.2.2 使用规则 5.3 项目中的使用 5.3.1 定义信息规则 5.3.2 使用规则 6 密码加密包 bcrypt.…...

并发编程-线程

并发编程-线程 一个进程是操作系统中运行的一个任务&#xff0c;进程独立拥有CPU、内存等资源一个线程是一个进程中运行的一个任务&#xff0c;线程之间共享CPU、内存等资源&#xff0c;进程里的每一个任务都是线程。 线程创建 创建线程&#xff1a;使用threading模块中的Th…...

图解LeetCode——剑指 Offer 34. 二叉树中和为某一值的路径

一、题目 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。叶子节点 是指没有子节点的节点。 二、示例 2.1> 示例 1&#xff1a; 【输入】root [5,4,8,11,null,13,4,7,2,null,null,5,1], t…...

使用Python免费试用最新Openai API

一、背景介绍 3月2日凌晨&#xff0c;OpenAI放出了真正的ChatGPT API&#xff0c;不是背后的GPT-3.5大模型&#xff0c;是ChatGPT的本体模型&#xff01;ChatGPT API价格为1k tokens/$0.002&#xff0c;等于每输出100万个单词&#xff0c;价格才2.7美金&#xff08;约18元人民…...

04、启动 SVN 服务器端程序

启动 SVN 服务器端程序1 概述2 用命令行单项目启动2.1 采用 svnserve 命令2.2 验证服务是否启动2.3 命令行方式的缺陷3 注册Windows服务3.1 注册服务的命令3.2 命令说明3.3 启动服务1 概述 SVN 服务器和 Tomcat 服务器&#xff0c;Nexus 服务器一样, 必须处于运行状态才能响应…...

jsp船舶引航计费网站Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP船舶引航计费网站是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…...

Allegro如何画半圆形的线操作指导

Allegro如何画半圆形的线操作指导 在用Allegro设计PCB的时候,在某些应用场合会需要画半圆形,如下图 如何画半圆形,具体操作如下 点击Add点击Arc w/Radius...

【强烈建议收藏:MySQL面试必问系列之SQL语句执行专题】

一.知识回顾 之前的文章我们一起学习了MySQL面试必问系列之事务专题、锁专题&#xff0c;没有学习的小伙伴可以直接通过该链接地址直接访问&#xff0c;MYSQL你真的了解吗专栏的文章&#xff0c;接下来我们就一起来学习一下MySQL中SQL语句的执行流程&#xff0c;看看你掌握的怎…...

详解Linux下的环境变量以及C++库文件和头文件、python库的配置

目录 Linux环境变量配置基本步骤 1.查看环境变量 2.设置环境变量 3.永久性设置环境变量 4.使用环境变量 C 库文件和头文件环境变量配置 1.配置so库文件的环境变量 2.配置头文件的环境变量 Python库环境变量配置 Linux配置执行文件环境变量 我们都习惯在Windows 上配置…...

企业级分布式数据库 - GaussDB介绍

目录 什么是GaussDB 简介 应用场景 产品架构 产品优势 安全 责任共担 身份认证与访问控制 数据保护技术 审计与日志 ​​​​​​​监控安全风险 ​​​​​​​故障恢复 ​​​​​​​认证证书 GaussDB与其他服务的关系 约束与限制 计费模式 什么是GaussDB …...

Linux I2C 驱动实验

目录 一、Linux I2C 驱动简介 1、I2C 总线驱动 2、I2C 设备驱动 1、 i2c_client 结构体 2、 i2c_driver 结构体 二、硬件分析 三、设备树编写 1、pinctrl_i2c1 2、在 i2c1 节点追加 ap3216c 子节点 3、验证 四、 代码编写 1、makefile 2、ap3216c.h 3、ap3216c.c …...

DC-DC模块电源隔离直流升压高压稳压输出5v12v24v转60v100v110v150v220v250v300v400v500v

特点效率高达80%以上1*1英寸标准封装单电压输出稳压输出工作温度: -40℃~85℃阻燃封装&#xff0c;满足UL94-V0 要求温度特性好可直接焊在PCB 上应用HRB 0.2~10W 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为&#xff1a;4.5~9V、9~18V、及18~36VDC标准&#…...

EF有几种模式,EF的三种模式分别是什么?

EF有几种模式&#xff0c;EF的三种模式分别是什么&#xff1f; 第一种&#xff1a;DataBase First DataBase First传统的表驱动方式创建EDM&#xff0c;然后通过EDM生成模型和数据层代码。除生成实体模型和自跟踪实现模型&#xff0c;还支持生成轻型DbContext。 解释&#xf…...

数据可视化展示:打工人常见职业病,颈腰椎病占比最高达66.51%

身体健康才是一切的根本。只有身体健健康康才能更好的去享受世间的美好&#xff0c;无论是谁都应当注重身体健康&#xff0c;而不是无度的挥霍它&#xff01; 良好的身体&#xff0c;释放给工作&#xff0c;健壮的体魄&#xff0c;享受美好生活&#xff0c;良好的心态&#xff…...

【食品图像识别】Large Scale Visual Food Recognition

1 引言 视觉智能部与中科院计算所于2020-2021年度展开了《细粒度菜品图像识别和检索》科研课题合作&#xff0c;本文系双方联合在IEEE T-PAMI2023发布论文《Large Scale Visual Food Recognition》 (Weiqing Min, Zhiling Wang, Yuxin Liu, Mengjiang Luo, Liping Kang, Xiaom…...

RAN-in-the-Cloud:为 5G RAN 提供云经济性

RAN-in-the-Cloud&#xff1a;为 5G RAN 提供云经济性 5G 部署在全球范围内一直在加速。 许多电信运营商已经推出了5G服务并正在快速扩张。 除了电信运营商之外&#xff0c;企业也对使用 5G 建立私有网络产生了浓厚的兴趣&#xff0c;这些私有网络利用了更高的带宽、更低的延迟…...

vector、list、queue

引用&#xff1a;windows程序员面试指南 vector vector 类似于C语言中的数组 vector 支持随机访问&#xff0c;访问某个元素的时间复杂度 O(1) vector 插入和删除元素效率较低&#xff0c;时间复杂度O(n) vector 是连续存储&#xff0c;没有内存碎片&#xff0c;空间利用率高…...

操作系统面经

进程与线程区别 1.进程是资源分配的最小单位&#xff0c;线程是程序执行的最小单位&#xff08;资源调度的最小单位&#xff09; 2.进程有自己的独立地址空间&#xff0c;每启动一个进程&#xff0c;系统就会为它分配地址空间&#xff0c;建立数据表来维护代码段、堆栈段和数…...

一天约了4个面试,复盘一下面试题和薪资福利

除了最新的面经分享&#xff0c;还有字节大佬的求职面试答疑&#xff0c;告诉你关键问题是什么&#xff1f;少走弯路。**另外本文也汇总了6份大厂面试题&#xff1a;字节、腾讯、小米、腾讯云、滴滴、小米游戏。**希望对大家有帮助。 前言 昨天我的交流群里&#xff0c;有位宝…...

天津网站建设 文率科技/怎么弄推广广告

0. 前言 听了实验室6位老师的讲座之后&#xff0c;对老师们的研究内容有了基本的认识。下面将对这6次的内容做个总结。 1. 主动学习 主动学习方法&#xff0c;是指能够从任务出发&#xff0c;通过对任务的理解来制定标准&#xff0c;挑选最关键的样本&#xff0c;使其最有助于…...

英语网站大全免费/市场调研报告怎么写的

使用JavaScript开发IE浏览器本地插件实例 投稿&#xff1a;junjie 字体&#xff1a;[增加 减小] 类型&#xff1a;转载 时间&#xff1a;2015-02-18 我要评论 这篇文章主要介绍了使用JavaScript开发IE浏览器本地插件实例,本文讲解使用JS注册表的方式开发一个IE浏览器本地插件,需…...

模板手机网站建设多少钱/郑州竞价代运营公司

撰文 | JZ专栏 | 九章算法题目描述 有一个集合组成的list&#xff0c;如果有两个集合有相同的元素&#xff0c;将他们合并。返回最后还剩下几个集合。 思路点拨 先遍历所有元素&#xff0c;以元素为key&#xff0c;元素所属的集合id为value(是一个集合)建立hashmap&#xff0…...

视频网站如何做盗链/威海网站制作

文章目录1 报错2 解决办法1 报错 尝试在linux上通过Pycharm IDE使用matplotlib包。当我运行此代码时&#xff1a; from matplotlib import pyplot结果报错&#xff1a; ImportError: No module named tkinter2 解决办法 ubuntu的系统&#xff1a; sudo apt-get install py…...

网站设计赚钱吗/软文推广是什么

《一个Android工程的从零开始》-1前期准备 先扯两句 很早就在CSDN上看各路大神发的博客&#xff0c;可以说我今天没饿死&#xff0c;很大程度上&#xff0c;也正是得益于各路大神的无私分享。 一想到从今天起&#xff0c;自己也能发些东西出来&#xff0c;或许可以帮到哪些人…...

有哪些网站可以做图片打赏/郑州百度推广外包

qDeleteAll&#xff1a;专门用于指针容器&#xff0c;对容器或者迭代器中的每个对象进行delete操作&#xff0c;而不是从容器中移除对象。源代码如下&#xff1a; void qDeleteAll(ForwardIterator begin, ForwardIterator end) { while (begin ! end) { delete *begin; begin;…...