利用计算机视觉算法提取裂纹相关特征参数信息

ABCnutter/CrackFeature: 🚀使用计算机视觉相关算法提取裂缝的骨架(矢量化)、轮廓【支持提前修复断裂裂缝】,以及几何特征参数(长度、宽度、面积和主要方向)【欢迎Star】。主要流程以及相关算法如下:

注意:要求输入为裂缝提取结果的二值图像!

代码如下:

import os
import math
from tqdm import tqdm
import numpy as np
import matplotlib.pyplot as plt
from skimage import io
from skimage.measure import find_contours, regionprops, label
from skimage.morphology import skeletonize, closing, square
from sklearn.neighbors import KDTreedef load_image_list(image_dir):if not os.path.exists(image_dir):raise FileNotFoundError("image_dir not found!")image_path_list = []image_name_list = []for img in os.listdir(image_dir):image_path_list.append(os.path.join(image_dir, img))image_name_list.append(img)return image_path_list, image_name_listdef SVD(points):# 二维,三维均适用# 二维直线,三维平面pts = points.copy()# 奇异值分解c = np.mean(pts, axis=0)A = pts - c  # shift the pointsA = A.T  # 3*nu, s, vh = np.linalg.svd(A, full_matrices=False, compute_uv=True)  # A=u*s*vhnormal = u[:, -1]# 法向量归一化nlen = np.sqrt(np.dot(normal, normal))normal = normal / nlen# normal 是主方向的方向向量 与PCA最小特征值对应的特征向量是垂直关系# u 每一列是一个方向# s 是对应的特征值# c >>> 点的中心# normal >>> 拟合的方向向量return u, s, c, normaldef calcu_dis_from_ctrlpts(ctrlpts):if ctrlpts.shape[1] == 4:return np.sqrt(np.sum((ctrlpts[:, 0:2] - ctrlpts[:, 2:4]) ** 2, axis=1))else:return np.sqrt(np.sum((ctrlpts[:, [0, 2]] - ctrlpts[:, [3, 5]]) ** 2, axis=1))def get_crack_ctrlpts(centers, normals, bpoints, hband=5, vband=2, est_width=0):# main algorithm to obtain crack widthcpoints = np.copy(centers)cnormals = np.copy(normals)xmatrix = np.array([[0, 1], [-1, 0]])cnormalsx = np.dot(xmatrix, cnormals.T).T  # the normal of x axisN = cpoints.shape[0]interp_segm = []widths = []for i in range(N):try:ny = cnormals[i]nx = cnormalsx[i]tform = np.array([nx, ny])bpoints_loc = np.dot(tform, bpoints.T).Tcpoints_loc = np.dot(tform, cpoints.T).Tci = cpoints_loc[i]bl_ind = (bpoints_loc[:, 0] - (ci[0] - hband)) * (bpoints_loc[:, 0] - ci[0]) < 0br_ind = (bpoints_loc[:, 0] - ci[0]) * (bpoints_loc[:, 0] - (ci[0] + hband)) <= 0bl = bpoints_loc[bl_ind]  # left pointsbr = bpoints_loc[br_ind]  # right pointsif est_width > 0:# 下面的数值 est_width 是预估计的裂缝宽度half_est_width = est_width / 2blt = bl[(bl[:, 1] - (ci[1] + half_est_width)) * (bl[:, 1] - ci[1]) < 0]blb = bl[(bl[:, 1] - (ci[1] - half_est_width)) * (bl[:, 1] - ci[1]) < 0]brt = br[(br[:, 1] - (ci[1] + half_est_width)) * (br[:, 1] - ci[1]) < 0]brb = br[(br[:, 1] - (ci[1] - half_est_width)) * (br[:, 1] - ci[1]) < 0]else:blt = bl[bl[:, 1] > np.mean(bl[:, 1])]if np.ptp(blt[:, 1]) > vband:blt = blt[blt[:, 1] > np.mean(blt[:, 1])]blb = bl[bl[:, 1] < np.mean(bl[:, 1])]if np.ptp(blb[:, 1]) > vband:blb = blb[blb[:, 1] < np.mean(blb[:, 1])]brt = br[br[:, 1] > np.mean(br[:, 1])]if np.ptp(brt[:, 1]) > vband:brt = brt[brt[:, 1] > np.mean(brt[:, 1])]brb = br[br[:, 1] < np.mean(br[:, 1])]if np.ptp(brb[:, 1]) > vband:brb = brb[brb[:, 1] < np.mean(brb[:, 1])]t1 = blt[np.argsort(blt[:, 0])[-1]]t2 = brt[np.argsort(brt[:, 0])[0]]b1 = blb[np.argsort(blb[:, 0])[-1]]b2 = brb[np.argsort(brb[:, 0])[0]]interp1 = (ci[0] - t1[0]) * ((t2[1] - t1[1]) / (t2[0] - t1[0])) + t1[1]interp2 = (ci[0] - b1[0]) * ((b2[1] - b1[1]) / (b2[0] - b1[0])) + b1[1]if interp1 - ci[1] > 0 and interp2 - ci[1] < 0:widths.append([i, interp1 - ci[1], interp2 - ci[1]])interps = np.array([[ci[0], interp1], [ci[0], interp2]])interps_rec = np.dot(np.linalg.inv(tform), interps.T).Tinterps_rec = interps_rec.reshape(1, -1)[0, :]interp_segm.append(interps_rec)except:print("the %d-th was wrong" % i)continueinterp_segm = np.array(interp_segm)widths = np.array(widths)return interp_segm, widthsdef estimate_normal_for_pos(pos, points, n):# estimate normal vectors at a given pointpts = np.copy(points)tree = KDTree(pts, leaf_size=2)idx = tree.query(pos, k=n, return_distance=False, dualtree=False, breadth_first=False)normals = []for i in range(0, pos.shape[0]):pts_for_normals = pts[idx[i, :], :]_, _, _, normal = SVD(pts_for_normals)normals.append(normal)normals = np.array(normals)return normalsdef estimate_normals(points, n):pts = np.copy(points)tree = KDTree(pts, leaf_size=2)idx = tree.query(pts, k=n, return_distance=False, dualtree=False, breadth_first=False)normals = []for i in range(0, pts.shape[0]):pts_for_normals = pts[idx[i, :], :]_, _, _, normal = SVD(pts_for_normals)normals.append(normal)normals = np.array(normals)return normalsdef close_skeleton_contour(image_path, square_value, contours_value):image = io.imread(image_path)if len(image.shape) != 2:raise ValueError(f"Please check input images, guaranteed to be a single-channel image!")image[image != 0] = 1# 使用闭运算填充小孔和连接小块closed_image = closing(image, square(square_value))skeleton_zha = skeletonize(closed_image)# skeleton_lee = skeletonize(closed_image, method="lee")# 提取轮廓contours = find_contours(closed_image, contours_value)# 创建一个空白图像contour_image = np.zeros_like(image)# 在空白图像上绘制轮廓for contour in contours:contour_image[np.round(contour[:, 0]).astype(int), np.round(contour[:, 1]).astype(int)] = 1skeleton_zha_contour_image = np.zeros((3, image.shape[0], image.shape[1]), dtype=np.uint8)skeleton_zha_contour_image[0, skeleton_zha] = 255for contour in contours:skeleton_zha_contour_image[1, np.round(contour[:, 0]).astype(int), np.round(contour[:, 1]).astype(int)] = 255# skeleton_zha_contour_image[1, contour_image] = 255skeleton_zha_contour_image = np.transpose(skeleton_zha_contour_image, (1, 2, 0))# skeleton_lee_contour_image = np.zeros(#     (3, image.shape[0], image.shape[1]), dtype=np.uint8# )# skeleton_lee_contour_image[0, skeleton_lee] = 255# for contour in contours:#     skeleton_lee_contour_image[#         1, np.round(contour[:, 0]).astype(int), np.round(contour[:, 1]).astype(int)#     ] = 255# # skeleton_lee_contour_image[1, contour_image] = 255# skeleton_lee_contour_image = np.transpose(skeleton_lee_contour_image, (1, 2, 0))return (image,closed_image,skeleton_zha,# skeleton_lee,contour_image,skeleton_zha_contour_image,# skeleton_lee_contour_image,)def calculate_crack_length(skeletons, scale_factor):# 标记连通区域labeled_skeletons = label(skeletons)# 存储所有裂隙的像素坐标、微分裂隙的长度和像素个数all_crack_coordinates = []all_crack_lengths = []all_crack_pixel_counts = []# 处理每个连通域for skeleton_idx in range(1, np.max(labeled_skeletons) + 1):  # 从1开始,因为0表示背景# 提取当前连通域的骨架current_skeleton = (labeled_skeletons == skeleton_idx).astype(np.uint8)# # 提取当前骨架的坐标和像素个数coords = np.column_stack(np.where(current_skeleton))pixel_count = np.sum(current_skeleton)# 提取当前骨架的轮廓contour = find_contours(current_skeleton, level=0.5)[0]# 裂隙的像素坐标crack_coordinates = np.round(contour).astype(int)# # 微分法求取单条裂隙的长度# dx = np.diff(crack_coordinates[:, 1])# dy = np.diff(crack_coordinates[:, 0])# distances = np.sqrt(dx**2 + dy**2)total_length = np.sum(current_skeleton) * scale_factor# 将每一微分段裂隙单元的长度进行累加,得到单条裂隙的总长度# total_length = np.sum(distances)# 根据比例缩放# total_length *= scale_factorprint(f"crack connected domain-{skeleton_idx} average lengths:{total_length}")# 存储当前裂隙的信息all_crack_coordinates.append(crack_coordinates)all_crack_pixel_counts.append(pixel_count)all_crack_lengths.append([skeleton_idx, total_length])all_crack_average_lengths = np.sum(all_crack_lengths) / len(all_crack_lengths)print(f"crack average lengths:{all_crack_average_lengths}")return (all_crack_coordinates,all_crack_lengths,all_crack_pixel_counts,all_crack_average_lengths,)# # 将每一微分段骨架单元的长度进行累加,得到骨架的总长度# total_length = np.sum(skeleton) * scale_factor# # total_length = np.sum(distances)# return total_lengthdef calculate_crack_width(image,skeletons,scale_factor,tree_n=3,find_contours_level=0.5,hband=5,vband=5,est_width=50,
):# 标记连通区域labeled_skeletons = label(skeletons)# 存储所有裂隙的像素坐标、微分裂隙的长度和像素个数all_crack_interps = []all_crack_widths = []all_connected_domain_widths = []# 处理每个连通域for skeleton_idx in range(1, np.max(labeled_skeletons) + 1):  # 从1开始,因为0表示背景# 提取当前连通域的骨架current_skeleton = (labeled_skeletons == skeleton_idx).astype(np.uint8)# 提取当前骨架的坐标和像素个数coords = np.column_stack(np.where(current_skeleton))pixel_count = np.sum(current_skeleton)normals = estimate_normals(coords, tree_n)# 提取当前连通域的轮廓labeled_images = label(image)if np.max(labeled_skeletons) != np.max(labeled_images):raise ValueError(f"the number of images != the number of skeletons")current_connected_domain_coords = np.column_stack(np.where((labeled_images == skeleton_idx).astype(np.uint8)))current_connected_domain = np.zeros_like(labeled_images)current_connected_domain[current_connected_domain_coords[:, 0], current_connected_domain_coords[:, 1]] = 1contours = find_contours(current_connected_domain, level=find_contours_level)bpoints = np.vstack(contours)interps, widths = get_crack_ctrlpts(coords, normals, bpoints, hband, vband, est_width)# print(widths)# if len(widths) == 0 or len(interps) == 0:per_crack_widths = np.sum(np.abs(widths[:, 1:]), axis=1)# 计算当前裂缝连通域的宽度平均值average_crack_widths = np.sum(per_crack_widths) / len(widths) * scale_factorprint(f"crack connected domain-{skeleton_idx} average widths:{average_crack_widths}")all_crack_interps.append(interps)all_crack_widths.append(widths)all_connected_domain_widths.append([skeleton_idx, average_crack_widths])# 计算图像中的所有裂缝的宽度平均值all_average_crack_widths = np.sum(np.array(all_connected_domain_widths)[:, 1]) / len(all_connected_domain_widths)print(f"crack average widths:{all_average_crack_widths}")return (all_crack_interps,all_crack_widths,all_connected_domain_widths,all_average_crack_widths,)def draw_widths(image, interps, show_points_nums, save_dir, image_name, plugin):# inters 为 all_crack_interpsfig, ax = plt.subplots()for interp in interps:show_points_nums_copy = np.copy(show_points_nums)if interp.shape[0] < show_points_nums_copy:show_points_nums_copy = interp.shape[0]interps_show = interp[np.random.choice(interp.shape[0], show_points_nums_copy, replace=False), :]for i in range(interps_show.shape[0]):ax.plot([interps_show[i, 1], interps_show[i, 3]],[interps_show[i, 0], interps_show[i, 2]],c="c",ls="-",lw=2,marker="o",ms=4,mec="c",mfc="c",)ax.imshow(image)# 设置坐标轴不可见ax.axis("off")# 调整子图的间距,使得图像紧凑显示plt.subplots_adjust(left=0, right=1, top=1, bottom=0)save_file_dir = os.path.join(save_dir, image_name.split(".")[0])if not os.path.exists(save_file_dir):os.makedirs(save_file_dir)plt.savefig(os.path.join(save_file_dir, image_name.split(".")[0] + f"{plugin}.png"),bbox_inches="tight",pad_inches=0,)# 显示结果# plt.show()def radians_to_degrees_minutes_seconds(angle_radians):# 转换弧度为度angle_degrees = math.degrees(angle_radians)# 提取度、分、秒degrees = int(angle_degrees)remainder_minutes = (angle_degrees - degrees) * 60minutes = int(remainder_minutes)seconds = (remainder_minutes - minutes) * 60return degrees, minutes, secondsdef estimate_crack_direction(image):# 标记裂缝连通域labeled_image = label(image)# 存储裂缝的法线方向和椭圆信息crack_connected_domain_directions = []# 处理每个连通域for region in regionprops(labeled_image):current_crack_direction = region.orientationdegrees, minutes, seconds = radians_to_degrees_minutes_seconds(current_crack_direction)print(f"{region.label}-{current_crack_direction}-子连通域弧度对应的度分秒为:{degrees}° {minutes}' {seconds}\"")crack_connected_domain_directions.append([region.label, current_crack_direction, degrees, minutes, seconds])# 计算图像中的所有裂缝的面积平均值all_average_crack_directions = np.sum(np.array(crack_connected_domain_directions)[:, 1]) / len(crack_connected_domain_directions)all_average_degrees, all_average_minutes, all_average_seconds = (radians_to_degrees_minutes_seconds(all_average_crack_directions))print(f"整体平均弧度-{all_average_crack_directions}-对应的度分秒为:{all_average_degrees}° {all_average_minutes}' {all_average_seconds}\"")all_average_crack_direction = [all_average_crack_directions,all_average_degrees,all_average_minutes,all_average_seconds,]return crack_connected_domain_directions, all_average_crack_directiondef extract_crack_areas(image, scale_factor=1):# 标记裂缝连通域labeled_image = label(image)# 存储裂缝的法线方向和椭圆信息crack_connected_domain_areas = []# 处理每个连通域for region in regionprops(labeled_image):crack_area = region.area * (scale_factor * scale_factor)print(f'{region.label}-子连通域面积为:{crack_area}"')crack_connected_domain_areas.append([region.label, crack_area])# 计算图像中的所有裂缝的面积平均值all_average_crack_areas = np.sum(np.array(crack_connected_domain_areas)[:, 1]) / len(crack_connected_domain_areas)print(f"crack average areas:{all_average_crack_areas}")return crack_connected_domain_areas, all_average_crack_areasdef save_results(save_dir, image_name, image, plugin):save_file_dir = os.path.join(save_dir, image_name.split(".")[0])if not os.path.exists(save_file_dir):os.makedirs(save_file_dir)io.imsave(fname=os.path.join(save_file_dir, image_name.split(".")[0] + f"{plugin}.png"),arr=image,)def extract_crack_feature_parameters(image_dir,save_dir,square_value,contours_value,scale_factor,tree_n=3,find_contours_level=0.5,hband=5,vband=5,est_width=50,show_points_nums=50,
):img_path_list, img_name_list = load_image_list(image_dir)for img_path, img_name in tqdm(zip(img_path_list, img_name_list)):try:print(f"***************************************************************************************************")print(f"**************************************** {img_name} BEGIN! ****************************************")print(f"***************************************************************************************************")########################################## calculate_crack_closed_skeleton ##########################################(image,closed_image,skeleton_zha,# skeleton_lee,contour_image,skeleton_zha_contour_image,# skeleton_lee_contour_image,) = close_skeleton_contour(img_path, square_value, contours_value)save_results(save_dir, img_name, image * 255, "_image")save_results(save_dir, img_name, closed_image * 255, "_closed_image")save_results(save_dir, img_name, skeleton_zha, "_skeleton_zha")# save_results(save_dir, img_name, skeleton_lee * 255, "_skeleton_lee")save_results(save_dir, img_name, contour_image * 255, "_contour_image")save_results(save_dir,img_name,skeleton_zha_contour_image,"_skeleton_zha_contour_image",)# save_results(save_dir, img_name, skeleton_lee_contour_image, '_skeleton_lee_contour_image')save_file_dir = os.path.join(save_dir, img_name.split(".")[0])if not os.path.exists(save_file_dir):os.makedirs(save_file_dir)########################################## calculate_crack_length ##########################################(all_crack_coordinates,all_crack_lengths,all_crack_pixel_counts,all_crack_average_lengths,) = calculate_crack_length(skeleton_zha, scale_factor)# 将lengths逐行写入文本文件with open(f"{save_file_dir}/{img_name}_crack_length.txt", "w") as file:for row in all_crack_lengths:file.write("_crack_connected_domain_average_length: ".join(map(str, row))+ "\n")file.write(f"total figure crack average length: {all_crack_average_lengths}")########################################## calculate_crack_width ##########################################print(f"{img_name} BEGIN!")(all_crack_interps,all_crack_widths,all_connected_domain_widths,all_average_crack_widths,) = calculate_crack_width(closed_image,skeleton_zha,scale_factor,tree_n,find_contours_level,hband,vband,est_width,)# 将widths逐行写入文本文件with open(f"{save_file_dir}/{img_name}_crack_width.txt", "w") as file:for row in all_connected_domain_widths:file.write("_crack_connected_domain_average_width: ".join(map(str, row))+ "\n")file.write(f"total figure crack average width: {all_average_crack_widths}")draw_widths(skeleton_zha_contour_image,all_crack_interps,show_points_nums,save_dir,img_name,"_width",)########################################## calculate_crack_direction ##########################################crack_connected_domain_directions, all_average_crack_direction = (estimate_crack_direction(closed_image))# 将direction逐行写入文本文件with open(f"{save_file_dir}/{img_name}_crack_direction.txt", "w") as file:for row in crack_connected_domain_directions:file.write(f"{row[0]}_crack_connected_domain_average_direction:{row[1]} --- 对应的度分秒为:{row[2]}° {row[3]}' {row[4]}\""+ "\n")file.write(f"total figure crack average direction: {all_average_crack_direction[0]} --- 对应的度分秒为:{all_average_crack_direction[1]}° {all_average_crack_direction[2]}' {all_average_crack_direction[3]}")########################################## calculate_crack_area ##########################################crack_connected_domain_areas, all_average_crack_areas = extract_crack_areas(closed_image, scale_factor)# 将area逐行写入文本文件with open(f"{save_file_dir}/{img_name}_crack_area.txt", "w") as file:for row in crack_connected_domain_areas:file.write("_crack_connected_domain_average_area: ".join(map(str, row))+ "\n")file.write(f"total figure crack average area: {all_average_crack_areas}")print(f"####################################################################################################")print(f"######################################### {img_name} OVER! #########################################")print(f"####################################################################################################")except:import logginglogging.error(f"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  {img_name} exists wrong  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")continueif __name__ == "__main__":import configparser# 将参数保存到配置文件config = configparser.ConfigParser()config["Parameters"] = {"square_value": "20","contours_value": "0.8","scale_factor": "2.6","tree_n": "3","find_contours_level": "0.5","hband": "5","vband": "5","est_width": "30","show_points_nums": "150","image_dir": "test",  # 存放所有裂缝二值图片的文件夹"save_dir": "results",}# 保存配置文件# 保存配置文件到 save_dir 路径下save_file_dir = config["Parameters"]["save_dir"]if not os.path.exists(save_file_dir):os.makedirs(save_file_dir)config_file_path = os.path.join(config["Parameters"]["save_dir"], "config.ini")with open(config_file_path, "w") as configfile:config.write(configfile)# 读取配置文件中的参数config = configparser.ConfigParser()config.read(config_file_path)square_value = int(config["Parameters"]["square_value"])contours_value = float(config["Parameters"]["contours_value"])scale_factor = float(config["Parameters"]["scale_factor"])tree_n = int(config["Parameters"]["tree_n"])find_contours_level = float(config["Parameters"]["find_contours_level"])hband = int(config["Parameters"]["hband"])vband = int(config["Parameters"]["vband"])est_width = int(config["Parameters"]["est_width"])show_points_nums = int(config["Parameters"]["show_points_nums"])image_dir = config["Parameters"]["image_dir"]save_dir = config["Parameters"]["save_dir"]# 然后在你的函数中使用这些参数extract_crack_feature_parameters(image_dir,save_dir,square_value,contours_value,scale_factor,tree_n,find_contours_level,hband,vband,est_width,show_points_nums,)

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

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

