diff --git a/.gitignore b/.gitignore index baa8e22..8ea01fa 100644 --- a/.gitignore +++ b/.gitignore @@ -152,4 +152,5 @@ cython_debug/ 实验六/models/ # dataset -实验七/cache/ \ No newline at end of file +实验七/cache/ +实验七/models/ \ No newline at end of file diff --git a/实验七/2.pretrain.py b/实验七/2.pretrain.py new file mode 100644 index 0000000..406425b --- /dev/null +++ b/实验七/2.pretrain.py @@ -0,0 +1,39 @@ +import cv2 as cv +import os +import tqdm + +# 处理图像 +def pretrain(img_path,output_path): + img=cv.imread(img_path, cv.IMREAD_GRAYSCALE) + img = cv.resize(img, (50, 50)) + _,img=cv.threshold(img,127,255,cv.THRESH_BINARY) + img=cv.blur(img,(3,3)) + os.makedirs(os.path.dirname(output_path), exist_ok=True) + cv.imwrite(output_path, img) + +# 获取文件路径 +def get_img_name(directory, extensions=None): + if extensions is None: + extensions = ['.png', '.jpg','.jpeg'] + files = [] + for root, dirs, file_names in os.walk(directory): + for file_name in file_names: + if any(file_name.lower().endswith(ext) for ext in extensions): + files.append(os.path.join(root, file_name)) + return files + +# 处理非人脸数据集 +os.makedirs('cache/pretrained/non_face/', exist_ok=True) +non_face_files=get_img_name('cache/dataset/non_face/') +print('预处理非人脸数据中:') +for img_path in tqdm.tqdm(non_face_files): + pretrain(img_path, os.path.join('cache/pretrained/non_face', os.path.basename(img_path))) + +# 处理人脸数据集 +os.makedirs('cache/pretrained/face/', exist_ok=True) +face_files=get_img_name('cache/dataset/face/') +print('预处理人脸数据中:') +for img_path in tqdm.tqdm(face_files): + relative_path=os.path.relpath(img_path, 'cache/dataset/face/') + output_path=os.path.join('cache/pretrained/face', relative_path) + pretrain(img_path, output_path) diff --git a/实验七/3.train.py b/实验七/3.train.py new file mode 100644 index 0000000..c42acba --- /dev/null +++ b/实验七/3.train.py @@ -0,0 +1,88 @@ +import numpy as np +import cv2 as cv +import os +import tqdm +from sklearn.metrics import accuracy_score +from sklearn.model_selection import train_test_split +from sklearn.svm import SVC +from joblib import dump + + +# 加载图像 +def load_dataset(directory): + files = [] + for root, dirs, file_list in os.walk(directory): + for file in file_list: + files.append(os.path.join(root, file)) + return files + +# 提取特征 +## 提取轮廓特征 +def extract_contour_features(img): + contours, _ = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + contour = contours[0] + area = cv.contourArea(contour) + perimeter = cv.arcLength(contour, True) + return [area, perimeter] + +## 提取形状特征 +def extract_shape_features(contour): + x, y, w, h = cv.boundingRect(contour) + aspect_ratio = float(w) / h + rect_area = w * h + shape_factor = cv.contourArea(contour) / rect_area + return [aspect_ratio, shape_factor] + +## 计算HU矩 +def extract_hu_moments(contour): + moments = cv.moments(contour) + hu_moments = cv.HuMoments(moments) + return hu_moments.flatten() + +## 特征向量构建 +def extract_features(img_path): + img = cv.imread(img_path, cv.IMREAD_GRAYSCALE) + if img is None: + raise FileNotFoundError(f"无法加载图像: {img_path}") + + _, img_bin = cv.threshold(img, 128, 255, cv.THRESH_BINARY) + contours, _ = cv.findContours(img_bin, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + if len(contours) == 0: + return [0] * 11 + contour = contours[0] + contour_features = extract_contour_features(img_bin) + shape_features = extract_shape_features(contour) + hu_moments = extract_hu_moments(contour) + feature_vector = contour_features + shape_features + hu_moments.tolist() + return feature_vector + [0] * (11 - len(feature_vector)) + +# 加载数据集和标签 +face_paths = load_dataset("cache/pretrained/face/") +face_train_data = [(path, True) for path in face_paths] +non_face_paths = load_dataset("cache/pretrained/non_face/") +non_face_train_data = [(path, False) for path in non_face_paths] + +train_test_data = face_train_data + non_face_train_data +train_data, test_data = train_test_split(train_test_data, test_size=0.3) + +# 提取特征和标签 +X_train = np.vstack([extract_features(train_path) for train_path, _ in tqdm.tqdm(train_data, desc="数据集特征提取中:")]) +X_test = np.vstack([extract_features(test_path) for test_path, _ in tqdm.tqdm(test_data, desc="测试集特征提取中:")]) + +Y_train = np.array([label for _, label in train_data]) +Y_test = np.array([label for _, label in test_data]) + + +# 训练分类器 +classifier = SVC(kernel='linear', max_iter=10000) +classifier.fit(X_train, Y_train) + +# 评估 +Y_pred = classifier.predict(X_test) + +accuracy = accuracy_score(Y_test, Y_pred) +print(f"准确率: {accuracy * 100:.2f}%") + +# 保存模型 +os.makedirs("models", exist_ok=True) +dump(classifier, "models/classifier.pkl") diff --git a/实验七/main.py b/实验七/main.py index eb389a0..97c77ad 100644 --- a/实验七/main.py +++ b/实验七/main.py @@ -1,16 +1,111 @@ -# 这是一个示例 Python 脚本。 +import cv2 as cv +import numpy as np +from joblib import load -# 按 Shift+F10 执行或将其替换为您的代码。 -# 按 双击 Shift 在所有地方搜索类、文件、工具窗口、操作和设置。 +classifier = load('models/classifier.pkl') + +# 预处理图像 +def pre_detect(img): + pre_img = img.copy() + pre_img = cv.resize(pre_img, (50, 50)) + pre_img = cv.cvtColor(pre_img, cv.COLOR_BGR2GRAY) + _, pre_img = cv.threshold(pre_img, 127, 255, cv.THRESH_BINARY) + pre_img = cv.blur(pre_img, (3, 3)) + return pre_img + +# 特征提取 +def pre_detect(img): + pre_img = img.copy() + pre_img = cv.resize(pre_img, (50, 50)) + pre_img = cv.cvtColor(pre_img, cv.COLOR_BGR2GRAY) + _, pre_img = cv.threshold(pre_img, 127, 255, cv.THRESH_BINARY) + pre_img = cv.blur(pre_img, (3, 3)) + return pre_img + +# 特征提取 +def extract_contour_features(img): + contours, _ = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + if len(contours) == 0: + return [0, 0] # 如果没有轮廓,返回默认值 + contour = contours[0] + area = cv.contourArea(contour) + perimeter = cv.arcLength(contour, True) + return [area, perimeter] + +def extract_shape_features(contour): + x, y, w, h = cv.boundingRect(contour) + aspect_ratio = float(w) / h + rect_area = w * h + shape_factor = cv.contourArea(contour) / rect_area + return [aspect_ratio, shape_factor] + +def extract_hu_moments(contour): + moments = cv.moments(contour) + hu_moments = cv.HuMoments(moments) + return hu_moments.flatten() -def print_hi(name): - # 在下面的代码行中使用断点来调试脚本。 - print(f'Hi, {name}') # 按 Ctrl+F8 切换断点。 +def extract_features(img): + contours, _ = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + if len(contours) == 0: + # 如果没有找到轮廓,返回 11 个零,保持特征数量一致 + return [0] * 11 + contour = contours[0] + + # 提取轮廓特征 + contour_features = extract_contour_features(img) + + # 提取形状特征 + shape_features = extract_shape_features(contour) + + # 提取 Hu 矩 + hu_moments = extract_hu_moments(contour) + + # 合并所有特征为一个特征向量,确保总共有 11 个特征 + feature_vector = contour_features + shape_features + hu_moments.tolist() + return feature_vector -# 按装订区域中的绿色按钮以运行脚本。 -if __name__ == '__main__': - print_hi('PyCharm') +# 读取图像并进行预处理 +img = cv.imread('test.jpg') +pre_img = pre_detect(img) -# 访问 https://www.jetbrains.com/help/pycharm/ 获取 PyCharm 帮助 +features = extract_features(pre_img) + +features = np.array(features).reshape(1, -1) + +predict_label = classifier.predict(features) + +cv.imshow('face? ' + str(predict_label[0]), img) +cv.waitKey(0) +cv.destroyAllWindows() + +# 读取视频并进行检测 +cap = cv.VideoCapture(1) + +while True: + ret, frame = cap.read() + if not ret: + break + + # 预处理 + pre_img = pre_detect(frame) + + # 提取特征 + features = extract_features(pre_img) + features=np.array(features).reshape(1, -1) + + predict_label = classifier.predict(features) + + # 在帧上显示预测结果 + label_text = 'Face' if predict_label[0] else 'Non-Face' + cv.putText(frame, label_text, (50, 50), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv.LINE_AA) + + # 展示 + cv.imshow('video', frame) + + if cv.waitKey(1) & 0xFF == ord('q'): + break + +cap.release() +cv.destroyAllWindows() diff --git a/实验七/test.jpg b/实验七/test.jpg new file mode 100644 index 0000000..a89466b Binary files /dev/null and b/实验七/test.jpg differ diff --git a/实验六/main.py b/实验六/main.py index 5678a2f..a7d5198 100644 --- a/实验六/main.py +++ b/实验六/main.py @@ -13,6 +13,7 @@ rcParams['font.sans-serif'] = ['SimHei'] rcParams['axes.unicode_minus'] = False # 预处理图像 +img=cv.resize(img,(28,28)) _,img_classifier=cv.threshold(img, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU) img_classifier=cv.blur(img,(3,3))