You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ORB提取图像特征维度不一致无法训练传统ML分类器问题

问题描述

我是机器学习初学者,目前正在开展二分类图像分类项目,任务是完成COVID、正常两类医学影像的预测分类。使用ORB特征检测器与描述子提取图像特征时遇到问题:不同图像输出的特征向量长度不一致,无法直接输入SVM、KNN等传统机器学习算法训练。(为简化展示,下方代码暂未包含正常类图像的处理逻辑)

原有实现代码

%matplotlib inline
from sklearn.model_selection import train_test_split
from matplotlib import pyplot as plt
from sklearn import tree
import numpy as np
import random
import cv2
import os

print (cv2.__version__)

path1 = 'D:\\Semester 6\\ML\\Image Classification\\Testing\\Train\\COVID'
path2 = 'D:\\Semester 6\\ML\\Image Classification\\Testing\\Train\\Normal'
images1 = []
images2 = []
myListC = os.listdir(path1)
myListN = os.listdir(path2)

orb = cv2.ORB_create()

for clC in myListC:
    imgCur1 = cv2.imread(f'{path1}/{clC}', 0)
    imgCur1 = cv2.resize(imgCur1, (200,200))
    print(len(imgCur1))
    images1.append(imgCur1)

desListC = []
for img in images1:
    kp1, des1 = orb.detectAndCompute(img, None)
    e, z = des1.shape
    des1 = des1.reshape(e*z)
    print(des1.shape)
    desListC.append(des1)

desList = np.array(desList) 

X = []
y = []

for i in range(len(desList)):
     X.append(desList[i][:-1])

for i in range(len(desList)):
     y.append(desList[i][-1:])

X = np.array(X) 
y = np.array(y) 

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

clf = tree.DecisionTreeClassifier()
clf = clf.fit(X, y)

运行异常现象

  • 不同图像提取的ORB描述子展平后维度不统一,输出形状如下:
    描述子形状输出
  • 代码运行报错信息如下:
    运行报错截图
  • 核心问题:代码直接将每张图的ORB描述子展平后尝试构造数据集,由于不同图像检测到的关键点数量不同,展平后特征维度不统一,无法构造规整numpy数组,也无法完成分类器拟合。
解决方案

ORB算法本身不会为每张图返回固定数量的关键点,每个ORB描述子固定为32维二进制向量,直接展平必然出现维度不齐的问题,同时原有代码的标签构造逻辑存在错误(不应该从描述子数组中切分标签,需要手动根据图像类别赋值),可按以下方法修复:

  • 快速修复方案:初始化ORB检测器时固定最大关键点检测数量,对提取到的描述子做截断/补零对齐
    初始化ORB时传入nfeatures参数指定单张图最多提取的关键点数量,提取描述子时,关键点不足指定数量的用零向量填充,超出的直接截断,就能得到长度统一的特征向量。
    关键修正代码如下:
    # 超参数:单张图固定提取500个ORB关键点
    FIXED_KP_NUM = 500
    DESC_DIM = 32 # ORB单个描述子固定32维
    orb = cv2.ORB_create(nfeatures=FIXED_KP_NUM)
    
    def get_aligned_feature(img_path):
        img = cv2.imread(img_path, 0)
        img = cv2.resize(img, (200,200))
        _, des = orb.detectAndCompute(img, None)
        # 处理无关键点的极端情况
        if des is None:
            des = np.zeros((FIXED_KP_NUM, DESC_DIM), dtype=np.uint8)
        # 补零对齐
        if des.shape[0] < FIXED_KP_NUM:
            pad = np.zeros((FIXED_KP_NUM - des.shape[0], DESC_DIM), dtype=np.uint8)
            des = np.vstack([des, pad])
        # 超长截断
        else:
            des = des[:FIXED_KP_NUM]
        return des.reshape(-1)
    
    X = []
    y = []
    # 提取COVID类特征,标签赋值0
    for f in myListC:
        X.append(get_aligned_feature(f'{path1}/{f}'))
        y.append(0)
    # 提取正常类特征,标签赋值1
    for f in myListN:
        X.append(get_aligned_feature(f'{path2}/{f}'))
        y.append(1)
    # 转换为规整数组即可直接输入分类器训练
    X = np.array(X)
    y = np.array(y)
    
  • 效果更优的传统方案:使用词袋模型(BoVW)做特征聚合
    这是手工特征搭配传统分类器的标准流程:先收集所有训练图像提取到的ORB描述子,用K-Means聚类生成固定规模的视觉词典(比如聚成100~200个簇),再将每张图的描述子映射为视觉单词的统计直方图,直方图维度和聚类簇数一致,得到固定长度特征后再训练分类器,泛化性比直接补零截断的方案更好。

内容的提问来源于stack exchange,提问作者RANA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 22:24:18