欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > # 基于词袋模型(BoW)的猫狗图像分类实践

# 基于词袋模型(BoW)的猫狗图像分类实践

2025/5/4 20:15:54 来源:https://blog.csdn.net/www_pp_/article/details/147686252  浏览:    关键词:# 基于词袋模型(BoW)的猫狗图像分类实践

基于词袋模型(BoW)的猫狗图像分类实践

在计算机视觉领域,图像分类是一项基础且重要的任务。本文将介绍如何使用词袋模型(Bag of Words, BoW)结合支持向量机(SVM)实现猫狗图像分类。通过详细的代码实现和过程分析,帮助读者快速掌握这一经典方法的应用。

一、背景知识

(一)词袋模型(BoW)

词袋模型是一种用于文本分类的模型,它将文本中的单词看作是“词袋”中的元素,忽略单词的顺序和语法结构,只关注单词的出现频率。在图像处理中,我们可以将图像中的局部特征(如 SIFT 特征)看作是“词”,通过聚类将这些特征划分为不同的“视觉单词”,然后统计每个图像中各个视觉单词的出现频率,形成词袋直方图,作为图像的特征表示。

(二)支持向量机(SVM)

支持向量机是一种强大的分类算法,它通过寻找最优分割超平面,将不同类别的数据分隔开。在图像分类任务中,SVM 可以根据图像的特征向量进行分类,具有良好的分类性能和泛化能力。

二、代码实现

(一)环境准备

在开始之前,请确保已安装以下 Python 库:

  • OpenCV:用于图像处理和特征提取。
  • scikit-learn:用于机器学习算法的实现,包括 KMeans 聚类和 SVM 分类。
  • NumPy:用于数值计算。

可以通过以下命令安装这些库(如果尚未安装):

pip install opencv-python scikit-learn numpy

(二)代码解析

1. 类定义与初始化
class BowClassifier:def __init__(self, num_clusters=100):self.num_clusters = num_clustersself.kmeans = KMeans(n_clusters=num_clusters, random_state=42)self.svm = SVC(kernel='linear', probability=True, random_state=42)self.sift = cv2.SIFT_create()self.scaler = StandardScaler()self.class_names = ['cat', 'dog']  # 确保与文件夹名称一致
  • num_clusters:词袋模型中视觉单词的数量。
  • kmeans:用于将 SIFT 特征聚类为视觉单词。
  • svm:用于分类的 SVM 模型。
  • sift:用于提取图像的 SIFT 特征。
  • scaler:用于对特征进行标准化处理。
  • class_names:类别名称,这里以猫和狗为例。
2. 特征提取
def extract_features(self, image):"""使用SIFT提取图像特征"""try:gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)keypoints, descriptors = self.sift.detectAndCompute(gray, None)return descriptorsexcept Exception as e:print(f"特征提取错误: {e}")return None
  • 将图像转换为灰度图像。
  • 使用 SIFT 算法提取图像的特征点和描述符。
  • 如果提取过程中出现错误,返回 None