相关文章

zato,一个神奇的 Python 库!

大家好&#xff0c;今天为大家分享一个神奇的 Python 库 - zato。 Zato是一个高性能的Python企业服务总线(ESB)和应用集成框架&#xff0c;专为简化复杂系统间的通信和数据交换而设计。它提供了一个灵活、可扩展的平台&#xff0c;以支持各种集成需求&#xff0c;从简单的数据传…

Android Studio 之 Intent及其参数传递

一、Intent 显式Intent&#xff1a;通过组件名指定启动的目标组件,比如startActivity(new Intent(A.this,B.class)); 每次启动的组件只有一个~隐式Intent:不指定组件名,而指定Intent的Action,Data,或Category,当我们启动组件时, 会去匹配AndroidManifest.xml相关组件的Intent-…

代码随想录——动态规划

系列文章目录 代码随想录——回溯 代码随想录——贪心算法 代码随想录——动态规划 文章目录 系列文章目录概述简单斐波那契数***爬楼梯***使用最小花费爬楼梯不同路径不同路径 II***整数拆分***不同的二叉搜索树***普通0-1背包***分割等和子集***最后一块石头的重量 II***目标…

内网渗透-内网环境下的横向移动总结

内网环境下的横向移动总结 文章目录 内网环境下的横向移动总结前言横向移动威胁 威胁密码安全 威胁主机安全 威胁信息安全横向移动威胁的特点 利用psexec 利用psexec.exe工具msf中的psexec 利用windows服务 sc命令 1.与靶机建立ipc连接2.拷贝exe到主机系统上3.在靶机上创建一个…

