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

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 KDTree


def 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_list


def SVD(points):
    # 二维,三维均适用
    # 二维直线,三维平面
    pts = points.copy()
    # 奇异值分解
    c = np.mean(pts, axis=0)
    A = pts - c  # shift the points
    A = A.T  # 3*n
    u, s, vh = np.linalg.svd(A, full_matrices=False, compute_uv=True)  # A=u*s*vh
    normal = u[:, -1]

    # 法向量归一化
    nlen = np.sqrt(np.dot(normal, normal))
    normal = normal / nlen
    # normal 是主方向的方向向量 与PCA最小特征值对应的特征向量是垂直关系
    # u 每一列是一个方向
    # s 是对应的特征值
    # c >>> 点的中心
    # normal >>> 拟合的方向向量
    return u, s, c, normal


def 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 width
    cpoints = 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 axis
    N = 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).T
            cpoints_loc = np.dot(tform, cpoints.T).T
            ci = cpoints_loc[i]

            bl_ind = (bpoints_loc[:, 0] - (ci[0] - hband)) * (
                bpoints_loc[:, 0] - ci[0]
            ) < 0
            br_ind = (bpoints_loc[:, 0] - ci[0]) * (
                bpoints_loc[:, 0] - (ci[0] + hband)
            ) <= 0
            bl = bpoints_loc[bl_ind]  # left points
            br = bpoints_loc[br_ind]  # right points

            if est_width > 0:
                # 下面的数值 est_width 是预估计的裂缝宽度
                half_est_width = est_width / 2
                blt = 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).T

                interps_rec = interps_rec.reshape(1, -1)[0, :]
                interp_segm.append(interps_rec)
        except:
            print("the %d-th was wrong" % i)
            continue
    interp_segm = np.array(interp_segm)
    widths = np.array(widths)

    return interp_segm, widths


def estimate_normal_for_pos(pos, points, n):
    # estimate normal vectors at a given point
    pts = 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 normals


def 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 normals


def 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)
        ] = 1

    skeleton_zha_contour_image = np.zeros(
        (3, image.shape[0], image.shape[1]), dtype=np.uint8
    )
    skeleton_zha_contour_image[0, skeleton_zha] = 255
    for 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] = 255
    skeleton_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_factor
        print(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_length


def 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]
        ] = 1
        contours = 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_factor
        print(
            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_interps
    fig, 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) * 60
    minutes = int(remainder_minutes)
    seconds = (remainder_minutes - minutes) * 60

    return degrees, minutes, seconds


def estimate_crack_direction(image):
    # 标记裂缝连通域
    labeled_image = label(image)

    # 存储裂缝的法线方向和椭圆信息
    crack_connected_domain_directions = []

    # 处理每个连通域
    for region in regionprops(labeled_image):

        current_crack_direction = region.orientation

        degrees, 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_direction


def 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_areas


def 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 logging

            logging.error(
                f"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  {img_name} exists wrong  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
            )
            continue


if __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,
    )

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

异构超图嵌入的图分类 笔记

1 Title Heterogeneous Hypergraph Embedding for Graph Classification&#xff08;Xiangguo Sun , PictureHongzhi Yin , PictureBo Liu , PictureHongxu Chen , PictureJiuxin Cao , PictureYingxia Shao , PictureNguyen Quoc Viet Hung&#xff09;【WSDM 2021】 2 Co…

1038: 顺序表中重复数据的删除

解法&#xff1a; #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() {int n, k;cin >> n;vector<int> arr(n);for (auto& x : arr) cin >> x;cin >> k;int sum 0;for (auto x : arr…

句柄ros::NodeHandle nh(“~“)与nh对launch文件参数配置(param)的影响

ros::NodeHandle nh("~"); 改为&#xff1a; ros::NodeHandle nh; 即可 /*************************分割线 ************************/ 如果原本是&#xff1a; ros::NodeHandle nh;可以改成&#xff1a; ros::NodeHandle nh("~"); 试试

反射与动态代理

一、反射 什么是反射? 反射允许对成员变量&#xff0c;成员方法和构造方法的信息进行编程访问 1.获取class对象的三种方式 Class这个类里面的静态方法forName&#xff08;“全类名”&#xff09;&#xff08;最常用&#xff09; 通过class属性获取 通过对象获取字节码文件对…

浏览器原理---事件循环

浏览器原理 学习浏览器原理对于我们开发是很有必要的 我们可以了解到浏览器内部工作原理对自己的代码进行优化 进程线程 首先了解进程和线程 进程就就是内存在正在进行的应用程序 在内存中独占一个内存空间 并且进程之间是隔离的 可以看到每个应用都有一个进程 占用空间内存…

