CoraxAsAPlanet 2024-07-10 11:43 采纳率: 0%
浏览 5

optics图像聚类无法正确聚类

optics图像聚类簇数过多
被要求对类似以下图片做基于距离的聚类

img

之后我使用optics在多轮调参后始终无法使每一列聚为一类,总是断断续续的

img


我想让他一列能连出一条线,这个该怎么修改。
以下是主要代码

import os
import math
import shutil

import cv2
import numpy as np
import ssd
from sklearn.cluster import DBSCAN, OPTICS
from tqdm import tqdm
from sklearn.cluster import AgglomerativeClustering
import scipy.spatial.distance as ssd

def point_to_line_distance(x1, y1, slope, x2, y2):
    A = slope
    B = -1
    C = y1 - slope * x1
    distance = abs(A * x2 + B * y2 + C) / math.sqrt(A ** 2 + B ** 2)
    return distance


def angel_distance(angel1, angel2):
    return 180 - abs(abs(angel1 - angel2) - 180)


def point_distance(x1, y1, x2, y2):
    return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)


def merge_close_clusters(points, labels, distance_threshold=50):
    # 根据标签对点进行分组
    clusters = {}
    for label, point in zip(labels, points):
        if label not in clusters:
            clusters[label] = []
        clusters[label].append(point)

    # 合并距离小于阈值的簇
    for label1, points1 in clusters.items():
        for label2, points2 in clusters.items():
            if label1 < label2:  # 避免重复合并
                for point1 in points1:
                    for point2 in points2:
                        if point_distance(point1[0], point1[1], point2[0], point2[1]) < distance_threshold:
                            # 合并簇label1到label2
                            for i in range(len(labels)):
                                if labels[i] == label1:
                                    labels[i] = label2
                            break

    return labels
def merge_components(comp1, comp2):
    x1, y1 = comp1[0]
    w1, h1, area1, (cx1, cy1) = comp1[1:]
    x2, y2 = comp2[0]
    w2, h2, area2, (cx2, cy2) = comp2[1:]

    # 合并边界框
    x = min(x1, x2)
    y = min(y1, y2)
    w = max(x1 + w1, x2 + w2) - x
    h = max(y1 + h1, y2 + h2) - y

    # 合并面积
    area = area1 + area2

    # 计算新的质心
    cx = (cx1 * area1 + cx2 * area2) / area
    cy = (cy1 * area1 + cy2 * area2) / area

    return [(x, y), w, h, area, (int(cx), int(cy))]


# 文件夹路径
folder_path = r'E:\image/'  # 替换为你的图像路径
output_folder = 'temp/'

# 如果输出文件夹不存在,则创建
if os.path.exists(output_folder):
    shutil.rmtree(output_folder)
os.makedirs(output_folder)

# 获取文件夹中所有图像路径
images_path = os.listdir(folder_path)
images_path = [os.path.join(folder_path, image_path) for image_path in images_path]
for image_path in tqdm(images_path):
    # 读取图像
    image = cv2.imread(image_path)

    # 读取二值化图像
    binary_image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

    # 进行连通组件标记
    num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image, connectivity=8)

    # 遍历所有组件(第一个组件是背景,所以从1开始)
    components_list = []
    for i in range(1, num_labels):
        # 获取组件的统计信息
        x, y, w, h, area = stats[i]
        if area <= 100:
            continue
        cx, cy = centroids[i]
        cx = int(cx)
        cy = int(cy)

        # 绘制中心点
        # cv2.circle(image, (cx, cy), 3, (0, 0, 255), -1)

        components_list.append([(x, y), w, h, area, (cx, cy)])

    # 合并距离小于50像素的组件
    while True:
        merged = False
        for i in range(len(components_list)):
            for j in range(i + 1, len(components_list)):
                cx1, cy1 = components_list[i][4]
                cx2, cy2 = components_list[j][4]
                if point_distance(cx1, cy1, cx2, cy2) < 50:
                    new_component = merge_components(components_list[i], components_list[j])
                    components_list[i] = new_component
                    del components_list[j]
                    merged = True
                    break
            if merged:
                break
        if not merged:
            break
        # 使用 OPTICS 聚类算法
        # 提取质心坐标
    points = np.array([component[4] for component in components_list])

    # 使用 OPTICS 聚类算法
    optics = OPTICS(min_samples=0.0025,xi=0.008, max_eps=300,metric='manhattan')
    labels = optics.fit_predict(points)

    # 检查聚类结果
    # 打印聚类结果的统计信息
    unique_labels = np.unique(labels)
    print("Clustered labels:", unique_labels)
    for label in unique_labels:
        if label == -1:
            continue  # 忽略噪声点
        print(f"Cluster {label} has {len(points[labels == label])} points")

    new_labels = merge_close_clusters(points, labels)

    for label in np.unique(new_labels):
        if label == -1:
            continue  # 忽略噪声点
        cluster_points = points[new_labels == label]
        if len(cluster_points) > 1:
            sorted_points = sorted(cluster_points, key=lambda point: point[1])
            for i in range(1, len(sorted_points)):
                start_point = (int(sorted_points[i - 1][0]), int(sorted_points[i - 1][1]))
                end_point = (int(sorted_points[i][0]), int(sorted_points[i][1]))
                cv2.line(image, start_point, end_point, (0, 0, 255), 20)


        # 保存图像
        output_path = os.path.join(output_folder, os.path.basename(image_path))
        cv2.imwrite(output_path, image)
    else:
        print("No valid clusters found with current parameters. Adjusting parameters may be needed.")

  • 写回答