ros-param添加参数控制rviz显示掉帧问题

在ros中有一套参数系统可以直接写到launch文件中&#xff0c;这样非常方便&#xff0c;不需要编译就能直接用&#xff0c;这对于c来说非常的有好&#xff0c;这里记录一下如何使用。 主要步骤如下&#xff1a; 首先初始化节点 使用nodehandle进行管理&#xff0c;然后通过param…

企业常用Linux文件命令相关知识+小案例

远程连接工具无法连接VMWARE&#xff1a; 如果发现连接工具有时连不上&#xff0c;ip存在&#xff0c;这时候我们查看网络编辑器&#xff0c;更多配置&#xff0c;看vnet8是不是10段&#xff0c;nat设置是否是正确的&#xff1f; 软件重启一下虚机还原一下网络编辑器 查看文件…

Windows版PHP7.4.9解压直用(免安装-绿色-项目打包直接使用)

安装版和解压版 区别 安装版: 安装方便&#xff0c;下一步------下一步就OK了&#xff0c;但重装系统更换环境又要重新来一遍&#xff0c;会特别麻烦解压版&#xff08;推荐&#xff09;&#xff1a; 这种方式&#xff08;项目打包特别方便&#xff09;能更深了解mysql的配置&…

LOF 简介

1. 背景 在LOF之前的异常检测算法大多是基于统计方法的&#xff0c;或是借用了一些聚类算法用于异常点的识别(如DBSCAN, OPTICS)。但这些方法都有一些不完美的地方&#xff1a; 1. 基于统计的方法&#xff1a;通常需要假设数据服从特定的概率分布&#xff0c;这个假设往往是不成…