3. 数据加载与特征提取
def load_dataset(self, data_dir):"""加载数据集并提取特征"""features = []labels = []processed_count = 0failed_count = 0# 验证数据目录是否存在if not os.path.exists(data_dir):raise FileNotFoundError(f"数据目录 {data_dir} 不存在")for class_idx, class_name in enumerate(self.class_names):class_dir = os.path.join(data_dir, class_name)# 验证类别目录是否存在if not os.path.exists(class_dir):print(f"警告: 类别目录 {class_dir} 不存在,跳过")continueprint(f"\n正在处理类别: {class_name} ({class_dir})")for img_name in sorted(os.listdir(class_dir)):img_path = os.path.join(class_dir, img_name)# 添加更严格的图像格式检查if not img_name.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp')):print(f"跳过非图像文件: {img_name}")continuetry:# 使用更可靠的图像读取方式with open(img_path, 'rb') as f:file_bytes = np.asarray(bytearray(f.read()), dtype=np.uint8)image = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)if image is None:print(f"警告: 无法解码图像 {img_name},可能已损坏")failed_count += 1continue# 检查图像尺寸是否合理if image.shape[0] < 32 or image.shape[1] < 32:print(f"警告: 图像 {img_name} 尺寸过小 ({image.shape}),跳过")failed_count += 1continue# 提取特征descriptors = self.extract_features(image)if descriptors is None or len(descriptors) == 0:print(f"警告: 图像 {img_name} 未检测到特征点,跳过")failed_count += 1continuefeatures.append(descriptors)labels.append(class_idx)processed_count += 1if processed_count % 20 == 0:print(f"已处理 {processed_count} 张图像...")except Exception as e:print(f"处理图像 {img_name} 时出错: {str(e)}")failed_count += 1print(f"\n特征提取完成,共 {processed_count} 个有效样本")print(f"失败/跳过 {failed_count} 个样本")if processed_count == 0:raise ValueError("没有提取到任何有效特征,请检查:\n""1. 图像文件是否真实存在\n""2. 文件路径是否包含特殊字符\n""3. 图像文件是否已损坏\n""4. 文件权限是否正确")return features, labels
  • 遍历数据目录中的每个类别文件夹。
  • 对每个图像文件进行读取和特征提取。
  • 跳过非图像文件、损坏的图像文件、尺寸过小的图像文件以及未检测到特征点的图像文件。
  • 将提取到的特征和对应的标签存储起来。
4. 创建词袋直方图
def create_bow_histograms(self, features):"""创建词袋直方图"""histograms = []for descriptor in features:clusters = self.kmeans.predict(descriptor)histogram = np.bincount(clusters, minlength=self.num_clusters)histograms.append(histogram)return np.array(histograms)
  • 对每个图像的特征描述符进行聚类,得到每个描述符所属的聚类中心(即视觉单词)。
  • 统计每个图像中各个视觉单词的出现频率,形成词袋直方图。
5. 模型训练与评估
def train(self, data_dir):"""训练模型"""print("开始加载数据集和提取特征...")start_time = time.time()try:# 1. 加载数据集并提取特征features, labels = self.load_dataset(data_dir)# 2. 将所有描述符连接起来用于K-means聚类print("\n开始合并特征描述符...")all_descriptors = np.vstack(features)print(f"合并完成,总描述符数量: {all_descriptors.shape[0]}")# 3. 训练K-means聚类器print(f"\n开始K-means聚类 ({self.num_clusters}个聚类中心)...")self.kmeans.fit(all_descriptors)print("K-means聚类完成")# 4. 为每个图像创建词袋直方图print("\n创建词袋直方图...")X = self.create_bow_histograms(features)y = np.array(labels)# 5. 标准化特征X = self.scaler.fit_transform(X)# 6. 分割训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42, stratify=y)print(f"\n训练集: {X_train.shape[0]} 个样本")print(f"测试集: {X_test.shape[0]} 个样本")# 7. 训练SVM分类器print("\n开始训练SVM分类器...")self.svm.fit(X_train, y_train)print("SVM训练完成")# 8. 评估模型print("\n评估模型性能...")y_pred = self.svm.predict(X_test)precision = precision_score(y_test, y_pred, average='weighted')recall = recall_score(y_test, y_pred, average='weighted')f1 = f1_score(y_test, y_pred, average='weighted')print("\n分类报告:")print(classification_report(y_test, y_pred, target_names=self.class_names))print(f"\n测试集评估结果:")print(f"Precision: {precision:.4f}")print(f"Recall: {recall:.4f}")print(f"F1-score: {f1:.4f}")except Exception as e:print(f"\n训练过程中发生错误: {str(e)}")finally:end_time = time.time()print(f"\n总耗时: {end_time - start_time:.2f}秒")
  • 将数据集分为训练集和测试集,测试集占总数据集的 10%。
  • 使用训练集训练 SVM 分类器。
  • 在测试集上评估模型性能,计算精确率(Precision)、召回率(Recall)和 F1 分数,并打印分类报告。
  • 最后,打印整个训练和评估过程的总耗时。

