计算机视觉-基于LM滤波器的特征提取与分类

       本次实验基于图像分类原理,选取 3 类数据用于训练与测试。利用 LM 滤波器组对数据提取特征。其原理是通过设定不同尺度、方向等参数生成多种滤波器,以获取图像不同特征。接着运用 SVM 算法进行分类,借助 libsvm - 3.21工具包,依据给定的多项式核函数的度和惩罚系数,用训练样本训练模型并对测试样本预测。最后通过评估函数计算 kappa 值、混淆矩阵等指标来评价,并分析 SVM 中两个关键参数对分类结果的影响,以此探究实验中图像分类的规律和性能 。

-------------------------------------------------------------------------------------------------------------------------------- 

LM 滤波器的特征提取原理

  • 多分辨率分析:LM 滤波器利用拉普拉斯金字塔的构建来实现图像的多分辨率分解。首先,通过高斯滤波器对原始图像进行不同尺度的平滑处理,得到一系列不同分辨率的图像。然后,通过相邻尺度图像的差分来构建拉普拉斯金字塔,这些差分图像保留了图像在不同尺度下的细节信息,例如边缘、纹理等。这样可以捕捉到图像中不同大小和频率的特征,从粗到细地描述图像的结构。
  • 边缘和纹理增强:拉普拉斯算子本身是一种二阶导数算子,对图像中的边缘和纹理等细节信息具有较强的响应。在 LM 滤波器中,通过在不同尺度上应用拉普拉斯算子,能够突出图像中各种尺度的边缘和纹理特征。边缘是图像中灰度变化剧烈的地方,而纹理则是由一系列重复的局部模式组成,LM 滤波器能够有效地将这些特征提取出来,使得图像的特征更加明显,便于后续的分类处理。

基于提取特征的分类原理

  • 特征向量构建:将经过 LM 滤波器处理后得到的多尺度特征进行组合和量化,形成特征向量。这些特征向量包含了图像在不同尺度下的边缘、纹理等信息,能够全面地描述图像的特征。例如,可以将不同尺度下的拉普拉斯金字塔图像的统计信息(如均值、方差、能量等)作为特征向量的元素,或者使用一些局部特征描述子(如 SIFT、SURF 等)在 LM 滤波器处理后的图像上进行特征提取,然后将这些描述子组合成特征向量。
  • 分类器训练与分类:使用已经标注好类别的图像数据集来训练分类器。常见的分类器有支持向量机(SVM)、神经网络(如卷积神经网络 CNN)、决策树等。在训练过程中,分类器学习特征向量与图像类别之间的映射关系。对于待分类的图像,首先通过 LM 滤波器提取其特征向量,然后将该特征向量输入到训练好的分类器中,分类器根据学习到的映射关系输出该图像所属的类别。

def gaussian1d(sigma, mean, x, ord):
    x = np.array(x)
    x_ = x - mean
    var = sigma ** 2
    g1 = (1 / np.sqrt(2 * np.pi * var)) * (np.exp((-1 * x_ * x_) / (2 * var)))

    if ord == 0:
        return g1
    elif ord == 1:
        return -g1 * ((x_) / (var))
    else:
        return g1 * (((x_ * x_) - var) / (var ** 2))
  • 功能:计算一维高斯函数或其一阶、二阶导数。
  • 参数
    • sigma:高斯函数的标准差,用于控制函数的宽度。
    • mean:高斯函数的均值,即函数的中心位置。
    • x:输入的自变量数组,可以是一维的数值序列。
    • ord:导数的阶数,ord=0表示计算高斯函数本身,ord=1表示计算一阶导数,ord=2表示计算二阶导数。
  • 实现步骤
    1. 将输入的x转换为 NumPy 数组。
    2. 计算x与均值mean的差值x_
    3. 计算方差var
    4. 根据高斯函数的公式计算g1
    5. 根据ord的值返回不同的结果:如果ord为 0,返回高斯函数的值;如果ord为 1,返回一阶导数的值;如果ord为其他值(这里实际是 2),返回二阶导数的值。

def gaussian2d(sup, scales):
    var = scales * scales
    shape = (sup, sup)
    n, m = [(i - 1) / 2 for i in shape]
    x, y = np.ogrid[-m:m + 1, -n:n + 1]
    return (1 / np.sqrt(2 * np.pi * var)) * np.exp(-(x * x + y * y) / (2 * var))
  • 功能:计算二维高斯函数。
  • 参数
    • sup:生成的二维高斯函数的大小,即输出矩阵的边长。
    • scales:高斯函数的标准差,用于控制函数的宽度。
  • 实现步骤
    1. 计算方差var
    2. 确定输出矩阵的形状shape
    3. 计算矩阵中心的索引nm
    4. 使用np.ogrid生成二维坐标网格xy
    5. 根据二维高斯函数的公式计算并返回结果。