electron项目打包慢、打包报错

项目使用了electron框架&#xff0c;在第一次打包或者网络条件不好的环境下进行打包时熟速度慢的出奇&#xff0c;甚至经常出现打包失败的情况&#xff08;如上面图片的报错&#xff09;。 这是因为&#xff0c;在electron打包的过程中&#xff0c;需要去官方源https://github.…

第十五届蓝桥杯c++b组赛后复盘和真题展示

题目变成八道了&#xff0c;分数一百分可能&#xff0c;感觉拿奖难度还是很高 第一题是一个简单的握手问题 答案算出来1204&#xff0c;纯手写 第二题是 物理题 纯蒙&#xff0c;随便猜了个轨迹&#xff0c;答案具体忘了&#xff0c;最后是 .45 第三题暴力 第四题 我是傻逼…

指针的深入理解(七)

指针的深入理解&#xff08;七&#xff09; 个人主页&#xff1a;大白的编程日记 个人专栏&#xff1a;C语言学习之路 感谢遇见&#xff0c;我们一起学习进步&#xff01; 文章目录 指针的深入理解&#xff08;七&#xff09;前言一.常量字符串指针1.1常量字符串的理解1.2常量…

OneFlow深度学习简介

介绍 OneFlow是一个基于深度学习的开源框架,主要面向机器学习工程师和研究人员。它提供了类似于其他深度学习框架(如TensorFlow和PyTorch)的API,同时具有高性能和高效的特点。OneFlow专注于在大规模数据集和分布式环境下的训练和推理,以及在生产环境中的部署和优化。其设计…