(三)主函数

if __name__ == "__main__":# 使用原始字符串处理路径,避免转义问题data_dir = r"D:\Users\妄生\PycharmProjects\人工智能\作业(2023)\data"# 创建并训练分类器try:print("=" * 50)print("开始猫狗图像分类任务")print("=" * 50)# 先验证数据目录if not os.path.exists(data_dir):raise FileNotFoundError(f"主数据目录不存在: {data_dir}")print("\n数据目录结构验证:")for class_name in ['cat', 'dog']:class_dir = os.path.join(data_dir, class_name)if os.path.exists(class_dir):num_images = len([f for f in os.listdir(class_dir) if f.lower().endswith(('.jpg', '.jpeg', '.png'))])print(f"{class_name}目录: {class_dir} (包含 {num_images} 张图像)")else:print(f"警告: {class_name}目录不存在: {class_dir}")bow_classifier = BowClassifier(num_clusters=50)  # 减少聚类中心数量以加快处理速度bow_classifier.train(data_dir)except Exception as e:print(f"\n程序运行出错: {str(e)}")print("\n建议的解决方案:")print("1. 检查数据路径是否正确")print("2. 确保图像文件真实存在且可读")print("3. 尝试将数据复制到不含中文/特殊字符的路径")print("4. 检查图像文件是否损坏")finally:print("\n程序结束")
  • 指定数据集所在的目录路径。
  • 验证数据目录是否存在,并检查每个类别目录下的图像文件数量。
  • 创建 BowClassifier 实例,并调用 train 方法进行模型训练。
  • 如果在运行过程中出现错误,打印错误信息并提供一些可能的解决方案。

三、运行结果与分析

在这里插入图片描述

(一)运行结果

运行程序后,程序会依次输出以下内容:

  1. 数据目录结构验证结果,显示每个类别目录下的图像文件数量。
  2. 特征提取过程中的进度信息,包括已处理的图像数量和跳过的图像数量。
  3. K-means 聚类过程的耗时和结果。
  4. SVM 分类器的训练耗时。
  5. 模型在测试集上的评估结果,包括分类报告、精确率、召回率和 F1 分数。
  6. 整个训练和评估过程的总耗时。

(二)结果分析

  • 精确率(Precision):衡量模型预测为正类的样本中实际为正类的比例。较高的精确率表示模型的预测结果较为可靠。
  • 召回率(Recall):衡量模型能够正确识别出的正类样本占所有正类样本的比例。较高的召回率表示模型能够较好地识别出正类样本。
  • F1 分数:精确率和召回率的调和平均值,综合考虑了精确率和召回率的平衡。较高的 F1 分数表示模型在精确率和召回率之间取得了较好的平衡。

通过观察分类报告和评估指标,可以对模型的性能进行全面评估。如果模型的性能不理想,可以尝试以下方法进行优化:

  1. 调整聚类中心数量:增加或减少 num_clusters 的值,以改变视觉单词的数量,从而影响模型的特征表示能力。
  2. 改进特征提取方法:除了 SIFT 特征,还可以尝试使用其他特征提取算法,如 ORB、SURF 等。
  3. 调整 SVM 参数:通过调整 SVM 的核函数、惩罚参数等超参数,优化模型的分类性能。
  4. 增加数据量:扩充数据集,增加模型的训练样本数量,提高模型的泛化能力。

四、总结

本文介绍了基于词袋模型(BoW)和支持向量机(SVM)的猫狗图像分类方法,并提供了详细的代码实现。通过特征提取、聚类和分类的过程,实现了对猫狗图像的自动分类。实验结果表明,该方法能够取得较好的分类效果。在实际应用中,可以根据具体需求对模型进行优化和改进,以提高分类性能。希望本文的内容对读者有所帮助,能够为读者在图像分类领域的学习和研究提供一定的参考。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词