def log2d(sup, scales):
    var = scales * scales
    shape = (sup, sup)
    n, m = [(i - 1) / 2 for i in shape]
    x, y = np.ogrid[-m:m + 1, -n:n + 1]
    g = (1 / np.sqrt(2 * np.pi * var)) * np.exp(-(x * x + y * y) / (2 * var))
    return g * ((x * x + y * y) - var) / (var ** 2)

  • 功能:计算二维拉普拉斯高斯(LoG)函数。
  • 参数
    • sup:生成的二维 LoG 函数的大小,即输出矩阵的边长。
    • scales:高斯函数的标准差,用于控制函数的宽度。
  • 实现步骤
    1. 计算方差var
    2. 确定输出矩阵的形状shape
    3. 计算矩阵中心的索引nm
    4. 使用np.ogrid生成二维坐标网格xy
    5. 计算二维高斯函数g
    6. 根据二维 LoG 函数的公式计算并返回结果。

def makefilter(scale, phasex, phasey, pts, sup):
    gx = gaussian1d(3 * scale, 0, pts[0, ...], phasex)
    gy = gaussian1d(scale, 0, pts[1, ...], phasey)
    return np.reshape(gx * gy, (sup, sup))
  • 功能:结合两个一维高斯函数生成一个二维滤波器。
  • 参数
    • scale:用于控制高斯函数的尺度。
    • phasexx方向上高斯函数的导数阶数。
    • phaseyy方向上高斯函数的导数阶数。
    • pts:包含两个数组的二维数组,分别表示xy方向上的坐标点。
    • sup:生成的二维滤波器的大小,即输出矩阵的边长。
  • 实现步骤
    1. 调用gaussian1d函数计算x方向上的一维高斯函数gx,使用3 * scale作为标准差,0作为均值。
    2. 调用gaussian1d函数计算y方向上的一维高斯函数gy,使用scale作为标准差,0作为均值。
    3. gxgy相乘,并重新调整形状为(sup, sup)后返回。

def makeLMfilters():
    sup = 49
    scalex = np.sqrt(2) * np.array([1, 2, 3])
    norient = 6
    nrotinv = 12

    nbar = len(scalex) * norient
    nedge = len(scalex) * norient
    nf = nbar + nedge + nrotinv
    F = np.zeros([sup, sup, nf])
    hsup = (sup - 1) / 2

    x = [np.arange(-hsup, hsup + 1)]
    y = [np.arange(-hsup, hsup + 1)]
    [x, y] = np.meshgrid(x, y)
    orgpts = np.array([x.flatten(), y.flatten()])

    count = 0
    num_filters_per_plot = 24
    num_plots = (nf + num_filters_per_plot - 1) // num_filters_per_plot

    for plot_num in range(num_plots):
        fig = plt.figure(figsize=(10, 6))
        for i in range(num_filters_per_plot):
            if count >= nf:
                break
            scale = count // norient
            scale = np.clip(scale, 0, len(scalex) - 1)
            orient = count % norient
            angle = (np.pi * orient) / norient
            c, s = np.cos(angle), np.sin(angle)
            rotpts = np.dot([[c, -s], [s, c]], orgpts)
            F[:, :, count] = makefilter(scalex[scale], 0, 1, rotpts, sup)
            ax = fig.add_subplot(4, 6, i+1)
            plt.imshow(F[:, :, count], cmap='jet')
            ax.set_title(f'Filter {count+1}')
            ax.axis('off')
            count += 1

        plt.suptitle(f'LM滤波器 {plot_num * num_filters_per_plot + 1} 到 {min((plot_num + 1) * num_filters_per_plot, nf)}')
        plt.tight_layout()
        plt.show()

    return F
  • 功能:生成 LM(Leung-Malik)滤波器组,并可视化这些滤波器。
  • 实现步骤
    1. 初始化一些参数,包括滤波器的大小sup,尺度数组scalex,方向数量norient,旋转不变滤波器数量nrotinv等。
    2. 计算不同类型滤波器的数量nbarnedge和总滤波器数量nf,并初始化一个三维数组F来存储所有滤波器。
    3. 生成原始的坐标网格orgpts
    4. 计算需要绘制的滤波器数量和绘图数量。
    5. 遍历每个绘图:
      • 创建一个新的图形。
      • 遍历每个子图(滤波器):
        • 计算当前滤波器的尺度scale和方向orient
        • 计算旋转角度angle和旋转矩阵cs
        • 对原始坐标点进行旋转得到rotpts
        • 调用makefilter函数生成当前滤波器,并存储到F中。
        • 将滤波器可视化,并设置子图的标题,关闭坐标轴。
      • 设置整个绘图的标题,调整布局并显示图形。
    6. 返回生成的 LM 滤波器组F