2条回答 默认 最新

  • 阿里嘎多学长 2024-07-10 11:43
    关注

    以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


    您好!很高兴您在尝试使用 OPTICS 算法进行图像聚类时想到了我。从您提供的信息来看,您已经做了很多尝试,但聚类结果仍然不尽如人意。让我们一步步来分析可能的问题和解决方案。

    首先,OPTICS 算法是一种基于密度的聚类算法,它类似于 DBSCAN,但不需要指定邻域半径(eps)。您在代码中使用的参数包括 min_samples, xi, 和 max_eps。这些参数对聚类结果有很大的影响:

    • min_samples:一个区域内所需的最小样本数,以被认为是一个核心点。
    • xi:这个参数用于确定两个点之间的可达性距离,通常设置为一个较小的值,比如 0.01 到 0.05。
    • max_eps:最大的可达性距离,超过这个距离的点将不会被考虑。

    可能的解决方案:

    1. 参数调整:您可能需要进一步调整 min_samplesxi 的值。如果 min_samples 太大,可能会导致算法无法识别较小的簇。如果 xi 太小,算法可能会过于敏感,导致簇分散。

    2. 预处理:在进行聚类之前,对图像进行适当的预处理可能会有所帮助。例如,可以尝试使用形态学操作来消除噪点,或者使用图像滤波器来平滑图像。

    3. 特征选择:您可能需要考虑使用不同的特征进行聚类。例如,如果连通组件的方向很重要,您可能需要计算每个组件的主方向,并使用这个方向作为聚类的特征之一。

    4. 后处理:在聚类之后,您已经实现了一个 merge_close_clusters 函数来合并接近的簇。您可能需要调整这个函数中的 distance_threshold,或者考虑使用不同的方法来合并簇。

    5. 算法选择:如果 OPTICS 算法仍然无法满足您的需求,您可以考虑尝试其他聚类算法,比如 DBSCAN 或者 Agglomerative Clustering,并调整它们的参数。

    6. 可视化:为了更好地理解聚类结果,您可以尝试将聚类结果可视化。这可以帮助您直观地看到哪些部分的聚类效果不佳,并据此调整参数。

    7. 专业库:考虑使用专业的图像处理和聚类库,如 scikit-image 或其他,它们可能提供了更高级的聚类方法和工具。

    代码建议:

    • 在聚类之前,您可以尝试将连通组件的质心标准化,以消除由于图像尺寸不同带来的影响。
    • merge_close_clusters 函数中,您可能需要考虑合并簇的策略,比如根据簇的大小或者形状特征来决定是否合并。

    最后,由于我无法直接运行代码,我建议您根据上述建议逐一尝试,并观察聚类结果的变化。希望这些建议能够帮助您解决问题。如果您需要进一步的帮助,比如具体的代码实现或者算法的详细解释,请随时告诉我。

    参考链接:

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 7月10日

悬赏问题

  • ¥15 Windows Script Host 无法找到脚本文件"C:\ProgramData\Player800\Cotrl.vbs”
  • ¥15 matlab自定义损失函数
  • ¥15 35114 SVAC视频验签的问题
  • ¥15 impedancepy
  • ¥15 求往届大挑得奖作品(ppt…)
  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图