HBuilderX 中开发vue,引入百度地图获取当前ip地址定位

实现功能&#xff1a;使用百度地图获取IP地址&#xff0c;定位到当前位置 参考文档地址&#xff1a;MapVGL | 快速入门 一、在有外网的情况下&#xff0c;常规引入百度地图的方法如下&#xff1a; 1、在index.html中引入 <script src"//api.map.baidu.com/api?v1.…

Python100个库分享第14个—plyfile(将ply文件展示3d模型)

目录 专栏导读库的介绍库的安装ply文件格式介绍ply下载网址&#xff08;是斯坦福大学的3d模型下载网址&#xff09;报错解决完整代码参考&#xff1a;总结 专栏导读 &#x1f338; 欢迎来到Python办公自动化专栏—Python处理办公问题&#xff0c;解放您的双手 &#x1f3f3;️…

C语言单链表详解

链表和顺序表的区别 顺序表的底层存储空间是连续的&#xff0c;链表的底层存储空间是不连续的&#xff0c;链表的每个节点需要额外的指针来指向下一个节点&#xff0c;占用更多的存储空间。 顺序表的随机访问性能好&#xff0c;时间复杂度为O(1)&#xff0c;链表的随机访问性能…

接口优化技巧

一、背景 针对老项目&#xff0c;去年做了许多降本增效的事情&#xff0c;其中发现最多的就是接口耗时过长的问题&#xff0c;就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案 二、接口优化方案总结 1.批处理 批量思想&#xff1a;批量操作数据库&a…