def extract_features(images, F):
    features = []
    for img in images:
        img_features = []
        for i in range(F.shape[2]):
            filtered = convolve2d(img, F[:, :, i], mode='same')
            img_features.extend([filtered.mean(), filtered.std()])
        features.append(img_features)
    return np.array(features)
  • 功能:该函数用于从给定的图像集合中提取特征。它通过将每个图像与一组滤波器(由 F 表示)进行卷积操作,然后计算卷积结果的均值和标准差,以此作为图像的特征。

  • 参数

    • images:一个包含多个图像的列表或数组。每个图像应该是一个二维的数值数组,表示图像的像素值。
    • F:一个三维数组,表示一组滤波器。其中,F[:, :, i] 表示第 i 个滤波器,它是一个二维数组。
  • 实现步骤

    1. 初始化一个空列表 features,用于存储所有图像的特征。
    2. 遍历输入的图像列表 images
      • 对于每个图像 img,初始化一个空列表 img_features,用于存储该图像的特征。
      • 遍历滤波器数组 F 的第三个维度(即滤波器的数量):
        • 使用 convolve2d 函数对当前图像 img 和第 i 个滤波器 F[:, :, i] 进行二维卷积操作,mode='same' 表示输出的卷积结果与输入图像大小相同。
        • 计算卷积结果 filtered 的均值和标准差,并将这两个值添加到 img_features 列表中。
      • 将当前图像的特征列表 img_features 添加到 features 列表中。
    3. 最后,将 features 列表转换为 NumPy 数组并返回。
def evaluate_results(y_true, y_pred):
    CM = confusion_matrix(y_true, y_pred)
    CA = accuracy_score(y_true, y_pred)
    OA = np.trace(CM) / np.sum(CM)
    AA = np.mean(np.diag(CM) / np.sum(CM, axis=1))
    kappa = cohen_kappa_score(y_true, y_pred)
    return kappa, CM, CA, OA, AA

def confusion_matrix_plot(CM, class_names):
    plt.figure(figsize=(8, 6))
    sns.heatmap(CM, annot=True, fmt='d', xticklabels=class_names, yticklabels=class_names)
    plt.xlabel('预测类别')
    plt.ylabel('真实类别')
    plt.title('混淆矩阵')
    plt.show()

def main():
    data_path = r"D:\LM_SVM_DTD_Classification\data\dtd\images"
    selected_classes = ['banded', 'blotchy', 'braided']
    try:
        X, y = load_dtd_data(data_path, selected_classes)
    except Exception as e:
        print(f"数据加载失败: {str(e)}")
        print("请检查:")
        print(f"1. 路径是否存在: {os.path.exists(data_path)}")
        print(f"2. 可用类别: {os.listdir(data_path) if os.path.exists(data_path) else '路径无效'}")
        return
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
    F = makeLMfilters()
    X_train_feats = extract_features(X_train, F)
    X_test_feats = extract_features(X_test, F)
    print("\n训练SVM分类器...")
    clf = svm.SVC(kernel='poly', degree=3, C=1.0)
    clf.fit(X_train_feats, y_train)
    y_pred = clf.predict(X_test_feats)
    kappa, CM, CA, OA, AA = evaluate_results(y_test, y_pred)
    print("\n分类结果统计表:")
    print(f"{'指标':<15}{'值':<10}")
    print("-" * 25)
    print(f"{'Kappa系数':<15}{kappa:.4f}")
    print(f"{'总体准确率(OA)':<15}{OA:.4f}")
    print(f"{'平均准确率(AA)':<15}{AA:.4f}")
    print(f"{'分类准确率(CA)':<15}{CA:.4f}")
    plt.figure(figsize=(10, 8))
    sns.heatmap(CM, annot=True, fmt='d', cmap='Blues',
                xticklabels=selected_classes,
                yticklabels=selected_classes)
    plt.xlabel('预测类别', fontsize=12)
    plt.ylabel('真实类别', fontsize=12)
    plt.title('分类混淆矩阵', fontsize=15)
    plt.xticks(rotation=45)
    plt.yticks(rotation=45)
    plt.tight_layout()
    plt.savefig('confusion_matrix.png', dpi=300, bbox_inches='tight')
    plt.show()
    print("\n参数分析结果:")
    degrees = range(1, 8)  # 1-7
    C_values = [10 ** i for i in range(-1, 7)]  # 10^-1到10^6
    results = []
    best_acc = 0
    best_params = {}
    for degree in degrees:
        for C in C_values:
            clf = svm.SVC(kernel='poly', degree=degree, C=C)
            clf.fit(X_train_feats, y_train)
            y_pred = clf.predict(X_test_feats)
            acc = accuracy_score(y_test, y_pred)

            results.append({
                'degree': degree,
                'C': C,
                'accuracy': acc
            })

            if acc > best_acc:
                best_acc = acc
                best_params = {'degree': degree, 'C': C}

            print(f"degree={degree}, C={C:.1e}: 准确率={acc:.4f}")
    print(f"\n最佳参数组合: {best_params}")
    print(f"最高准确率: {best_acc:.4f}")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值