diff --git a/20240529RGBtest3/classifer.py b/20240529RGBtest3/classifer.py index 127b85a..eb5e656 100644 --- a/20240529RGBtest3/classifer.py +++ b/20240529RGBtest3/classifer.py @@ -299,37 +299,27 @@ class Passion_fruit: return result class Spec_predict(object): - def __init__(self, load_from=None, debug_mode=False, class_weight=None): - if load_from is None: - self.model = RandomForestRegressor(n_estimators=100) - else: - self.load(load_from) - self.log = utils.Logger(is_to_file=debug_mode) + def __init__(self, load_from=None, debug_mode=False): self.debug_mode = debug_mode + self.log = utils.Logger(is_to_file=debug_mode) + if load_from is not None: + self.load(load_from) + else: + self.model = RandomForestRegressor(n_estimators=100) - def load(self, path=None): - if path is None: - path = os.path.join(ROOT_DIR, 'models') - model_files = os.listdir(path) - if len(model_files) == 0: - self.log.log("No model found!") - return 1 - self.log.log("./ Models Found:") - _ = [self.log.log("├--" + str(model_file)) for model_file in model_files] - file_times = [model_file[6:-2] for model_file in model_files] - latest_model = model_files[int(np.argmax(file_times))] - self.log.log("└--Using the latest model: " + str(latest_model)) - path = os.path.join(ROOT_DIR, "models", str(latest_model)) + def load(self, path): if not os.path.isabs(path): - logging.warning('给的是相对路径') - return -1 + self.log.log('Path is relative, converting to absolute path.') + path = os.path.abspath(path) + if not os.path.exists(path): - logging.warning('文件不存在') - return -1 + self.log.log(f'Model file not found at path: {path}') + raise FileNotFoundError(f'Model file not found at path: {path}') + with open(path, 'rb') as f: model_dic = joblib.load(f) - self.model = model_dic['model'] - return 0 + self.model = model_dic + self.log.log(f'Model loaded successfully from {path}') def predict(self, data_x): ''' @@ -337,10 +327,13 @@ class Spec_predict(object): :param data_x: 波段选择后的数据 :return: 预测结果二值化后的数据,0为背景,1为黄芪,2为杂质2,3为杂质1,4为甘草片,5为红芪 ''' + data_x = data_x.reshape(1, -1) + selected_bands = [8, 9, 10, 48, 49, 50, 77, 80, 103, 108, 115, 143, 145] + data_x = data_x[:, selected_bands] data_y = self.model.predict(data_x) - return data_y + # def get_tomato_dimensions(edge_img): # """ # 根据边缘二值化轮廓图,计算果子的长径、短径和长短径比值。 @@ -484,10 +477,10 @@ class Data_processing: float: 估算的西红柿体积 """ density = 0.652228972 - a = long_axis / 2 - b = short_axis /2 + a = ((long_axis / 535) * 6.3) / 2 + b = ((short_axis /535) * 6.3) / 2 volume = 4 / 3 * np.pi * a * b * b - weigth = volume * density + weigth = round(volume * density) return weigth def analyze_tomato(self, img): """ @@ -522,7 +515,7 @@ class Data_processing: number_defects, total_pixels = self.analyze_defect(new_bin_img) # 将处理后的图像转换为 RGB 格式 rp = cv2.cvtColor(org_defect, cv2.COLOR_BGR2RGB) - diameter = (long_axis + short_axis) / 2 + diameter = (long_axis + short_axis) / 2 return diameter, green_percentage, number_defects, total_pixels, rp def analyze_passion_fruit(self, img, hue_value=37, hue_delta=10, value_target=25, value_delta=10): @@ -537,7 +530,6 @@ class Data_processing: combined_mask = pf.create_mask(hsv_image) combined_mask = pf.apply_morphology(combined_mask) max_mask = pf.find_largest_component(combined_mask) - contour_mask = self.contour_process(max_mask) long_axis, short_axis = self.analyze_ellipse(contour_mask) weigth = self.weight_estimates(long_axis, short_axis) diff --git a/20240529RGBtest3/main.py b/20240529RGBtest3/main.py index 6505628..dff44e1 100644 --- a/20240529RGBtest3/main.py +++ b/20240529RGBtest3/main.py @@ -44,7 +44,7 @@ def process_data(cmd: str, images: list, spec: any, detector: Spec_predict) -> b max_total_defect_area = max(max_total_defect_area, total_pixels) if i == 1: rp_result = rp - gp = green_percentage + gp = round(green_percentage) elif cmd == 'PF': # 百香果 @@ -64,23 +64,27 @@ def process_data(cmd: str, images: list, spec: any, detector: Spec_predict) -> b diameter = round(sum(diameter_axis_list) / 3) if cmd == 'TO': - response = pipe.send_data(cmd=cmd, diameter=diameter, green_percentage=gp, + brix = 0 + weigth = 0 + response = pipe.send_data(cmd=cmd, brix=brix, diameter=diameter, green_percentage=gp, weigth=weigth, defect_num=max_defect_num, total_defect_area=max_total_defect_area, rp=rp_result) + return response elif cmd == 'PF': + green_percentage = 0 brix = detector.predict(spec) - response = pipe.send_data(cmd=cmd, brix=brix, diameter=diameter, weigth=weigth, + response = pipe.send_data(cmd=cmd, brix=brix, green_percentage=green_percentage, diameter=diameter, weigth=weigth, defect_num=max_defect_num, total_defect_area=max_total_defect_area, rp=rp_result) - return response + return response def main(is_debug=False): file_handler = logging.FileHandler(os.path.join(ROOT_DIR, 'tomato.log')) file_handler.setLevel(logging.DEBUG if is_debug else logging.WARNING) console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.DEBUG if is_debug else logging.WARNING) - logging.basicConfig(format='%(asctime)s %(filename)s[line:%(lineno)d] - %(levellevel)s - %(message)s', + logging.basicConfig(format='%(asctime)s %(filename)s[line:%(lineno)d] - %(levelname)s - %(message)s', handlers=[file_handler, console_handler], level=logging.DEBUG) - detector = Spec_predict(ROOT_DIR/'20240529RGBtest3'/'models'/'passion_fruit.joblib') + detector = Spec_predict(ROOT_DIR/'models'/'passion_fruit_2.joblib') while True: images = [] @@ -89,8 +93,14 @@ def main(is_debug=False): for _ in range(5): data = pipe.receive_rgb_data(rgb_receive) cmd, img = pipe.parse_img(data) + + # print(cmd, img.shape) + images.append(img) + # print(len(images)) + + if cmd not in ['TO', 'PF']: logging.error(f'错误指令,指令为{cmd}') continue @@ -99,6 +109,7 @@ def main(is_debug=False): if cmd == 'PF': spec_data = pipe.receive_spec_data(spec_receive) _, spec = pipe.parse_spec(spec_data) + # print(spec.shape) response = process_data(cmd, images, spec, detector) if response: diff --git a/20240529RGBtest3/qt_test.py b/20240529RGBtest3/qt_test.py index 6083b81..144eabb 100644 --- a/20240529RGBtest3/qt_test.py +++ b/20240529RGBtest3/qt_test.py @@ -13,6 +13,9 @@ import win32file import struct from PIL import Image import io +import numpy as np +import cv2 + class MainWindow(QMainWindow): def __init__(self): @@ -69,12 +72,22 @@ class MainWindow(QMainWindow): spec_files = [os.path.join(image_dir, f) for f in os.listdir(image_dir) if f.endswith('.raw')][:1] for image_path in rgb_files: - with open(image_path, 'rb') as f: - img_data = f.read() + img = cv2.imread(image_path, cv2.IMREAD_COLOR) + img = np.asarray(img, dtype=np.uint8) + try: - win32file.WriteFile(self.rgb_send, len(img_data).to_bytes(4, byteorder='big')) - win32file.WriteFile(self.rgb_send, img_data) + # win32file.WriteFile(self.rgb_send, len(img_data).to_bytes(4, byteorder='big')) + height = img.shape[0] + width = img.shape[1] + height = height.to_bytes(2, byteorder='big') + width = width.to_bytes(2, byteorder='big') + img_data = img.tobytes() + length = (len(img_data) + 6).to_bytes(4, byteorder='big') + cmd = 'PF' + data_send = length + cmd.upper().encode('ascii') + height + width + img_data + win32file.WriteFile(self.rgb_send, data_send) + print(f'发送的图像数据长度: {len(data_send)}') except Exception as e: print(f"数据发送失败. 错误原因: {e}") @@ -84,10 +97,20 @@ class MainWindow(QMainWindow): spec_data = f.read() try: - win32file.WriteFile(self.spec_send, len(spec_data).to_bytes(4, byteorder='big')) - print(f"发送的光谱数据长度: {len(spec_data)}") - win32file.WriteFile(self.spec_send, spec_data) - print(f'发送的光谱数据长度: {len(spec_data)}') + # win32file.WriteFile(self.spec_send, len(spec_data).to_bytes(4, byteorder='big')) + # print(f"发送的光谱数据长度: {len(spec_data)}") + heigth = 30 + weight = 30 + bands = 224 + heigth = heigth.to_bytes(2, byteorder='big') + weight = weight.to_bytes(2, byteorder='big') + bands = bands.to_bytes(2, byteorder='big') + length = (len(spec_data)+8).to_bytes(4, byteorder='big') + cmd = 'PF' + data_send = length + cmd.upper().encode('ascii') + heigth + weight + bands + spec_data + win32file.WriteFile(self.spec_send, data_send) + print(f'发送的光谱数据长度: {len(data_send)}') + print(f'spec长度: {len(spec_data)}') except Exception as e: print(f"数据发送失败. 错误原因: {e}") @@ -96,17 +119,30 @@ class MainWindow(QMainWindow): def receive_result(self): try: # 读取结果数据 - long_axis = int.from_bytes(win32file.ReadFile(self.rgb_receive, 2)[1], byteorder='big') - short_axis = int.from_bytes(win32file.ReadFile(self.rgb_receive, 2)[1], byteorder='big') - defect_num = int.from_bytes(win32file.ReadFile(self.rgb_receive, 2)[1], byteorder='big') - total_defect_area = int.from_bytes(win32file.ReadFile(self.rgb_receive, 4)[1], byteorder='big') - len_img = int.from_bytes(win32file.ReadFile(self.rgb_receive, 4)[1], byteorder='big') - img_data = win32file.ReadFile(self.rgb_receive, len_img)[1] + # 读取4字节的数据长度信息,并将其转换为整数 + data_length = int.from_bytes(win32file.ReadFile(self.rgb_receive, 4)[1], byteorder='big') + print(f"应该接收到的数据长度: {data_length}") + # 根据读取到的数据长度,读取对应长度的数据 + data = win32file.ReadFile(self.rgb_receive, data_length)[1] + print(f"接收到的数据长度: {len(data)}") + # 解析数据 + cmd_result = data[:2].decode('ascii').strip().upper() + brix = int.from_bytes(data[2:4], byteorder='big') + green_percentage = int.from_bytes(data[4:5], byteorder='big') + diameter = int.from_bytes(data[5:7], byteorder='big') + weight = int.from_bytes(data[7:8], byteorder='big') + defect_num = int.from_bytes(data[8:10], byteorder='big') + total_defect_area = int.from_bytes(data[10:14], byteorder='big') + heigth = int.from_bytes(data[14:16], byteorder='big') + width = int.from_bytes(data[16:18], byteorder='big') + rp = data[18:] + print(heigth, width) + img = np.frombuffer(rp, dtype=np.uint8).reshape(heigth, width, -1) + print(f"接收到的结果数据: {cmd_result}, {brix}, {green_percentage}, {diameter}, {weight}, {defect_num}, {total_defect_area}, {img.shape}") - print(f"长径: {long_axis}, 短径: {short_axis}, 缺陷个数: {defect_num}, 缺陷面积: {total_defect_area}") # 显示结果图像 - image = Image.open(io.BytesIO(img_data)) + image = Image.fromarray(img) qimage = QImage(image.tobytes(), image.size[0], image.size[1], QImage.Format_RGB888) pixmap = QPixmap.fromImage(qimage) self.image_label.setPixmap(pixmap) @@ -122,6 +158,13 @@ class MainWindow(QMainWindow): self.send_image_group(selected_directory) if __name__ == "__main__": + ''' + 1. 创建Qt应用程序 + 2. 创建主窗口 + 3. 显示主窗口 + 4. 打开文件对话框 + 5. 进入Qt事件循环 + ''' app = QApplication(sys.argv) main_window = MainWindow() main_window.show() diff --git a/20240529RGBtest3/utils.py b/20240529RGBtest3/utils.py index 092ef4b..3ea3ee1 100644 --- a/20240529RGBtest3/utils.py +++ b/20240529RGBtest3/utils.py @@ -67,13 +67,13 @@ class Pipe: time.sleep(5) continue - def receive_rgb_data(self): + def receive_rgb_data(self, rgb_receive): try: # 读取图片数据长度 - len_img = win32file.ReadFile(self.rgb_receive, 4, None) + len_img = win32file.ReadFile(rgb_receive, 4, None) data_size = int.from_bytes(len_img[1], byteorder='big') # 读取实际图片数据 - result, data = win32file.ReadFile(self.rgb_receive, data_size, None) + result, data = win32file.ReadFile(rgb_receive, data_size, None) # 检查读取操作是否成功 if result != 0: print(f"读取失败,错误代码: {result}") @@ -84,13 +84,13 @@ class Pipe: print(f"数据接收失败,错误原因: {e}") return None - def receive_spec_data(self): + def receive_spec_data(self, spec_receive): try: # 读取光谱数据长度 - len_spec = win32file.ReadFile(self.spec_receive, 4, None) + len_spec = win32file.ReadFile(spec_receive, 4, None) data_size = int.from_bytes(len_spec[1], byteorder='big') # 读取光谱数据 - result, spec_data = win32file.ReadFile(self.spec_receive, data_size, None) + result, spec_data = win32file.ReadFile(spec_receive, data_size, None) # 检查读取操作是否成功 if result != 0: print(f"读取失败,错误代码: {result}") @@ -128,7 +128,7 @@ class Pipe: except AssertionError: logging.error('图像指令IM转换失败,数据长度错误') return '', None - img = np.frombuffer(img, dtype=np.uint8).reshape((n_rows, n_cols, -1)) + img = np.frombuffer(img, dtype=np.uint8).reshape(n_rows, n_cols, -1) return cmd, img def parse_spec(self, data: bytes) -> (str, any): @@ -153,12 +153,12 @@ class Pipe: logging.error(f'长宽转换失败, 错误代码{e}, 报文大小: n_rows:{n_rows}, n_cols:{n_cols}, n_bands:{n_bands}') return '', None try: - assert n_rows * n_cols * n_bands * 4 == len(spec) + assert n_rows * n_cols * n_bands * 2 == len(spec) except AssertionError: logging.error('图像指令转换失败,数据长度错误') return '', None - spec = spec.reshape((n_rows, n_bands, -1)).transpose(0, 2, 1) + spec = np.frombuffer(spec, dtype=np.uint16).reshape((n_rows, n_bands, -1)).transpose(0, 2, 1) return cmd, spec def send_data(self,cmd:str, brix, green_percentage, weigth, diameter, defect_num, total_defect_area, rp): @@ -193,17 +193,17 @@ class Pipe: diameter = diameter.to_bytes(2, byteorder='big') defect_num = defect_num.to_bytes(2, byteorder='big') total_defect_area = int(total_defect_area).to_bytes(4, byteorder='big') - length = len(img_bytes) + 15 + length = len(img_bytes) + 18 length = length.to_bytes(4, byteorder='big') if cmd == 'TO': brix = 0 - brix = brix.to_bytes(1, byteorder='big') + brix = brix.to_bytes(2, byteorder='big') gp = green_percentage.to_bytes(1, byteorder='big') weigth = 0 weigth = weigth.to_bytes(1, byteorder='big') send_message = length + cmd_re + brix + gp + diameter + weigth + defect_num + total_defect_area + height + width + img_bytes elif cmd == 'PF': - brix = brix.to_bytes(1, byteorder='big') + brix = int(brix.item() * 1000).to_bytes(2, byteorder='big') gp = 0 gp = gp.to_bytes(1, byteorder='big') weigth = weigth.to_bytes(1, byteorder='big') @@ -212,6 +212,7 @@ class Pipe: win32file.WriteFile(self.rgb_send, send_message) time.sleep(0.01) print('发送成功') + print(len(send_message), len(img_bytes)) # print(len(send_message)) except Exception as e: logging.error(f'发送完成指令失败,错误类型:{e}') diff --git a/20240529RGBtest3/xs/dimensionality_reduction.py b/20240529RGBtest3/xs/dimensionality_reduction.py index 50b586e..e0d5f30 100644 --- a/20240529RGBtest3/xs/dimensionality_reduction.py +++ b/20240529RGBtest3/xs/dimensionality_reduction.py @@ -55,7 +55,7 @@ def main(): for model_name, model in models.items(): model.fit(X_train, y_train) if model_name == "RandomForest": - joblib.dump(model, '../models/random_forest_model_2.joblib') + joblib.dump(model, r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\models\passion_fruit_2.joblib') mse, y_pred = evaluate_model(model, X_test, y_test) print(f"Model: {model_name}") diff --git a/20240529RGBtest3/xs/predict.py b/20240529RGBtest3/xs/predict.py index b1c3058..7abf078 100644 --- a/20240529RGBtest3/xs/predict.py +++ b/20240529RGBtest3/xs/predict.py @@ -60,10 +60,10 @@ def predict(model, data): def main(): # 加载模型 - model = load_model('../models/random_forest_model_2.joblib') + model = load_model(r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\models\passion_fruit.joblib') # 读取数据 - directory = '/Users/xs/PycharmProjects/super-tomato/baixiangguo/光谱数据3030/' + directory = r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\xs\光谱数据3030' all_spectral_data = [] for i in range(1, 101): hdr_path = os.path.join(directory, f'{i}.HDR') @@ -71,9 +71,11 @@ def main(): spectral_data = read_spectral_data(hdr_path, raw_path) all_spectral_data.append(spectral_data) all_spectral_data = np.stack(all_spectral_data) + print(all_spectral_data.shape) # 预处理数据 data_prepared = prepare_data(all_spectral_data) + print(data_prepared.shape) # 预测数据 predictions = predict(model, data_prepared) diff --git a/20240529RGBtest3/xs/spec_read.py b/20240529RGBtest3/xs/spec_read.py index 8dc036b..4a764ce 100644 --- a/20240529RGBtest3/xs/spec_read.py +++ b/20240529RGBtest3/xs/spec_read.py @@ -51,7 +51,7 @@ def read_spectral_data(hdr_path, raw_path): # Specify the directory containing the HDR and RAW files -directory = '/Users/xs/PycharmProjects/super-tomato/baixiangguo/光谱数据3030/' +directory = r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\xs\光谱数据3030' # Initialize a list to hold all the spectral data arrays all_spectral_data = [] diff --git a/20240529RGBtest3/通信协议(20240612).md b/20240529RGBtest3/通信协议(20240612).md index ac1e960..1f8dadf 100644 --- a/20240529RGBtest3/通信协议(20240612).md +++ b/20240529RGBtest3/通信协议(20240612).md @@ -52,11 +52,11 @@ $$ **返回结果数据包:'R''E'**,`数据1`~`数据i`包含了糖度值Brix、颜色占比color、直径long、预估重量weight、缺陷个数num、缺陷面积area、结果图像的行数rows(高度)、列数cols(宽度)、以及结果图像的RGB数据,组合方式为**糖度值+颜色占比+直径+预估重量+缺陷个数+缺陷面积+高度+宽度+RGB数据** $$ -i-15=rows \times cols \times 3 +i-16=rows \times cols \times 3 $$ `数据1`~`数据i`的分布具体如下: -| 糖度值 | 颜色占比 | 直径2 | 直径1 | 预估重量 | 缺陷个数1 | 缺陷个数2 | 缺陷面积1 | 缺陷面积2 | 缺陷面积3 | 缺陷面积4 | 行数1 | 行数2 | 列数1 | 列数2 | 图像数据1 | ... | 图像数据(i-16) | -| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | --- | --- | --- | -| Brix[7:0] | color[7:0] | long[15:8] | long[7:0] | weight[7:0] | num[15:8] | num[7:0] | area[31:24] | area[23:16] | area[15:8] | area[7:0] | rows[15:8] | rows[7:0] | cols[15:8] | cols[7:0] | | ... | | +| 糖度值2 | 糖度值1 | 颜色占比 | 直径2 | 直径1 | 预估重量 | 缺陷个数1 | 缺陷个数2 | 缺陷面积1 | 缺陷面积2 | 缺陷面积3 | 缺陷面积4 | 行数1 | 行数2 | 列数1 | 列数2 | 图像数据1 | ... | 图像数据(i-16) | +| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | --- | --- | --- | --- | +| Brix[15:8] | Brix[7:0] | color[7:0] | long[15:8] | long[7:0] | weight[7:0] | num[15:8] | num[7:0] | area[31:24] | area[23:16] | area[15:8] | area[7:0] | rows[15:8] | rows[7:0] | cols[15:8] | cols[7:0] | | ... | |