python怎么输出小数

先将整型转换成float型&#xff0c;再进行计算&#xff0c;结果就有小数了。 >>> a 10 >>> b 4 >>> c a/b >>> a,b,c (10, 4, 2) >>> a float(a) >>> d a/b >>> a,b,d (10.0, 4, 2.5) >>> 注意&…

螺栓拧紧工具选择——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 螺栓拧紧工具的选择遵循以下几点&#xff1a; &#xff08;1&#xff09;工艺要求精度。目前拧紧工具有两大类&#xff1a;一类是气动拧紧&#xff1b;另一类是电动拧紧&#xff0c;前者精度较后者精度低&#xff0c;发…

从HashMap了解二叉树、平衡二叉树、红黑树

前言 面试过程中&#xff0c;多多少少会问一点数据结构&#xff08;二叉树&#xff09;的问题&#xff0c;今天我们来复习一下二叉树的相关问题&#xff0c;文末总结。 1. 二叉树的由来 在 jdk1.8 之前&#xff0c;HashMap 的数据结构由「数组链表」组成&#xff0c;数组是 Ha…

免费插件集-illustrator插件-Ai插件-批量替换链接图

文章目录 1.介绍2.安装3.通过窗口>扩展>知了插件4.功能解释5.总结 1.介绍 本文介绍一款免费插件&#xff0c;加强illustrator使用人员工作效率&#xff0c;进行批量替换链接图。首先从下载网址下载这款插件 https://download.csdn.net/download/m0_67316550/87890501&am…