【300套】基于Springboot+Vue的Java毕业设计项目(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享300的Java毕业设计&#xff0c;基于Springbootvue框架&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业…

【C++进阶】RAII思想&智能指针

智能指针 一&#xff0c;为什么要用智能指针&#xff08;内存泄漏问题&#xff09;内存泄漏 二&#xff0c;智能指针的原理2.1 RAII思想2.2 C智能指针发展历史 三&#xff0c;更靠谱的shared_ptr3.1 引用计数3.2 循环引用3.3 定制删除器 四&#xff0c;总结 上一节我们在讲抛异…

Vulnhub靶机 DC-1渗透详细过程

Vulnhub靶机:DC-1渗透详细过程 目录 Vulnhub靶机:DC-1渗透详细过程一、将靶机导入到虚拟机当中二、攻击方式主机发现端口扫描web渗透利用msf反弹shell数据库信息web管理员密码提权 一、将靶机导入到虚拟机当中 靶机地址&#xff1a; https://www.vulnhub.com/entry/dc-1-1,29…

Open CASCADE学习|BRepOffsetAPI_DraftAngle

BRepOffsetAPI_DraftAngle 是 Open CASCADE Technology (OCCT) 中用于创建带有草图斜面的几何体的类。草图斜面是一种在零件设计中常见的特征&#xff0c;它可以在零件的表面上创建一个倾斜的面&#xff0c;通常用于便于零件的脱模或是增加零件的强度。 本例演示了如何创建一个…

启动nginx时报错:signal process started

解决方案&#xff0c;直接使用该命令启动&#xff0c;指向nginx.conf配置文件&#xff1a; nginx -c /www/wdlinux/nginx/conf/nginx.conf 启动成功&#xff1a;

C语言高质量编程之assert()和const

目录 编程中常见的错误 assert() const 编程中常见的错误 在编程中我们通常会遇到三种错误形式&#xff0c;分别是&#xff1a;编译型错误&#xff0c;链接型错误&#xff0c;运行时错误。 编译型错误&#xff1a; 在编译阶段发生的错误&#xff0c;绝大多数情况是由语法错误…

全栈的自我修养 ———— react实现滑动验证

实现滑动验证 展示依赖实现不借助create-puzzle借助create-puzzle 展示 依赖 npm install rc-slider-captcha npm install create-puzzleapi地址 实现 不借助create-puzzle 需要准备两张图片一个是核验图形&#xff0c;一个是原图------> 这个方法小编试了后感觉比较麻烦…

初探vercel托管项目

文章目录 第一步、注册与登录第二步、本地部署 在个人网站部署的助手vercel&#xff0c;支持 Github部署&#xff0c;只需简单操作&#xff0c;即可发布&#xff0c;方便快捷&#xff01; 第一步、注册与登录 进入vercel【官网】&#xff0c;在右上角 login on&#xff0c;可登…

图解JDK 8 HashMap

HashMap-简介 HashMap 主要用来存放键值对&#xff0c;它基于哈希表的 Map 接口实现&#xff0c;是常用的 Java 集合之一&#xff0c;是非线程安全的。 HashMap 可以存储 null 的 key 和 value&#xff0c;但 null 作为键只能有一个&#xff0c;null 作为值可以有多个 JDK1.8…

Macbook M1 Pro使用brew安装Docker并安装Nacos【超详细图解】

目录 一、安装 Docker 二、修改 Docker 镜像地址 三、拉取镜像-举例 Nacos 1.拉取镜像 2.查看本地镜像 3.删除镜像 四、启动容器 1.启动 Nacos 容器&#xff1a; I.方式一【推荐】 II.方式二【懒人推荐】 2.访问 Nacos Web 控制台 3.进入容器和退出容器 五、配置…

labview中的同步定时结构

单帧定时循环定时比较精确&#xff0c;最常用的功能还是它的定时循环功能&#xff0c;定时循环允许不连接“循环条件”端子&#xff0c;可以连接定时循环“结构名称”端子&#xff0c;通过定时结构停止函数停止循环。 例子在附件中。

如何下载和安装Google Chrome扩展插件:一步步指南

Google Chrome 插件为我们提供了这样的便利&#xff0c;但有时找到一个有用的插件后&#xff0c;我们可能需要将其下载到本地以便离线使用或备份。 一、为什么可以从Google Chrome商店直接下载插件&#xff1f; Google Chrome 扩展插件主要通过Chrome Web Store分发&#xff…

凡泰极客亮相2024 亚马逊云科技出海全球化论坛,为企业数字化出海赋能

随着「不出海&#xff0c;即出局」登上热搜榜单&#xff0c;企业出海已成燎原之势&#xff0c;3月29日&#xff0c;2024 亚马逊云科技出海全球化论坛在深圳成功举办&#xff0c;凡泰极客创始人梁启鸿受邀出席&#xff0c;并以 「App 2.0&#xff1a;以SuperApp构建智能数字生态…

使用Python的Pillow库进行图像处理书法参赛作品

介绍&#xff1a; 在计算机视觉和图像处理领域&#xff0c;Python是一种强大而流行的编程语言。它提供了许多优秀的库和工具&#xff0c;使得图像处理任务变得轻松和高效。本文将介绍如何使用Python的wxPython和Pillow库来选择JPEG图像文件&#xff0c;并对选中的图像进行调整和…

Vol.45 这个壁纸网址,功能简单,每月37.7万访问量

哈咯&#xff0c;大家好&#xff0c;我是欧维&#xff0c;今天要给大家分享的网站是&#xff1a;极简壁纸&#xff0c;一个专门做电脑壁纸的网站&#xff1b; 它的网址是&#xff1a;极简壁纸_海量电脑桌面壁纸美图_4K超高清_最潮壁纸网站 网站的壁纸质量很高&#xff0c;页面…