什么是F0 Contours

本文探讨了F0Contours,即FundamentalFrequencyContours,它是音高分析的核心概念,主要介绍其定义、如何与音高关联以及提取方法。通过实例解析,理解语音与旋律中的基频规律及其在信息技术中的应用。

什么是F0 Contours

​ ​ F0 Contours, 全称为Fundamental Frequency Contours, 它与Pitch Contours所指相同。

​ ​ 音高(pitch)是声音的三大属性(音量、音高、音色)之一。除去个别极端情况,音高是由声音的基频(fundamental frequency, 简记为 f 0 f_0 f0

import cv2 import numpy as np import imutils import pytesseract import os import easyocr # Tesseract 路径配置 pytesseract.pytesseract.tesseract_cmd = r'C:\Users\26281\tesseract\tesseract.exe' os.environ['TESSDATA_PREFIX'] = r'C:\Users\26281\tesseract\tessdata' # 初始化 EasyOCR 识别器 reader = easyocr.Reader(['ch_sim', 'en'], gpu=False) # 1. 读取图像 img_path = "D:/pro/pythonProject4/4.23.jpg" img = cv2.imread(img_path, cv2.IMREAD_COLOR) if img is None: print("无法识别图像!") exit() # 2. 预处理 img = cv2.resize(img, (600, 400)) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) edged = cv2.Canny(gray, 30, 200) # 3. 找轮廓并筛选车牌轮廓 contours = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) contours = imutils.grab_contours(contours) contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10] screenCnt = None for c in contours: peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.018 * peri, True) if len(approx) == 4: screenCnt = approx break if screenCnt is None: print("未能获取到有效车牌轮廓") exit() # 4. 提取车牌区域 cv2.drawContours(img, [screenCnt], -1, (0, 0, 255), 3) mask = np.zeros(gray.shape, np.uint8) cv2.fillPoly(mask, [screenCnt], 255) (x, y) = np.where(mask == 255) if len(x) == 0 or len(y) == 0: print("无效的车牌区域!") exit() (topx, topy) = (np.min(x), np.min(y)) (bottomx, bottomy) = (np.max(x), np.max(y)) cropped_gray = gray[topx:bottomx + 1, topy:bottomy + 1] cropped_color = img[topx:bottomx + 1, topy:bottomy + 1] # 保存彩色版本用于 EasyOCR # 5. 单独提取省份区域进行识别 h, w = cropped_gray.shape province_width = int(w * 0.25) # 取车牌宽度的1/4作为省份简称区域 province_region_gray = cropped_gray[:, :province_width] province_region_color = cropped_color[:, :province_width] # 6. 使用 EasyOCR 识别省份 province_results = reader.readtext(province_region_color) province = "" for (bbox, text, prob) in province_results: if text in '粤苏浙京沪津渝冀晋蒙辽吉黑皖闽赣鲁豫鄂湘粤桂琼川贵云藏陕甘青宁新' and prob > 0.5: province = text break # 7. 使用 EasyOCR 识别车牌其他部分 char_region_color = cropped_color[:, province_width:] results = reader.readtext(char_region_color) easy_text = "" for (bbox, text, prob) in results: if len(text) >= 5 and prob > 0.5: # 至少5个字符且置信度>0.5 easy_text = text.strip().replace(" ", "") break # 8. 处理识别结果 if province and easy_text: print("车牌省份:", province) print("车牌号码:", easy_text) else: print("EasyOCR 识别不完整,尝试 Tesseract") # 9. 使用 Tesseract 进行识别 # 配置 Tesseract 参数 tess_config = ( '-c tessedit_char_whitelist=粤苏浙京沪津渝冀晋蒙辽吉黑皖闽赣鲁豫鄂湘粤桂琼川贵云藏陕甘青宁新0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ' '--oem 3 --psm 6' ) # 对车牌进行二值化处理 _, binary = cv2.threshold(cropped_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 使用 Tesseract 识别 text = pytesseract.image_to_string(binary, config=tess_config, lang='chi_sim+eng') text = text.strip().replace(" ", "").replace("\n", "") if text: # 尝试分离省份和车牌其他部分 province = text[0] if len(text) > 0 and text[ 0] in '粤苏浙京沪津渝冀晋蒙辽吉黑皖闽赣鲁豫鄂湘粤桂琼川贵云藏陕甘青宁新' else "" plate_number = text[1:] if len(text) > 1 else "" print("车牌省份:", province) print("车牌号码:", plate_number) else: print("Tesseract 识别失败") # 10. 图像显示(在有UI环境下) if os.environ.get('DISPLAY') or cv2.getWindowProperty('dummy', cv2.WND_PROP_VISIBLE) >= 0: img = cv2.resize(img, (500, 300)) cv2.imshow('Detected Plate', img) cv2.imshow('Cropped Plate', cropped_gray) cv2.imshow('Province Region', province_region_color) cv2.imshow('Char Region', char_region_color) cv2.waitKey(0) cv2.destroyAllWindows() 输出车牌正确结果应是粤F0A943,但是输出结果是D:\pro\pythonProject\venv\Scripts\python.exe D:\pro\pythonProject\测试.py Using CPU. Note: This module is much faster with a GPU. 车牌省份: 粤 车牌号码: 0A943 [ WARN:0@6.519] global window.cpp:302 cvGetWindowProperty No UI backends available. Use OPENCV_LOG_LEVEL=DEBUG for investigation,车牌识别不能完整是为什么
06-12
import tkinter as tk from tkinter import filedialog, messagebox, ttk import os import threading import time import cv2 import numpy as np import pandas as pd from PIL import Image, ImageTk import pickle import json from sklearn.preprocessing import MinMaxScaler from scipy.spatial.distance import euclidean import warnings warnings.filterwarnings("ignore") # 常量定义 FEATURE_CACHE_FILE = "disease_features.pkl" DISEASE_INFO_FILE = "disease_info.json" # 高效图像预处理(传统方法优化) def efficient_preprocess_image(image_path): """使用传统图像处理技术进行高效预处理""" try: img = cv2.imread(image_path) if img is None: print(f"警告:无法读取图像 {image_path}") return None, None # 转换到RGB色彩空间,便于处理和显示 img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 增强图像对比度 img_rgb = cv2.convertScaleAbs(img_rgb, alpha=1.5, beta=0) # 传统方法1: 直方图均衡化(只处理亮度通道) img_yuv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2YUV) img_yuv[:, :, 0] = cv2.equalizeHist(img_yuv[:, :, 0]) img_enhanced = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2RGB) # 传统方法2: 减少噪声的中值滤波 img_filtered = cv2.medianBlur(img_enhanced, 5) # 转换为灰度图,用于后续处理 img_gray = cv2.cvtColor(img_filtered, cv2.COLOR_RGB2GRAY) return img_filtered, img_gray except Exception as e: print(f"预处理错误: {str(e)}") return None, None # 高效病害区域分割(传统方法) def fast_segment_disease_areas(img_rgb, img_gray): """使用传统图像处理方法快速分割病害区域""" try: if img_rgb is None or img_gray is None: return None, None # 传统方法3: 自适应阈值(快速且有效) binary = cv2.adaptiveThreshold( img_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2 ) # 传统方法4: 简单的形态学操作 kernel = np.ones((3, 3), np.uint8) opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=1) closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=1) # 轮廓检测和筛选(保留有意义的区域) contours, _ = cv2.findContours(closing, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) mask = np.zeros_like(img_gray) # 基于图像大小动态确定最小轮廓面积 min_area = max(50, (img_gray.shape[0] * img_gray.shape[1]) // 2000) for cnt in contours: area = cv2.contourArea(cnt) if area > min_area: cv2.drawContours(mask, [cnt], -1, 255, -1) # 应用掩码到原始图像 segmented = cv2.bitwise_and(img_rgb, img_rgb, mask=mask) return segmented, mask except Exception as e: print(f"分割错误: {str(e)}") return None, None # 高效特征提取(传统方法) def fast_extract_features(img_rgb, img_gray, mask): """提取图像的关键特征,使用传统方法""" features = {} if img_rgb is None or mask is None or np.sum(mask) == 0: return features try: # 1. 颜色特征(统计RGB通道) for i, color in enumerate(['R', 'G', 'B']): channel_data = img_rgb[:, :, i][mask > 0] if len(channel_data) > 0: features[f"{color}_Mean"] = float(np.mean(channel_data)) features[f"{color}_Std"] = float(np.std(channel_data)) features[f"{color}_Median"] = float(np.median(channel_data)) # 添加中位数 features[f"{color}_Range"] = float(np.max(channel_data) - np.min(channel_data)) # 2. 纹理特征(灰度共生矩阵简化版) masked_gray = img_gray.copy() masked_gray[mask == 0] = 0 glcm_h = np.zeros((8, 8), dtype=np.float32) glcm_v = np.zeros((8, 8), dtype=np.float32) reduced_gray = (masked_gray // 32).astype(np.uint8) height, width = reduced_gray.shape for y in range(height): for x in range(width - 1): if mask[y, x] > 0 and mask[y, x + 1] > 0: i, j = reduced_gray[y, x], reduced_gray[y, x + 1] glcm_h[i, j] += 1 for y in range(height - 1): for x in range(width): if mask[y, x] > 0 and mask[y + 1, x] > 0: i, j = reduced_gray[y, x], reduced_gray[y + 1, x] glcm_v[i, j] += 1 if np.sum(glcm_h) > 0: glcm_h = glcm_h / np.sum(glcm_h) if np.sum(glcm_v) > 0: glcm_v = glcm_v / np.sum(glcm_v) features['GLCM_Energy'] = float(np.sum(glcm_h ** 2) + np.sum(glcm_v ** 2)) / 2 features['GLCM_Contrast'] = float((np.sum((np.arange(8)[:, np.newaxis] - np.arange(8)[np.newaxis, :]) ** 2 * glcm_h) + np.sum((np.arange(8)[:, np.newaxis] - np.arange(8)[np.newaxis, :]) ** 2 * glcm_v)) / 2) # 3. 形状特征 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) features['Region_Count'] = len(contours) total_area = np.sum(mask > 0) features['Disease_Area'] = float(total_area) features['Coverage_Ratio'] = float(total_area / (mask.shape[0] * mask.shape[1])) if len(contours) > 0: areas = [] perimeters = [] for cnt in contours: area = cv2.contourArea(cnt) perimeter = cv2.arcLength(cnt, True) areas.append(area) perimeters.append(perimeter) features['Avg_Region_Area'] = float(np.mean(areas)) features['Avg_Region_Perimeter'] = float(np.mean(perimeters)) features['Area_Std'] = float(np.std(areas)) features['Area_Max'] = float(np.max(areas)) # 添加基于HSV颜色空间的特征 hsv_img = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV) for i, color in enumerate(['H', 'S', 'V']): channel_data = hsv_img[:, :, i][mask > 0] if len(channel_data) > 0: features[f"{color}_Mean"] = float(np.mean(channel_data)) features[f"{color}_Std"] = float(np.std(channel_data)) features[f"{color}_Median"] = float(np.median(channel_data)) # 添加中位数 features[f"{color}_Range"] = float(np.max(channel_data) - np.min(channel_data)) # 添加颜色直方图特征 hist_size = 8 for i, color in enumerate(['H', 'S', 'V']): hist = cv2.calcHist([hsv_img], [i], mask, [hist_size], [0, 256 if color != 'H' else 180]) hist = cv2.normalize(hist, None).flatten() for j in range(hist_size): features[f"{color}_Hist_{j}"] = float(hist[j]) return features except Exception as e: print(f"特征提取错误: {str(e)}") return {} # 改进的特征相似度计算 def compute_feature_similarity(features1, features2, feature_weights=None): """计算两个特征向量之间的加权相似度""" if not features1 or not features2: return 0.0 # 默认特征权重,可根据重要性调整 if feature_weights is None: feature_weights = { 'R_Mean': 1.5, 'G_Mean': 1.5, 'B_Mean': 1.5, 'R_Std': 1.0, 'G_Std': 1.0, 'B_Std': 1.0, 'R_Median': 1.0, 'G_Median': 1.0, 'B_Median': 1.0, 'H_Mean': 2.0, 'S_Mean': 2.0, 'V_Mean': 1.5, 'H_Std': 1.5, 'S_Std': 1.5, 'V_Std': 1.0, 'H_Median': 1.0, 'S_Median': 1.0, 'V_Median': 1.0, 'GLCM_Energy': 1.2, 'GLCM_Contrast': 1.2, 'Disease_Area': 0.8, 'Coverage_Ratio': 1.5, 'Region_Count': 1.0, 'Avg_Region_Area': 1.0, 'Avg_Region_Perimeter': 0.8, 'Area_Std': 0.7, 'Area_Max': 0.8 } # 为颜色直方图特征添加权重 for i in range(8): feature_weights[f'H_Hist_{i}'] = 1.2 feature_weights[f'S_Hist_{i}'] = 1.2 feature_weights[f'V_Hist_{i}'] = 1.0 common_keys = set(features1.keys()) & set(features2.keys()) & set(feature_weights.keys()) if not common_keys: return 0.0 weighted_distance = 0.0 total_weight = 0.0 normalization_values = { 'R_Mean': 255.0, 'G_Mean': 255.0, 'B_Mean': 255.0, 'R_Std': 128.0, 'G_Std': 128.0, 'B_Std': 128.0, 'R_Median': 255.0, 'G_Median': 255.0, 'B_Median': 255.0, 'H_Mean': 180.0, 'S_Mean': 255.0, 'V_Mean': 255.0, 'H_Std': 90.0, 'S_Std': 128.0, 'V_Std': 128.0, 'H_Median': 180.0, 'S_Median': 255.0, 'V_Median': 255.0, 'GLCM_Energy': 1.0, 'GLCM_Contrast': 1.0, 'Coverage_Ratio': 1.0 } for key in common_keys: value1 = features1[key] value2 = features2[key] if key.startswith('Hist_'): diff = abs(value1 - value2) else: norm_value = normalization_values.get(key, max(abs(value1), abs(value2)) if max(abs(value1), abs(value2)) > 0 else 1.0) diff = abs(value1 - value2) / norm_value weight = feature_weights[key] weighted_distance += diff * weight total_weight += weight if total_weight == 0: return 0.0 avg_weighted_distance = weighted_distance / total_weight similarity = 1.0 - min(avg_weighted_distance, 1.0) return similarity # 基于相似度的快速分类 def fast_classify_disease(features, reference_features, threshold=0.45): """基于特征相似度的快速分类""" if not features or not reference_features: return None try: similarities = {} for disease, ref_features in reference_features.items(): similarity = compute_feature_similarity(features, ref_features) similarities[disease] = similarity if not similarities: return "未知" best_match = max(similarities.items(), key=lambda x: x[1]) disease, similarity = best_match if similarity < threshold: return "未知" return disease except Exception as e: print(f"分类错误: {str(e)}") return None class DiseaseDetectionApp: def __init__(self, root): self.root = root self.root.title("植物病虫害识别系统") self.root.geometry("1280x900") self.root.configure(bg="#f0f0f0") # 变量初始化 self.dataset_path = tk.StringVar() self.reference_features = {} self.features_db = [] self.current_image_path = None self.processed_image = None self.segmented_image = None self.disease_info = {} # 创建UI组件 self.create_widgets() # 尝试加载已保存的特征 self.load_features() def get_disease_description(self, features): """根据特征信息生成病害描述""" if not features: return "未检测到有效特征,无法生成病害描述。" description = "根据图像特征分析,病害具有以下特征:\n\n" # 颜色特征描述 color_description = [] for color in ['R', 'G', 'B']: mean = features.get(f"{color}_Mean", 0) std = features.get(f"{color}_Std", 0) color_description.append(f"{color}通道平均值:{mean:.2f},标准差:{std:.2f}") # 纹理特征描述 glcm_energy = features.get('GLCM_Energy', 0) glcm_contrast = features.get('GLCM_Contrast', 0) texture_description = f"纹理能量:{glcm_energy:.4f},纹理对比度:{glcm_contrast:.4f}" # 形状特征描述 region_count = features.get('Region_Count', 0) avg_area = features.get('Avg_Region_Area', 0) coverage_ratio = features.get('Coverage_Ratio', 0) shape_description = f"病斑数量:{region_count},平均病斑面积:{avg_area:.2f},覆盖率:{coverage_ratio:.2f}%" description += "颜色特征:\n" + "\n".join(color_description) + "\n\n" description += "纹理特征:\n" + texture_description + "\n\n" description += "形状特征:\n" + shape_description return description def create_widgets(self): # 顶部标题 title_frame = tk.Frame(self.root, bg="#2c3e50", pady=10) title_frame.pack(fill="x") tk.Label(title_frame, text="植物病虫害识别系统", font=("Arial", 20, "bold"), bg="#2c3e50", fg="white").pack() # 主要内容区域 main_frame = tk.Frame(self.root, bg="#f0f0f0") main_frame.pack(fill="both", expand=True, padx=10, pady=10) # 左侧图片显示区域 left_frame = tk.Frame(main_frame, bg="#f0f0f0") left_frame.pack(side="left", fill="both", expand=True, padx=5, pady=5) # 原始图像显示 original_frame = tk.LabelFrame(left_frame, text="原始图像", font=("Arial", 12), bg="#f0f0f0") original_frame.pack(fill="both", expand=True, padx=5, pady=5) self.original_canvas = tk.Canvas(original_frame, bg="#ffffff", width=400, height=300) self.original_canvas.pack(fill="both", expand=True, padx=5, pady=5) # 处理后图像显示 processed_frame = tk.LabelFrame(left_frame, text="处理后图像", font=("Arial", 12), bg="#f0f0f0") processed_frame.pack(fill="both", expand=True, padx=5, pady=5) self.processed_canvas = tk.Canvas(processed_frame, bg="#ffffff", width=400, height=300) self.processed_canvas.pack(fill="both", expand=True, padx=5, pady=5) # 右侧控制和信息显示区域 right_frame = tk.Frame(main_frame, bg="#f0f0f0") right_frame.pack(side="right", fill="both", expand=True, padx=5, pady=5) # 控制面板 control_frame = tk.LabelFrame(right_frame, text="控制面板", font=("Arial", 12), bg="#f0f0f0") control_frame.pack(fill="x", padx=5, pady=5) # 数据集路径和选择按钮 path_frame = tk.Frame(control_frame, bg="#f0f0f0") path_frame.pack(fill="x", padx=5, pady=5) tk.Label(path_frame, text="数据集路径:", bg="#f0f0f0").pack(side="left", padx=5) tk.Entry(path_frame, textvariable=self.dataset_path, width=30).pack(side="left", padx=5, expand=True, fill="x") tk.Button(path_frame, text="选择", command=self.select_dataset, bg="#3498db", fg="white").pack(side="right", padx=5) # 置信度阈值设置 threshold_frame = tk.Frame(control_frame, bg="#f0f0f0") threshold_frame.pack(fill="x", padx=5, pady=5) tk.Label(threshold_frame, text="置信度阈值:", bg="#f0f0f0").pack(side="left", padx=5) self.confidence_threshold = tk.DoubleVar(value=0.45) tk.Scale(threshold_frame, variable=self.confidence_threshold, from_=0.0, to=1.0, resolution=0.05, orient="horizontal", bg="#f0f0f0").pack(side="left", expand=True, fill="x", padx=5) # 功能按钮 button_frame = tk.Frame(control_frame, bg="#f0f0f0") button_frame.pack(fill="x", padx=5, pady=5) tk.Button(button_frame, text="提取特征", command=self.extract_features, bg="#2ecc71", fg="white", width=12).pack(side="left", padx=5, pady=5) tk.Button(button_frame, text="保存特征", command=self.save_features, bg="#9b59b6", fg="white", width=12).pack(side="left", padx=5, pady=5) tk.Button(button_frame, text="加载特征", command=self.load_features, bg="#f39c12", fg="white", width=12).pack(side="left", padx=5, pady=5) tk.Button(button_frame, text="识别图片", command=self.identify_image, bg="#e74c3c", fg="white", width=12).pack(side="left", padx=5, pady=5) # 新增按钮:保存处理后图像 tk.Button(button_frame, text="保存当前图像", command=self.save_processed_image, bg="#1abc9c", fg="white", width=12).pack(side="left", padx=5, pady=5) # 识别结果显示 result_frame = tk.LabelFrame(right_frame, text="识别结果", font=("Arial", 12), bg="#f0f0f0") result_frame.pack(fill="both", expand=True, padx=5, pady=5) # 病害名称和置信度 info_frame = tk.Frame(result_frame, bg="#f0f0f0") info_frame.pack(fill="x", padx=5, pady=5) self.disease_var = tk.StringVar(value="未检测") tk.Label(info_frame, text="病害名称:", font=("Arial", 12), bg="#f0f0f0").grid(row=0, column=0, sticky="w", padx=5, pady=5) tk.Label(info_frame, textvariable=self.disease_var, font=("Arial", 12, "bold"), bg="#f0f0f0").grid(row=0, column=1, sticky="w", padx=5, pady=5) # 特征信息 feature_frame = tk.LabelFrame(result_frame, text="特征信息", font=("Arial", 12), bg="#f0f0f0") feature_frame.pack(fill="both", expand=True, padx=5, pady=5) # 添加滚动条 feature_scroll = tk.Scrollbar(feature_frame) feature_scroll.pack(side="right", fill="y") self.feature_text = tk.Text(feature_frame, height=10, width=40, bg="white", wrap="word", yscrollcommand=feature_scroll.set) self.feature_text.pack(fill="both", expand=True, padx=5, pady=5) feature_scroll.config(command=self.feature_text.yview) # 病害描述 desc_frame = tk.LabelFrame(result_frame, text="病害描述", font=("Arial", 12), bg="#f0f0f0") desc_frame.pack(fill="both", expand=True, padx=5, pady=5) # 添加滚动条 desc_scroll = tk.Scrollbar(desc_frame) desc_scroll.pack(side="right", fill="y") self.desc_text = tk.Text(desc_frame, height=8, width=40, bg="white", wrap="word", yscrollcommand=desc_scroll.set) self.desc_text.pack(fill="both", expand=True, padx=5, pady=5) desc_scroll.config(command=self.desc_text.yview) # 状态栏 self.status_var = tk.StringVar(value="就绪") status_bar = tk.Label(self.root, textvariable=self.status_var, bd=1, relief=tk.SUNKEN, anchor=tk.W) status_bar.pack(side=tk.BOTTOM, fill=tk.X) def select_dataset(self): """选择数据集目录""" folder_selected = filedialog.askdirectory() if folder_selected: self.dataset_path.set(folder_selected) def identify_image(self): """识别单张图片""" file_path = filedialog.askopenfilename( filetypes=[("图片文件", "*.jpg;*.jpeg;*.png;*.bmp")] ) if not file_path: return self.status_var.set("正在处理图像...") self.root.update() # 启动处理线程 threading.Thread(target=self._process_single_image, args=(file_path,)).start() def _process_single_image(self, file_path): """在单独线程中处理图像""" try: # 保存当前图像路径 self.current_image_path = file_path # 显示原始图像 img = Image.open(file_path) self.display_image(img, self.original_canvas) # 预处理图像 processed_img, img_gray = efficient_preprocess_image(file_path) if processed_img is None: self.status_var.set("图像处理失败") return # 分割病害区域 segmented_img, mask = fast_segment_disease_areas(processed_img, img_gray) if segmented_img is None: self.status_var.set("病害分割失败") return # 保存处理后的图像供后续保存使用 self.processed_image = Image.fromarray(processed_img) self.segmented_image = Image.fromarray(segmented_img) # 显示分割后图像 self.display_image(self.segmented_image, self.processed_canvas) # 提取特征 features = fast_extract_features(processed_img, img_gray, mask) # 分类 result = fast_classify_disease(features, self.reference_features, threshold=self.confidence_threshold.get()) # 显示结果 self.disease_var.set(result if result else "未检测到") # 显示特征 self.display_features(features) # 显示病害描述 self.desc_text.delete(1.0, tk.END) self.desc_text.insert(tk.END, self.get_disease_description(features)) self.status_var.set("识别完成") except Exception as e: self.status_var.set(f"处理错误: {str(e)}") print(f"处理错误: {str(e)}") def extract_features(self): """从数据集中提取特征""" dataset_path = self.dataset_path.get() if not dataset_path or not os.path.exists(dataset_path): messagebox.showerror("错误", "请选择有效的数据集路径") return # 开始提取特征 self.status_var.set("正在提取特征...") self.root.update() # 启动提取线程 threading.Thread(target=self._extract_features_thread, args=(dataset_path,)).start() def _extract_features_thread(self, dataset_path): """在单独线程中提取特征""" try: # 清空当前特征 self.reference_features = {} features_db = [] processed_count = 0 # 遍历数据集目录 for disease_folder in os.listdir(dataset_path): disease_path = os.path.join(dataset_path, disease_folder) if not os.path.isdir(disease_path): continue disease_features = [] # 处理每个疾病文件夹中的图像 for img_file in os.listdir(disease_path): if not img_file.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp')): continue img_path = os.path.join(disease_path, img_file) # 更新状态 self.status_var.set(f"处理: {img_file}") self.root.update() # 预处理图像 processed_img, img_gray = efficient_preprocess_image(img_path) if processed_img is None: continue # 分割病害区域 segmented_img, mask = fast_segment_disease_areas(processed_img, img_gray) if segmented_img is None: continue # 提取特征 features = fast_extract_features(processed_img, img_gray, mask) if features: disease_features.append(features) features_db.append({ 'disease': disease_folder, 'file': img_file, 'features': features }) processed_count += 1 # 计算每种疾病的平均特征 if disease_features: avg_features = {} for feature_key in disease_features[0].keys(): values = [feat.get(feature_key, 0) for feat in disease_features if feature_key in feat] if values: avg_features[feature_key] = sum(values) / len(values) self.reference_features[disease_folder] = avg_features # 保存特征数据库 self.features_db = features_db self.status_var.set(f"特征提取完成,共处理 {processed_count} 张图像") messagebox.showinfo("完成", f"特征提取完成,共处理 {processed_count} 张图像") except Exception as e: self.status_var.set(f"特征提取错误: {str(e)}") messagebox.showerror("错误", f"特征提取过程中发生错误: {str(e)}") def save_features(self): """保存提取的特征到文件""" if not self.reference_features: messagebox.showerror("错误", "没有可保存的特征数据") return try: # 保存特征数据 data_to_save = { 'reference_features': self.reference_features, 'features_db': self.features_db } with open(FEATURE_CACHE_FILE, 'wb') as f: pickle.dump(data_to_save, f) self.status_var.set("特征数据已保存") messagebox.showinfo("成功", f"特征数据已保存至 {FEATURE_CACHE_FILE}") except Exception as e: self.status_var.set(f"保存特征失败: {str(e)}") messagebox.showerror("错误", f"保存特征时发生错误: {str(e)}") def load_features(self): """加载保存的特征数据""" if not os.path.exists(FEATURE_CACHE_FILE): self.status_var.set("未找到保存的特征数据") return try: with open(FEATURE_CACHE_FILE, 'rb') as f: data = pickle.load(f) self.reference_features = data.get('reference_features', {}) self.features_db = data.get('features_db', []) disease_count = len(self.reference_features) image_count = len(self.features_db) self.status_var.set(f"已加载特征数据: {disease_count} 种病害, {image_count} 张图像") return True except Exception as e: self.status_var.set(f"加载特征失败: {str(e)}") return False def display_image(self, img, canvas): """在画布上显示图像""" try: # 调整图像大小以适应画布 canvas_width = canvas.winfo_width() canvas_height = canvas.winfo_height() # 确保画布尺寸有效 if canvas_width < 50: canvas_width = 400 if canvas_height < 50: canvas_height = 300 # 计算等比例缩放 img_width, img_height = img.size scale = min(canvas_width / img_width, canvas_height / img_height) new_width = int(img_width * scale) new_height = int(img_height * scale) resized_img = img.resize((new_width, new_height), Image.LANCZOS) # 转换为PhotoImage photo = ImageTk.PhotoImage(resized_img) # 保存引用,防止垃圾回收 canvas.image = photo # 清除画布并显示图像 canvas.delete("all") canvas.config(width=canvas_width, height=canvas_height) canvas.create_image(canvas_width // 2, canvas_height // 2, image=photo) except Exception as e: print(f"显示图像错误: {str(e)}") def display_features(self, features): """显示特征信息""" self.feature_text.delete(1.0, tk.END) if not features: self.feature_text.insert(tk.END, "未提取到有效特征") return # 分类显示特征 feature_groups = { "颜色特征": ["R_Mean", "G_Mean", "B_Mean", "R_Std", "G_Std", "B_Std", "H_Mean", "S_Mean", "V_Mean", "R_Range", "G_Range", "B_Range"], "纹理特征": ["GLCM_Energy", "GLCM_Contrast"], "形状特征": ["Disease_Area", "Coverage_Ratio", "Region_Count", "Avg_Region_Area", "Avg_Region_Perimeter", "Area_Std", "Area_Max"] } for group, feature_keys in feature_groups.items(): self.feature_text.insert(tk.END, f"{group}:\n", "group") for key in feature_keys: if key in features: value = features[key] if isinstance(value, float): self.feature_text.insert(tk.END, f" {key}: {value:.4f}\n") else: self.feature_text.insert(tk.END, f" {key}: {value}\n") self.feature_text.insert(tk.END, "\n") def save_processed_image(self): """保存处理后的图像""" if self.segmented_image is None: messagebox.showerror("错误", "没有可保存的处理后图像") return try: # 定义保存路径 file_path = filedialog.asksaveasfilename( defaultextension=".png", filetypes=[("PNG文件", "*.png"), ("JPEG文件", "*.jpg"), ("所有文件", "*.*")] ) if not file_path: return # 保存图像 self.segmented_image.save(file_path) self.status_var.set(f"图像已保存至 {file_path}") messagebox.showinfo("成功", f"图像已保存至 {file_path}") except Exception as e: self.status_var.set(f"保存图像失败: {str(e)}") messagebox.showerror("错误", f"保存图像时发生错误: {str(e)}") if __name__ == "__main__": root = tk.Tk() app = DiseaseDetectionApp(root) root.mainloop()完善对水稻病虫害识别系统代码完善,将完善后代码完整展现出来
05-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值