<think>根据日志,现在词汇表构建成功,并且成功提取了BoW特征(形状为(1,50))。接下来,我们需要完成整个物品识别系统的剩余部分,包括:1.为训练集中的所有图像提取BoW特征,形成特征矩阵。2.训练一个分类器(如SVM)来学习这些特征。3.对测试图像进行分类。下面我将给出完整的代码框架,包括特征矩阵构建、分类器训练和测试。###完整物品识别系统代码```pythonimportcv2importnumpyasnpimportosimportglobimportpicklefromsklearn.svmimportSVCfromsklearn.model_selectionimporttrain_test_splitfromsklearn.preprocessingimportStandardScalerfromsklearn.metricsimportclassification_report,accuracy_scoreimporttime#使用之前定义的RobustFeatureExtractor类(确保包含所有修复)classRobustFeatureExtractor:#...之前的代码,包括build_vocabulary,compute_bow_features等方法...defcreate_feature_matrix(extractor,data_dir,max_samples_per_class=50):"""为数据集中的所有图像提取BoW特征,构建特征矩阵和标签向量参数:extractor--RobustFeatureExtractor实例data_dir--数据集根目录(每个类一个子目录)max_samples_per_class--每类最大样本数(默认50)返回:X--特征矩阵(n_samples,n_features)y--标签向量(n_samples,)class_names--类别名称列表"""X=[]y=[]class_names=[]#遍历每个类别目录forclass_idx,class_nameinenumerate(sorted(os.listdir(data_dir))):class_dir=os.path.join(data_dir,class_name)ifnotos.path.isdir(class_dir):continueclass_names.append(class_name)image_paths=glob.glob(os.path.join(class_dir,'*.jpg'))+\glob.glob(os.path.join(class_dir,'*.png'))print(f"提取类别{class_name}的特征...")forpathinimage_paths[:max_samples_per_class]:img=cv2.imread(path,cv2.IMREAD_GRAYSCALE)ifimgisNone:print(f"跳过图像(加载失败):{path}")continuebow_features=extractor.compute_bow_features(img)ifbow_featuresisnotNone:X.append(bow_features.flatten())#将(1,50)变成(50,)y.append(class_idx)else:print(f"特征提取失败:{path}")returnnp.array(X),np.array(y),class_namesdeftrain_and_evaluate(X_train,y_train,X_test,y_test,class_names):"""训练SVM分类器并评估性能参数:X_train,y_train--训练数据和标签X_test,y_test--测试数据和标签class_names--类别名称列表"""#特征标准化scaler=StandardScaler()X_train_scaled=scaler.fit_transform(X_train)X_test_scaled=scaler.transform(X_test)#训练SVMprint("训练SVM分类器...")svm=SVC(kernel='linear',C=1.0,random_state=42,probability=True)svm.fit(X_train_scaled,y_train)#评估训练集y_train_pred=svm.predict(X_train_scaled)train_acc=accuracy_score(y_train,y_train_pred)print(f"训练集准确率:{train_acc:.4f}")#评估测试集y_test_pred=svm.predict(X_test_scaled)test_acc=accuracy_score(y_test,y_test_pred)print(f"测试集准确率:{test_acc:.4f}")#详细分类报告print("\n分类报告:")print(classification_report(y_test,y_test_pred,target_names=class_names))returnsvm,scalerdefmain():#1.初始化特征提取器extractor=RobustFeatureExtractor(feature_type='sift',n_clusters=50)#2.构建词汇表(如果之前未保存)TRAIN_DIR="data/train"VOCAB_FILE="models/vocabulary.pkl"ifnotos.path.exists(VOCAB_FILE):print("构建词汇表...")ifextractor.build_vocabulary(TRAIN_DIR):extractor.save(VOCAB_FILE)print("词汇表保存成功")else:print("词汇表构建失败,退出")returnelse:#加载已有的词汇表extractor=RobustFeatureExtractor.load(VOCAB_FILE)print("词汇表加载成功")#3.为训练集构建特征矩阵print("\n提取训练集特征...")X,y,class_names=create_feature_matrix(extractor,TRAIN_DIR)print(f"特征矩阵形状:{X.shape},标签数量:{len(y)}")#4.划分训练集和测试集(或者使用单独的测试目录)TEST_DIR="data/test"ifos.path.exists(TEST_DIR):print("\n提取测试集特征...")X_test,y_test,_=create_feature_matrix(extractor,TEST_DIR)else:print("\n未找到独立测试集,将分割训练集")X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=42,stratify=y)X=X_trainy=y_train#5.训练和评估分类器if'X_train'notinlocals():X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=42,stratify=y)print("\n训练分类器...")svm,scaler=train_and_evaluate(X_train,y_train,X_test,y_test,class_names)#6.保存模型MODEL_FILE="models/object_classifier.pkl"withopen(MODEL_FILE,'wb')asf:pickle.dump({'svm':svm,'scaler':scaler,'class_names':class_names,'feature_extractor':extractor},f)print(f"模型保存至{MODEL_FILE}")#7.测试单张图像(可选)TEST_IMAGE="test_image.jpg"ifos.path.exists(TEST_IMAGE):img=cv2.imread(TEST_IMAGE,cv2.IMREAD_GRAYSCALE)ifimgisnotNone:bow_features=extractor.compute_bow_features(img)ifbow_featuresisnotNone:features=bow_features.flatten()features_scaled=scaler.transform([features])proba=svm.predict_proba(features_scaled)[0]pred_class_idx=np.argmax(proba)pred_class=class_names[pred_class_idx]confidence=proba[pred_class_idx]print(f"\n测试图像分类结果:{pred_class}(置信度:{confidence:.4f})")else:print("测试图像特征提取失败")else:print("测试图像加载失败")else:print("未找到测试图像")if__name__=="__main__":start_time=time.time()main()print(f"总耗时:{time.time()-start_time:.2f}秒")```###代码说明####1.特征矩阵构建(`create_feature_matrix`)-遍历每个类别的图像目录-使用之前构建的词汇表提取每张图像的BoW特征(50维向量)-将特征和标签分别存入列表####2.分类器训练与评估(`train_and_evaluate`)-**特征标准化**:使用`StandardScaler`归一化特征(重要步骤,避免某些特征值过大影响SVM)-**SVM训练**:使用线性核SVM(适合中小型数据集)-**性能评估**:输出训练集和测试集的准确率以及详细分类报告####3.主流程(`main`)-**词汇表处理**:如果已有保存的词汇表则直接加载,否则重新构建-**特征提取**:为训练集所有图像提取BoW特征-**测试集处理**:如果有独立测试目录则单独提取,否则分割训练集-**模型保存**:保存训练好的SVM模型和标准化器-**单图测试**:演示如何对单张图像进行分类###性能优化建议1.**并行特征提取**:使用多线程加速特征提取过程```pythonfromconcurrent.futuresimportThreadPoolExecutordefextract_features_for_image(args):"""多线程辅助函数"""path,class_idx,extractor=argsimg=cv2.imread(path,cv2.IMREAD_GRAYSCALE)ifimgisNone:returnNonefeatures=extractor.compute_bow_features(img)return(features.flatten()iffeaturesisnotNoneelseNone,class_idx)#在create_feature_matrix中替换循环withThreadPoolExecutor(max_workers=4)asexecutor:args_list=[(path,class_idx,extractor)forpathinimage_paths[:max_samples_per_class]]results=executor.map(extract_features_for_image,args_list)forresultinresults:ifresultisnotNone:features,label=resultX.append(features)y.append(label)```2.**使用更高效的特征**:考虑使用ORB替代SIFT(速度更快,但精度可能略低)```pythonextractor=RobustFeatureExtractor(feature_type='orb',n_clusters=100)```3.**模型选择**:尝试不同的分类器(随机森林、XGBoost等)并进行超参数调优###常见问题处理-**类别不平衡**:在`train_and_evaluate`中设置`class_weight='balanced'````pythonsvm=SVC(kernel='linear',C=1.0,random_state=42,probability=True,class_weight='balanced')```-**特征维度低**:如果50维特征表现不佳,尝试增加聚类中心数量(如100-500)-**实时分类**:将特征提取和分类封装为单独函数,用于摄像头实时识别###扩展功能:实时摄像头识别```pythondefreal_time_recognition(model_path,camera_index=0):"""使用摄像头进行实时物品识别"""#加载模型withopen(model_path,'rb')asf:model_data=pickle.load(f)svm=model_data['svm']scaler=model_data['scaler']class_names=model_data['class_names']extractor=model_data['feature_extractor']#打开摄像头cap=cv2.VideoCapture(camera_index)ifnotcap.isOpened():print("无法打开摄像头")returnwhileTrue:ret,frame=cap.read()ifnotret:break#转换为灰度图gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)#提取特征bow_features=extractor.compute_bow_features(gray)ifbow_featuresisnotNone:features=bow_features.flatten()features_scaled=scaler.transform([features])proba=svm.predict_proba(features_scaled)[0]pred_class_idx=np.argmax(proba)pred_class=class_names[pred_class_idx]confidence=proba[pred_class_idx]#显示结果cv2.putText(frame,f"{pred_class}({confidence:.2f})",(10,30),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),2)cv2.imshow('ObjectRecognition',frame)#按ESC退出ifcv2.waitKey(1)==27:breakcap.release()cv2.destroyAllWindows()#在主函数中调用#real_time_recognition("models/object_classifier.pkl")```###总结现在您的物品识别系统已经完成以下功能:1.视觉词汇表构建2.BoW特征提取3.SVM分类器训练与评估4.模型保存与加载5.单图像测试和实时摄像头识别(可选)§§相关问题§§:1.如何提高物品识别系统的准确率?2.除了SIFT和ORB,还有哪些特征提取方法?3.当有新的类别加入时,如何更新现有模型?4.如何部署训练好的模型到Web应用中?</think>### 物品识别系统完整实现
根据您的最新日志,系统已成功构建词汇表并提取了BoW特征(形状为(1,50))。现在我将提供完整的物品识别系统代码,包括特征提取、分类器训练和预测功能。
```python
import cv2
import numpy as np
import os
import glob
import pickle
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, accuracy_score
import matplotlib.pyplot as plt
import time
# 特征提取器类(包含之前所有修复)
class RobustFeatureExtractor:
def __init__(self, feature_type='sift', n_clusters=100):
self.feature_type = feature_type.lower()
self.n_clusters = n_clusters
self.detector = None
self.bow_extractor = None
self.vocabulary = None
self._initialize_detector()
def _initialize_detector(self):
"""初始化特征检测器和BOW提取器"""
if self.feature_type == 'orb':
self.detector = cv2.ORB_create(nfeatures=1000)
matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
elif self.feature_type == 'sift':
self.detector = cv2.SIFT_create()
matcher = cv2.BFMatcher(cv2.NORM_L2)
else:
raise ValueError(f"不支持的特征类型: {self.feature_type}")
self.bow_extractor = cv2.BOWImgDescriptorExtractor(self.detector, matcher)
def extract_descriptors(self, image_path):
"""提取图像描述符"""
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
print(f"错误:无法读取图像 {image_path}")
return None
img = self._resize_image(img)
keypoints, descriptors = self.detector.detectAndCompute(img, None)
if descriptors is None or len(descriptors) == 0:
print(f"警告:图像 {os.path.basename(image_path)} 未检测到特征点")
return None
if self.feature_type == 'sift':
return descriptors.astype(np.float32)
return descriptors
def _resize_image(self, img, max_dim=800):
"""调整图像大小保持比例"""
h, w = img.shape
scale = max_dim / max(h, w)
return cv2.resize(img, (int(w * scale), int(h * scale)))
def build_vocabulary(self, data_dir, max_samples_per_class=50):
"""构建视觉词典"""
all_descriptors = []
for class_name in os.listdir(data_dir):
class_dir = os.path.join(data_dir, class_name)
if not os.path.isdir(class_dir):
continue
image_paths = glob.glob(os.path.join(class_dir, '*.jpg')) + \
glob.glob(os.path.join(class_dir, '*.png'))
print(f"处理类别 {class_name}: {len(image_paths)} 张图像")
for path in image_paths[:max_samples_per_class]:
descriptors = self.extract_descriptors(path)
if descriptors is not None:
all_descriptors.append(descriptors)
if not all_descriptors:
print("错误:没有提取到任何描述符!")
return False
all_descriptors = np.vstack(all_descriptors)
print(f"总共提取了 {len(all_descriptors)} 个描述符,维度: {all_descriptors.shape[1]}")
bow_trainer = cv2.BOWKMeansTrainer(self.n_clusters)
if self.feature_type == 'sift':
bow_trainer.add(all_descriptors.astype(np.float32))
else:
bow_trainer.add(all_descriptors)
print(f"聚类视觉单词,使用 {self.n_clusters} 个聚类中心...")
self.vocabulary = bow_trainer.cluster()
if self.vocabulary is None:
print("错误:词汇表聚类失败!")
return False
print(f"原始词汇表形状: {self.vocabulary.shape}")
if len(self.vocabulary.shape) == 1:
self.vocabulary = self.vocabulary.reshape(-1, all_descriptors.shape[1])
print(f"重塑后的词汇表形状: {self.vocabulary.shape}")
self.bow_extractor.setVocabulary(self.vocabulary)
print(f"词汇表类型: {self.vocabulary.dtype}, 形状: {self.vocabulary.shape}")
if self.bow_extractor.getVocabulary() is None:
print("错误:词汇表设置失败!")
return False
return True
def compute_bow_features(self, img):
"""计算图像的BoW特征"""
if img is None:
return None
img = self._resize_image(img)
keypoints = self.detector.detect(img, None)
if not keypoints:
return None
_, descriptors = self.detector.compute(img, keypoints)
if descriptors is None:
return None
if descriptors.dtype != self.vocabulary.dtype:
descriptors = descriptors.astype(self.vocabulary.dtype)
if descriptors.shape[1] != self.vocabulary.shape[1]:
return None
try:
return self.bow_extractor.compute(img, keypoints, descriptors)
except cv2.error as e:
print(f"计算BoW特征时出错: {str(e)}")
return None
def save(self, file_path):
"""保存特征提取器到文件"""
with open(file_path, 'wb') as f:
pickle.dump({
'feature_type': self.feature_type,
'n_clusters': self.n_clusters,
'vocabulary': self.vocabulary
}, f)
@staticmethod
def load(file_path):
"""从文件加载特征提取器"""
with open(file_path, 'rb') as f:
data = pickle.load(f)
extractor = RobustFeatureExtractor(
feature_type=data['feature_type'],
n_clusters=data['n_clusters']
)
extractor.vocabulary = data['vocabulary']
extractor._initialize_detector()
extractor.bow_extractor.setVocabulary(extractor.vocabulary)
return extractor
# 图像分类器类
class ObjectClassifier:
def __init__(self):
self.classifier = None
self.scaler = None
self.class_names = []
def train(self, X, y, class_names):
"""训练分类器"""
self.class_names = class_names
# 特征标准化
self.scaler = StandardScaler()
X_scaled = self.scaler.fit_transform(X)
# 训练SVM分类器
self.classifier = SVC(kernel='linear', C=1.0, probability=True)
self.classifier.fit(X_scaled, y)
# 评估训练集性能
y_pred = self.classifier.predict(X_scaled)
acc = accuracy_score(y, y_pred)
print(f"训练集准确率: {acc:.4f}")
# 分类报告
print("\n分类报告:")
print(classification_report(y, y_pred, target_names=class_names))
return acc
def predict(self, features):
"""预测新样本"""
if self.classifier is None or self.scaler is None:
print("错误:分类器未训练!")
return None, None
# 标准化特征
features = features.reshape(1, -1)
scaled_features = self.scaler.transform(features)
# 预测概率
probabilities = self.classifier.predict_proba(scaled_features)[0]
class_idx = np.argmax(probabilities)
class_name = self.class_names[class_idx]
confidence = probabilities[class_idx]
return class_name, confidence
def save(self, file_path):
"""保存分类器模型"""
with open(file_path, 'wb') as f:
pickle.dump({
'classifier': self.classifier,
'scaler': self.scaler,
'class_names': self.class_names
}, f)
@staticmethod
def load(file_path):
"""加载分类器模型"""
with open(file_path, 'rb') as f:
data = pickle.load(f)
classifier = ObjectClassifier()
classifier.classifier = data['classifier']
classifier.scaler = data['scaler']
classifier.class_names = data['class_names']
return classifier
# 完整系统主函数
def main():
start_time = time.time()
# 配置路径
TRAIN_DIR = "data/train"
TEST_DIR = "data/test"
VOCAB_FILE = "models/vocabulary.pkl"
CLASSIFIER_FILE = "models/classifier.pkl"
# 1. 创建或加载特征提取器
if os.path.exists(VOCAB_FILE):
print("加载现有词汇表...")
extractor = RobustFeatureExtractor.load(VOCAB_FILE)
else:
print("创建新词汇表...")
extractor = RobustFeatureExtractor(feature_type='sift', n_clusters=50)
if extractor.build_vocabulary(TRAIN_DIR):
extractor.save(VOCAB_FILE)
else:
print("词汇表构建失败,退出")
return
# 2. 创建特征矩阵
print("\n创建特征矩阵...")
X = [] # 特征列表
y = [] # 标签列表
class_names = sorted(os.listdir(TRAIN_DIR))
for class_idx, class_name in enumerate(class_names):
class_dir = os.path.join(TRAIN_DIR, class_name)
image_paths = glob.glob(os.path.join(class_dir, '*.jpg')) + \
glob.glob(os.path.join(class_dir, '*.png'))
print(f"提取 {class_name} 的特征 ({len(image_paths)} 张图像)...")
for path in image_paths:
img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
if img is None:
continue
features = extractor.compute_bow_features(img)
if features is not None:
X.append(features.flatten())
y.append(class_idx)
X = np.array(X)
y = np.array(y)
print(f"特征矩阵形状: {X.shape}, 标签数量: {len(y)}")
# 3. 训练分类器
print("\n训练分类器...")
classifier = ObjectClassifier()
classifier.train(X, y, class_names)
classifier.save(CLASSIFIER_FILE)
# 4. 测试分类器
print("\n测试分类器...")
test_image_paths = glob.glob(os.path.join(TEST_DIR, '*.jpg')) + \
glob.glob(os.path.join(TEST_DIR, '*.png'))
correct = 0
total = 0
for path in test_image_paths:
img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
if img is None:
continue
# 提取特征
features = extractor.compute_bow_features(img)
if features is None:
continue
# 预测
true_class = os.path.basename(os.path.dirname(path))
pred_class, confidence = classifier.predict(features.flatten())
# 显示结果
print(f"图像: {os.path.basename(path)}")
print(f" 真实类别: {true_class}, 预测类别: {pred_class}, 置信度: {confidence:.4f}")
# 更新准确率
total += 1
if pred_class == true_class:
correct += 1
# 计算测试准确率
if total > 0:
test_acc = correct / total
print(f"\n测试准确率: {test_acc:.4f} ({correct}/{total})")
# 5. 实时摄像头识别(可选)
enable_camera = False
if enable_camera:
print("\n启动摄像头识别...")
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# 转换为灰度图
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 提取特征
features = extractor.compute_bow_features(gray)
if features is not None:
# 预测
pred_class, confidence = classifier.predict(features.flatten())
# 显示结果
cv2.putText(frame, f"{pred_class} ({confidence:.2f})",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow('Object Recognition', frame)
# 按ESC退出
if cv2.waitKey(1) == 27:
break
cap.release()
cv2.destroyAllWindows()
# 6. 性能分析
end_time = time.time()
print(f"\n总耗时: {end_time - start_time:.2f}秒")
if __name__ == "__main__":
main()
```
### 系统功能详解
#### 1. 特征提取器 (`RobustFeatureExtractor`)
- **词汇表构建**:从训练图像中提取特征并聚类
- **特征计算**:将图像转换为BoW特征向量
- **持久化**:支持保存和加载训练好的特征提取器
#### 2. 分类器 (`ObjectClassifier`)
- **训练**:使用标准化后的特征训练SVM分类器
- **预测**:对新样本进行预测并返回类别和置信度
- **评估**:输出训练集准确率和分类报告
- **持久化**:支持保存和加载训练好的分类器
#### 3. 主流程 (`main`)
1. **初始化**:加载或创建特征提取器
2. **特征提取**:为所有训练图像提取BoW特征
3. **模型训练**:训练SVM分类器
4. **模型测试**:在测试集上评估性能
5. **实时识别**:可选摄像头实时识别功能
### 性能优化技巧
#### 1. 并行特征提取
```python
from concurrent.futures import ThreadPoolExecutor
def extract_features_for_image(args):
path, class_idx, extractor = args
img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
if img is None:
return None
features = extractor.compute_bow_features(img)
return (features.flatten() if features is not None else None, class_idx)
# 在主流程中替换
with ThreadPoolExecutor(max_workers=4) as executor:
args_list = [(path, class_idx, extractor)
for class_idx, class_name in enumerate(class_names)
for path in glob.glob(os.path.join(TRAIN_DIR, class_name, '*'))]
results = executor.map(extract_features_for_image, args_list)
for result in results:
if result is not None:
features, class_idx = result
X.append(features)
y.append(class_idx)
```
#### 2. 特征缓存
```python
def load_or_extract_features(extractor, cache_file="cache/features.pkl"):
"""加载或提取特征"""
if os.path.exists(cache_file):
print("加载缓存特征...")
with open(cache_file, 'rb') as f:
data = pickle.load(f)
return data['X'], data['y'], data['class_names']
# 提取特征...
X, y, class_names = extract_features(extractor)
# 保存缓存
os.makedirs(os.path.dirname(cache_file), exist_ok=True)
with open(cache_file, 'wb') as f:
pickle.dump({'X': X, 'y': y, 'class_names': class_names}, f)
return X, y, class_names
```
#### 3. 模型选择与调优
```python
from sklearn.model_selection import GridSearchCV
def optimize_classifier(X, y):
"""使用网格搜索优化分类器参数"""
param_grid = {
'C': [0.1, 1, 10, 100],
'kernel': ['linear', 'rbf', 'poly'],
'gamma': ['scale', 'auto']
}
svc = SVC(probability=True)
grid_search = GridSearchCV(svc, param_grid, cv=5, n_jobs=-1)
grid_search.fit(X, y)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳准确率: {grid_search.best_score_:.4f}")
return grid_search.best_estimator_
```
### 系统部署方案
#### 1. 创建预测API
```python
from flask import Flask, request, jsonify
import numpy as np
app = Flask(__name__)
# 加载模型
extractor = RobustFeatureExtractor.load("models/vocabulary.pkl")
classifier = ObjectClassifier.load("models/classifier.pkl")
@app.route('/predict', methods=['POST'])
def predict():
# 接收上传的图像
file = request.files['image']
img_bytes = file.read()
img = cv2.imdecode(np.frombuffer(img_bytes, np.uint8), cv2.IMREAD_GRAYSCALE)
# 提取特征
features = extractor.compute_bow_features(img)
if features is None:
return jsonify({"error": "无法提取特征"}), 400
# 预测
class_name, confidence = classifier.predict(features.flatten())
return jsonify({
"class": class_name,
"confidence": float(confidence)
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
```
#### 2. 创建Web界面
```html
<!DOCTYPE html>
<html>
<head>
<title>物品识别系统</title>
</head>
<body>
<h1>上传物品图片</h1>
<input type="file" id="imageInput" accept="image/*">
<button onclick="predict()">识别物品</button>
<div id="result"></div>
<script>
function predict() {
const fileInput = document.getElementById('imageInput');
const file = fileInput.files[0];
if (!file) {
alert('请选择图片');
return;
}
const formData = new FormData();
formData.append('image', file);
fetch('/predict', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.error) {
document.getElementById('result').innerText = '错误: ' + data.error;
} else {
document.getElementById('result').innerText =
`识别结果: ${data.class} (置信度: ${(data.confidence * 100).toFixed(2)}%)`;
}
})
.catch(error => {
console.error('Error:', error);
document.getElementById('result').innerText = '请求失败';
});
}
</script>
</body>
</html>
```
### 总结
您现在已经拥有一个完整的物品识别系统,包含:
1. 健壮的特征提取器(SIFT/ORB + BoW)
2. 高性能分类器(SVM)
3. 完整的训练和测试流程
4. 实时摄像头识别功能
5. Web API和界面部署方案
系统特点:
- 模块化设计,易于扩展
- 支持模型持久化
- 提供性能优化选项
- 支持多种部署方式