diff --git a/20240529RGBtest3/classifer.py b/20240529RGBtest3/classifer.py
index f2f45e0..127b85a 100644
--- a/20240529RGBtest3/classifer.py
+++ b/20240529RGBtest3/classifer.py
@@ -7,6 +7,12 @@
import cv2
import numpy as np
+import logging
+import os
+import utils
+from root_dir import ROOT_DIR
+from sklearn.ensemble import RandomForestRegressor
+import joblib
class Tomato:
def __init__(self):
@@ -223,7 +229,6 @@ class Tomato:
img_filled = cv2.bitwise_or(new_bin_img, img_filled_inv)
return img_filled
-
class Passion_fruit:
def __init__(self, hue_value=37, hue_delta=10, value_target=25, value_delta=10):
# 初始化常用参数
@@ -293,4 +298,253 @@ class Passion_fruit:
result = cv2.bitwise_and(rgb_img, bin_img_3channel)
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)
+ self.debug_mode = debug_mode
+ 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))
+ if not os.path.isabs(path):
+ logging.warning('给的是相对路径')
+ return -1
+ if not os.path.exists(path):
+ logging.warning('文件不存在')
+ return -1
+ with open(path, 'rb') as f:
+ model_dic = joblib.load(f)
+ self.model = model_dic['model']
+ return 0
+
+ def predict(self, data_x):
+ '''
+ 对数据进行预测
+ :param data_x: 波段选择后的数据
+ :return: 预测结果二值化后的数据,0为背景,1为黄芪,2为杂质2,3为杂质1,4为甘草片,5为红芪
+ '''
+ data_y = self.model.predict(data_x)
+
+ return data_y
+
+# def get_tomato_dimensions(edge_img):
+# """
+# 根据边缘二值化轮廓图,计算果子的长径、短径和长短径比值。
+# 使用最小外接矩形和最小外接圆两种方法。
+#
+# 参数:
+# edge_img (numpy.ndarray): 边缘二值化轮廓图,背景为黑色,番茄区域为白色。
+#
+# 返回:
+# tuple: (长径, 短径, 长短径比值)
+# """
+# if edge_img is None or edge_img.any() == 0:
+# return (0, 0)
+# # 最小外接矩形
+# rect = cv2.minAreaRect(cv2.findContours(edge_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0][0])
+# major_axis, minor_axis = rect[1]
+# # aspect_ratio = max(major_axis, minor_axis) / min(major_axis, minor_axis)
+#
+# # # 最小外接圆
+# # (x, y), radius = cv2.minEnclosingCircle(
+# # cv2.findContours(edge_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0][0])
+# # diameter = 2 * radius
+# # aspect_ratio_circle = 1.0
+#
+# return (max(major_axis, minor_axis), min(major_axis, minor_axis))
+
+# def get_defect_info(defect_img):
+# """
+# 根据区域缺陷二值化轮廓图,计算缺陷区域的个数和总面积。
+#
+# 参数:
+# defect_img (numpy.ndarray): 番茄区域缺陷二值化轮廓图,背景为黑色,番茄区域为白色,缺陷区域为黑色连通域。
+#
+# 返回:
+# tuple: (缺陷区域个数, 缺陷区域像素面积,缺陷像素总面积)
+# """
+# # 检查输入是否为空
+# if defect_img is None or defect_img.any() == 0:
+# return (0, 0)
+#
+# nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(defect_img, connectivity=4)
+# max_area = max(stats[i, cv2.CC_STAT_AREA] for i in range(1, nb_components))
+# areas = []
+# for i in range(1, nb_components):
+# area = stats[i, cv2.CC_STAT_AREA]
+# if area != max_area:
+# areas.append(area)
+# number_defects = len(areas)
+# total_pixels = sum(areas)
+# return number_defects, total_pixels
+
+class Data_processing:
+ def __init__(self):
+ pass
+
+ def contour_process(self, image_array):
+ # 应用中值滤波
+ image_filtered = cv2.medianBlur(image_array, 5)
+
+ # 形态学闭操作
+ kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
+ image_closed = cv2.morphologyEx(image_filtered, cv2.MORPH_CLOSE, kernel)
+
+ # 查找轮廓
+ contours, _ = cv2.findContours(image_closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
+
+ # 创建空白图像以绘制轮廓
+ image_contours = np.zeros_like(image_array)
+
+ # 进行多边形拟合并填充轮廓
+ for contour in contours:
+ epsilon = 0.001 * cv2.arcLength(contour, True)
+ approx = cv2.approxPolyDP(contour, epsilon, True)
+ if cv2.contourArea(approx) > 100: # 仅处理较大的轮廓
+ cv2.drawContours(image_contours, [approx], -1, (255, 255, 255), -1)
+
+ return image_contours
+
+ def analyze_ellipse(self, image_array):
+ # 查找白色区域的轮廓
+ _, binary_image = cv2.threshold(image_array, 127, 255, cv2.THRESH_BINARY)
+ contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
+
+ # 初始化变量用于存储最大轮廓的长径和短径
+ major_axis = 0
+ minor_axis = 0
+
+ # 对每个找到的轮廓,找出可以包围它的最小椭圆,并计算长径和短径
+ for contour in contours:
+ if len(contour) >= 5: # 至少需要5个点来拟合椭圆
+ ellipse = cv2.fitEllipse(contour)
+ (center, axes, orientation) = ellipse
+ major_axis0 = max(axes)
+ minor_axis0 = min(axes)
+ # 更新最大的长径和短径
+ if major_axis0 > major_axis:
+ major_axis = major_axis0
+ minor_axis = minor_axis0
+
+ return major_axis, minor_axis
+
+ def analyze_defect(self, image_array):
+ # 查找白色区域的轮廓
+ _, binary_image = cv2.threshold(image_array, 127, 255, cv2.THRESH_BINARY)
+ contours_white, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
+
+ # 初始化统计数据
+ count_black_areas = 0
+ total_pixels_black_areas = 0
+
+ # 对于每个白色区域,查找内部的黑色小区域
+ for contour in contours_white:
+ # 创建一个mask以查找内部的黑色区域
+ mask = np.zeros_like(image_array)
+ cv2.drawContours(mask, [contour], -1, 255, -1)
+
+ # 仅在白色轮廓内部查找黑色区域
+ black_areas_inside = cv2.bitwise_and(cv2.bitwise_not(image_array), mask)
+
+ # 查找黑色区域的轮廓
+ contours_black, _ = cv2.findContours(black_areas_inside, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
+ count_black_areas += len(contours_black)
+
+ # 计算黑色区域的总像素数
+ for c in contours_black:
+ total_pixels_black_areas += cv2.contourArea(c)
+
+ number_defects = count_black_areas
+ total_pixels = total_pixels_black_areas
+ return number_defects, total_pixels
+
+ def weight_estimates(self, long_axis, short_axis):
+ """
+ 根据西红柿的长径、短径和直径估算其体积。
+ 使用椭圆体积公式计算体积。
+ 参数:
+ diameter (float): 西红柿的直径
+ long_axis (float): 西红柿的长径
+ short_axis (float): 西红柿的短径
+ 返回:
+ float: 估算的西红柿体积
+ """
+ density = 0.652228972
+ a = long_axis / 2
+ b = short_axis /2
+ volume = 4 / 3 * np.pi * a * b * b
+ weigth = volume * density
+ return weigth
+ def analyze_tomato(self, img):
+ """
+ 分析给定图像,提取和返回西红柿的长径、短径、缺陷数量和缺陷总面积,并返回处理后的图像。
+ 使用 Tomoto 类的图像处理方法,以及自定义的尺寸和缺陷信息获取函数。
+ 参数:
+ img (numpy.ndarray): 输入的 BGR 图像
+ 返回:
+ tuple: (长径, 短径, 缺陷区域个数, 缺陷区域总像素, 处理后的图像)
+ """
+ tomato = Tomato() # 创建 Tomato 类的实例
+ # 设置 S-L 通道阈值并处理图像
+ threshold_s_l = 180
+ threshold_fore_g_r_t = 20
+ s_l = tomato.extract_s_l(img)
+ thresholded_s_l = tomato.threshold_segmentation(s_l, threshold_s_l)
+ new_bin_img = tomato.largest_connected_component(thresholded_s_l)
+ # 绘制西红柿边缘并获取缺陷信息
+ edge, mask = tomato.draw_tomato_edge(img, new_bin_img)
+ org_defect = tomato.bitwise_and_rgb_with_binary(edge, new_bin_img)
+ fore = tomato.bitwise_and_rgb_with_binary(img, mask)
+ fore_g_r_t = tomato.threshold_segmentation(tomato.extract_g_r(fore), threshold=threshold_fore_g_r_t)
+ # 统计白色像素点个数
+ # print(np.sum(fore_g_r_t == 255))
+ # print(np.sum(mask == 255))
+ # print(np.sum(fore_g_r_t == 255) / np.sum(mask == 255))
+ green_percentage = np.sum(fore_g_r_t == 255) / np.sum(mask == 255)
+ green_percentage = round(green_percentage, 2) * 100
+ # 获取西红柿的尺寸信息
+ long_axis, short_axis = self.analyze_ellipse(mask)
+ # 获取缺陷信息
+ 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
+ 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):
+ if img is None:
+ print("Error: 无图像数据.")
+ return None
+
+ # 创建PassionFruit类的实例
+ pf = Passion_fruit(hue_value=hue_value, hue_delta=hue_delta, value_target=value_target, value_delta=value_delta)
+
+ hsv_image = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
+ 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)
+ number_defects, total_pixels = self.analyze_defect(max_mask)
+ edge = pf.draw_contours_on_image(img, contour_mask)
+ org_defect = pf.bitwise_and_rgb_with_binary(edge, max_mask)
+ rp = cv2.cvtColor(org_defect, cv2.COLOR_BGR2RGB)
+ diameter = (long_axis + short_axis) / 2
+
+ return diameter, weigth, number_defects, total_pixels, rp
diff --git a/20240529RGBtest3/main.py b/20240529RGBtest3/main.py
index 0a922f0..19d19e9 100644
--- a/20240529RGBtest3/main.py
+++ b/20240529RGBtest3/main.py
@@ -3,126 +3,107 @@
# @Author : TG
# @File : main.py
# @Software: PyCharm
-# -*- coding: utf-8 -*-
-# @Time : 2024/4/12 15:04
-# @Author : TG
-# @File : main.py
-# @Software: PyCharm
-import socket
import sys
-import numpy as np
-import cv2
-import root_dir
-import time
import os
from root_dir import ROOT_DIR
+from classifer import Spec_predict, Data_processing
import logging
-from utils import parse_protocol, create_pipes, receive_rgb_data, send_data, receive_spec_data, analyze_tomato, analyze_passion_fruit
-from collections import deque
-import time
-import io
-from PIL import Image
-import threading
-import queue
+from utils import Pipe
+import numpy as np
-def process_data(cmd: str, img: any) -> tuple:
+pipe = Pipe()
+dp = Data_processing()
+rgb_receive_name = r'\\.\pipe\rgb_receive'
+rgb_send_name = r'\\.\pipe\rgb_send'
+spec_receive_name = r'\\.\pipe\spec_receive'
+rgb_receive, rgb_send, spec_receive = pipe.create_pipes(rgb_receive_name, rgb_send_name, spec_receive_name)
+
+def process_data(cmd: str, images: list, spec: any, detector: Spec_predict) -> bool:
"""
处理指令
:param cmd: 指令类型
- :param data: 指令内容
- :param connected_sock: socket
+ :param images: 图像数据列表
+ :param spec: 光谱数据
:param detector: 模型
:return: 是否处理成功
"""
+ diameter_axis_list = []
+ max_defect_num = 0 # 初始化最大缺陷数量为0
+ max_total_defect_area = 0 # 初始化最大总像素数为0
+
+ for i, img in enumerate(images):
+ if cmd == 'TO':
+ # 番茄
+ diameter, green_percentage, number_defects, total_pixels, rp = dp.analyze_tomato(img)
+ if i <= 2:
+ diameter_axis_list.append(diameter)
+ max_defect_num = max(max_defect_num, number_defects)
+ max_total_defect_area = max(max_total_defect_area, total_pixels)
+ if i == 1:
+ rp_result = rp
+ gp = green_percentage
+
+ elif cmd == 'PF':
+ # 百香果
+ diameter, weigth, number_defects, total_pixels, rp = dp.analyze_passion_fruit(img)
+ if i <= 2:
+ diameter_axis_list.append(diameter)
+ max_defect_num = max(max_defect_num, number_defects)
+ max_total_defect_area = max(max_total_defect_area, total_pixels)
+ if i == 1:
+ rp_result = rp
+ weigth = weigth
+
+ else:
+ logging.error(f'错误指令,指令为{cmd}')
+ return False
+
+ diameter = round(sum(diameter_axis_list) / 3)
+
if cmd == 'TO':
- # 番茄
- long_axis, short_axis, number_defects, total_pixels, rp = analyze_tomato(img)
+ response = pipe.send_data(cmd=cmd, diameter=diameter, green_percentage=gp,
+ defect_num=max_defect_num, total_defect_area=max_total_defect_area, rp=rp_result)
elif cmd == 'PF':
- # 百香果
- long_axis, short_axis, number_defects, total_pixels, rp = analyze_passion_fruit(img)
+ brix = detector.predict(spec)
+ response = pipe.send_data(cmd=cmd, brix=brix, diameter=diameter, weigth=weigth,
+ defect_num=max_defect_num, total_defect_area=max_total_defect_area, rp=rp_result)
+ return response
- return long_axis, short_axis, number_defects, total_pixels, rp
-
-
-## 20240423代码
def main(is_debug=False):
file_handler = logging.FileHandler(os.path.join(ROOT_DIR, 'report.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] - %(levelname)s - %(message)s',
+ logging.basicConfig(format='%(asctime)s %(filename)s[line:%(lineno)d] - %(levellevel)s - %(message)s',
handlers=[file_handler, console_handler],
level=logging.DEBUG)
- rgb_receive_name = r'\\.\pipe\rgb_receive'
- rgb_send_name = r'\\.\pipe\rgb_send'
- spec_receive_name = r'\\.\pipe\spec_receive'
- rgb_receive, rgb_send, spec_receive = create_pipes(rgb_receive_name, rgb_send_name, spec_receive_name)
-
- # data_size = 15040566
+ detector = Spec_predict(ROOT_DIR/'20240529RGBtest3'/'models'/'passion_fruit.joblib')
while True:
- long_axis_list = []
- short_axis_list = []
- max_defect_num = 0 # 初始化最大缺陷数量为0
- max_total_defect_area = 0 # 初始化最大总像素数为0
- rp = None
+ images = []
+ cmd = None
- # start_time = time.time()
+ for _ in range(5):
+ data = pipe.receive_rgb_data(rgb_receive)
+ cmd, img = pipe.parse_img(data)
+ images.append(img)
- for i in range(5):
-
- # start_time = time.time()
-
- data = receive_rgb_data(rgb_receive)
- cmd, img = parse_protocol(data)
- # print(img.shape)
- # end_time = time.time()
- # elapsed_time = end_time - start_time
- # print(f'接收时间:{elapsed_time}秒')
-
- long_axis, short_axis, number_defects, total_pixels, rp = process_data(cmd=cmd, img=img)
- # print(long_axis, short_axis, number_defects, type(total_pixels), rp.shape)
-
- if i <= 2:
- long_axis_list.append(long_axis)
- short_axis_list.append(short_axis)
- # 更新最大缺陷数量和最大总像素数
- max_defect_num = max(max_defect_num, number_defects)
- max_total_defect_area = max(max_total_defect_area, total_pixels)
- if i == 1:
- rp_result = rp
-
- long_axis = round(sum(long_axis_list) / 3)
- short_axis = round(sum(short_axis_list) / 3)
- # print(type(long_axis), type(short_axis), type(defect_num_sum), type(total_defect_area_sum), type(rp_result))
-
- spec_data = receive_spec_data(spec_receive)
- cmd, spec_data = parse_protocol(spec_data)
-
- # print(f'光谱数据接收长度:', len(spec_data))
-
-
- response = send_data(pipe_send=rgb_send, long_axis=long_axis, short_axis=short_axis,
- defect_num=max_defect_num, total_defect_area=max_total_defect_area, rp=rp_result)
-
-
-
- # end_time = time.time()
- # elapsed_time = (end_time - start_time) * 1000
- # print(f'总时间:{elapsed_time}毫秒')
- #
- # print(long_axis, short_axis, defect_num_sum, total_defect_area_sum, rp_result.shape)
+ if cmd not in ['TO', 'PF']:
+ logging.error(f'错误指令,指令为{cmd}')
+ continue
+ spec = None
+ if cmd == 'PF':
+ spec_data = pipe.receive_spec_data(spec_receive)
+ _, spec = pipe.parse_spec(spec_data)
+ response = process_data(cmd, images, spec, detector)
+ if response:
+ logging.info(f'处理成功,响应为: {response}')
+ else:
+ logging.error('处理失败')
if __name__ == '__main__':
- # 2个pipe管道
- # 接收到图片 n_rows * n_cols * 3, uint8
- # 发送long_axis, short_axis, defect_num_sum, total_defect_area_sum, rp_result
main(is_debug=False)
-
-
-
-
diff --git a/20240529RGBtest3/models/passion_fruit.joblib b/20240529RGBtest3/models/passion_fruit.joblib
new file mode 100644
index 0000000..06471ee
Binary files /dev/null and b/20240529RGBtest3/models/passion_fruit.joblib differ
diff --git a/20240529RGBtest3/models/random_forest_model_2.joblib b/20240529RGBtest3/models/random_forest_model_2.joblib
new file mode 100644
index 0000000..1becbba
Binary files /dev/null and b/20240529RGBtest3/models/random_forest_model_2.joblib differ
diff --git a/20240529RGBtest3/utils.py b/20240529RGBtest3/utils.py
index 8c82559..52b68d3 100644
--- a/20240529RGBtest3/utils.py
+++ b/20240529RGBtest3/utils.py
@@ -20,60 +20,116 @@ import msvcrt
from classifer import Tomato, Passion_fruit
-def receive_rgb_data(pipe):
- try:
- # 读取图片数据长度
- len_img = win32file.ReadFile(pipe, 4, None)
- data_size = int.from_bytes(len_img[1], byteorder='big')
- # 读取实际图片数据
- result, data = win32file.ReadFile(pipe, data_size, None)
- # 检查读取操作是否成功
- if result != 0:
- print(f"读取失败,错误代码: {result}")
+import win32file
+import win32pipe
+import time
+import logging
+import numpy as np
+from PIL import Image
+import io
+
+class Pipe:
+ def __init__(self, rgb_receive_name, rgb_send_name, spec_receive_name):
+ self.rgb_receive_name = rgb_receive_name
+ self.rgb_send_name = rgb_send_name
+ self.spec_receive_name = spec_receive_name
+ self.rgb_receive = None
+ self.rgb_send = None
+ self.spec_receive = None
+
+ def create_pipes(self):
+ while True:
+ try:
+ # 打开或创建命名管道
+ self.rgb_receive = win32pipe.CreateNamedPipe(
+ self.rgb_receive_name,
+ win32pipe.PIPE_ACCESS_INBOUND,
+ win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_WAIT,
+ 1, 80000000, 80000000, 0, None
+ )
+ self.rgb_send = win32pipe.CreateNamedPipe(
+ self.rgb_send_name,
+ win32pipe.PIPE_ACCESS_OUTBOUND, # 修改为输出模式
+ win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_WAIT,
+ 1, 80000000, 80000000, 0, None
+ )
+ self.spec_receive = win32pipe.CreateNamedPipe(
+ self.spec_receive_name,
+ win32pipe.PIPE_ACCESS_INBOUND,
+ win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_WAIT,
+ 1, 200000000, 200000000, 0, None
+ )
+ print("pipe管道创建成功,等待连接...")
+ # 等待发送端连接
+ win32pipe.ConnectNamedPipe(self.rgb_receive, None)
+ print("rgb_receive connected.")
+ # 等待发送端连接
+ win32pipe.ConnectNamedPipe(self.rgb_send, None)
+ print("rgb_send connected.")
+ win32pipe.ConnectNamedPipe(self.spec_receive, None)
+ print("spec_receive connected.")
+ return self.rgb_receive, self.rgb_send, self.spec_receive
+
+ except Exception as e:
+ print(f"管道创建连接失败,失败原因: {e}")
+ print("等待5秒后重试...")
+ time.sleep(5)
+ continue
+
+ def receive_rgb_data(self):
+ try:
+ # 读取图片数据长度
+ len_img = win32file.ReadFile(self.rgb_receive, 4, None)
+ data_size = int.from_bytes(len_img[1], byteorder='big')
+ # 读取实际图片数据
+ result, data = win32file.ReadFile(self.rgb_receive, data_size, None)
+ # 检查读取操作是否成功
+ if result != 0:
+ print(f"读取失败,错误代码: {result}")
+ return None
+ # 返回成功读取的数据
+ return data
+ except Exception as e:
+ print(f"数据接收失败,错误原因: {e}")
return None
- # 返回成功读取的数据
- return data
- except Exception as e:
- print(f"数据接收失败,错误原因: {e}")
- return None
-def receive_spec_data(pipe):
- try:
- # 读取光谱数据长度
- len_spec = win32file.ReadFile(pipe, 4, None)
- data_size = int.from_bytes(len_spec[1], byteorder='big')
- # 读取光谱数据
- result, spec_data = win32file.ReadFile(pipe, data_size, None)
- # 检查读取操作是否成功
- if result != 0:
- print(f"读取失败,错误代码: {result}")
+ def receive_spec_data(self):
+ try:
+ # 读取光谱数据长度
+ len_spec = win32file.ReadFile(self.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)
+ # 检查读取操作是否成功
+ if result != 0:
+ print(f"读取失败,错误代码: {result}")
+ return None
+ # 返回成功读取的数据
+ return spec_data
+ except Exception as e:
+ print(f"数据接收失败,错误原因: {e}")
return None
- # 返回成功读取的数据
- return spec_data
- except Exception as e:
- print(f"数据接收失败,错误原因: {e}")
- return None
-def parse_protocol(data: bytes) -> (str, any):
- """
- 指令转换.
+ def parse_img(self, data: bytes) -> (str, any):
+ """
+ 图像数据转换.
+
+ :param data:接收到的报文
+ :return: 指令类型和内容
+ """
+ try:
+ assert len(data) > 2
+ except AssertionError:
+ logging.error('指令转换失败,长度不足3')
+ return '', None
+ cmd, data = data[:2], data[2:]
+ cmd = cmd.decode('ascii').strip().upper()
- :param data:接收到的报文
- :return: 指令类型和内容
- """
- try:
- assert len(data) > 2
- except AssertionError:
- logging.error('指令转换失败,长度不足3')
- return '', None
- cmd, data = data[:2], data[2:]
- cmd = cmd.decode('ascii').strip().upper()
- if cmd == 'TO':
n_rows, n_cols, img = data[:2], data[2:4], data[4:]
try:
n_rows, n_cols = [int.from_bytes(x, byteorder='big') for x in [n_rows, n_cols]]
except Exception as e:
- logging.error(f'长宽转换失败, 错误代码{e}, 报文大小: n_rows:{n_rows}, n_cols: {n_cols}')
+ logging.error(f'长宽转换失败, 错误代码{e}, 报文大小: n_rows:{n_rows}, n_cols:{n_cols}')
return '', None
try:
assert n_rows * n_cols * 3 == len(img)
@@ -83,12 +139,27 @@ def parse_protocol(data: bytes) -> (str, any):
return '', None
img = np.frombuffer(img, dtype=np.uint8).reshape((n_rows, n_cols, -1))
return cmd, img
- elif cmd == 'PF':
+
+ def parse_spec(self, data: bytes) -> (str, any):
+ """
+ 光谱数据转换.
+
+ :param data:接收到的报文
+ :return: 指令类型和内容
+ """
+ try:
+ assert len(data) > 2
+ except AssertionError:
+ logging.error('指令转换失败,长度不足3')
+ return '', None
+ cmd, data = data[:2], data[2:]
+ cmd = cmd.decode('ascii').strip().upper()
+
n_rows, n_cols, n_bands, spec = data[:2], data[2:4], data[4:6], data[6:]
try:
n_rows, n_cols, n_bands = [int.from_bytes(x, byteorder='big') for x in [n_rows, n_cols, n_bands]]
except Exception as e:
- logging.error(f'长宽转换失败, 错误代码{e}, 报文大小: n_rows:{n_rows}, n_cols: {n_cols}, n_bands: {n_bands}')
+ 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)
@@ -96,102 +167,70 @@ def parse_protocol(data: bytes) -> (str, any):
except AssertionError:
logging.error('图像指令转换失败,数据长度错误')
return '', None
- spec = np.frombuffer(spec, dtype=np.uint16).reshape(n_cols, n_rows, -1)
+ spec = spec.reshape((n_rows, n_bands, -1)).transpose(0, 2, 1)
return cmd, spec
-def create_pipes(rgb_receive_name, rgb_send_name, spec_receive_name):
- while True:
+ def send_data(self,cmd:str, brix, green_percentage, weigth, diameter, defect_num, total_defect_area, rp):
+ # start_time = time.time()
+ #
+ # rp1 = Image.fromarray(rp.astype(np.uint8))
+ # # cv2.imwrite('rp1.bmp', rp1)
+ #
+ # # 将 Image 对象保存到 BytesIO 流中
+ # img_bytes = io.BytesIO()
+ # rp1.save(img_bytes, format='BMP')
+ # img_bytes = img_bytes.getvalue()
+
+ # width = rp.shape[0]
+ # height = rp.shape[1]
+ # print(width, height)
+ # img_bytes = rp.tobytes()
+ # length = len(img_bytes) + 18
+ # print(length)
+ # length = length.to_bytes(4, byteorder='big')
+ # width = width.to_bytes(2, byteorder='big')
+ # height = height.to_bytes(2, byteorder='big')
+ cmd = cmd.strip().upper()
+ cmd_type = 'RE'
+ cmd_re = cmd_type.upper().encode('ascii')
+ img = np.asarray(rp, dtype=np.uint8) # 将图像转换为 NumPy 数组
+ height = img.shape[0] # 获取图像的高度
+ width = img.shape[1] # 获取图像的宽度
+ height = height.to_bytes(2, byteorder='big')
+ width = width.to_bytes(2, byteorder='big')
+ img_bytes = img.tobytes()
+ 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 = length.to_bytes(4, byteorder='big')
+ if cmd == 'TO':
+ brix = 0
+ brix = brix.to_bytes(1, 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')
+ gp = 0
+ gp = gp.to_bytes(1, byteorder='big')
+ 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
try:
- # 打开或创建命名管道
- rgb_receive = win32pipe.CreateNamedPipe(
- rgb_receive_name,
- win32pipe.PIPE_ACCESS_INBOUND,
- win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_WAIT,
- 1, 80000000, 80000000, 0, None
- )
- rgb_send = win32pipe.CreateNamedPipe(
- rgb_send_name,
- win32pipe.PIPE_ACCESS_OUTBOUND, # 修改为输出模式
- win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_WAIT,
- 1, 80000000, 80000000, 0, None
- )
- spec_receive = win32pipe.CreateNamedPipe(
- spec_receive_name,
- win32pipe.PIPE_ACCESS_INBOUND,
- win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_WAIT,
- 1, 200000000, 200000000, 0, None
- )
- print("pipe管道创建成功,等待连接...")
- # 等待发送端连接
- win32pipe.ConnectNamedPipe(rgb_receive, None)
- print("rgb_receive connected.")
- # 等待发送端连接
- win32pipe.ConnectNamedPipe(rgb_send, None)
- print("rgb_send connected.")
- win32pipe.ConnectNamedPipe(rgb_receive, None)
- print("spec_receive connected.")
- return rgb_receive, rgb_send, spec_receive
-
+ win32file.WriteFile(self.rgb_send, send_message)
+ time.sleep(0.01)
+ print('发送成功')
+ # print(len(send_message))
except Exception as e:
- print(f"管道创建连接失败,失败原因: {e}")
- print("等待5秒后重试...")
- time.sleep(5)
- continue
+ logging.error(f'发送完成指令失败,错误类型:{e}')
+ return False
-def send_data(pipe_send, long_axis, short_axis, defect_num, total_defect_area, rp):
- # start_time = time.time()
- #
- rp1 = Image.fromarray(rp.astype(np.uint8))
- # cv2.imwrite('rp1.bmp', rp1)
+ # end_time = time.time()
+ # print(f'发送时间:{end_time - start_time}秒')
- # 将 Image 对象保存到 BytesIO 流中
- img_bytes = io.BytesIO()
- rp1.save(img_bytes, format='BMP')
- img_bytes = img_bytes.getvalue()
+ return True
- # width = rp.shape[0]
- # height = rp.shape[1]
- # print(width, height)
- # img_bytes = rp.tobytes()
- # length = len(img_bytes) + 18
- # print(length)
- # length = length.to_bytes(4, byteorder='big')
- # width = width.to_bytes(2, byteorder='big')
- # height = height.to_bytes(2, byteorder='big')
-
- print(f'原始长度:', len(rp.tobytes()))
- print(f'发送长度:', len(img_bytes))
-
- long_axis = long_axis.to_bytes(2, byteorder='big')
- short_axis = short_axis.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) + 4).to_bytes(4, byteorder='big')
- # cmd_type = 'RIM'
- # result = result.encode('ascii')
- # send_message = b'\xaa' + length + (' ' + cmd_type).upper().encode('ascii') + long_axis + short_axis + defect_num + total_defect_area + width + height + img_bytes + b'\xff\xff\xbb'
- # send_message = long_axis + short_axis + defect_num + total_defect_area + img_bytes
- send_message = long_axis + short_axis + defect_num + total_defect_area + length + img_bytes
- # print(long_axis)
- # print(short_axis)
- # print(defect_num)
- # print(total_defect_area)
- # print(width)
- # print(height)
-
- try:
- win32file.WriteFile(pipe_send, send_message)
- time.sleep(0.01)
- print('发送成功')
- # print(len(send_message))
- except Exception as e:
- logging.error(f'发送完成指令失败,错误类型:{e}')
- return False
-
- # end_time = time.time()
- # print(f'发送时间:{end_time - start_time}秒')
-
- return True
@@ -246,204 +285,4 @@ class Logger(object):
print(time.strftime("[%Y-%m-%d_%H-%M-%S]:"), file=f)
print(content, file=f)
else:
- print(content)
-
-
-def contour_process(image_array):
- # 应用中值滤波
- image_filtered = cv2.medianBlur(image_array, 5)
-
- # 形态学闭操作
- kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
- image_closed = cv2.morphologyEx(image_filtered, cv2.MORPH_CLOSE, kernel)
-
- # 查找轮廓
- contours, _ = cv2.findContours(image_closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
-
- # 创建空白图像以绘制轮廓
- image_contours = np.zeros_like(image_array)
-
- # 进行多边形拟合并填充轮廓
- for contour in contours:
- epsilon = 0.001 * cv2.arcLength(contour, True)
- approx = cv2.approxPolyDP(contour, epsilon, True)
- if cv2.contourArea(approx) > 100: # 仅处理较大的轮廓
- cv2.drawContours(image_contours, [approx], -1, (255, 255, 255), -1)
-
- return image_contours
-
-# def get_tomato_dimensions(edge_img):
-# """
-# 根据边缘二值化轮廓图,计算果子的长径、短径和长短径比值。
-# 使用最小外接矩形和最小外接圆两种方法。
-#
-# 参数:
-# edge_img (numpy.ndarray): 边缘二值化轮廓图,背景为黑色,番茄区域为白色。
-#
-# 返回:
-# tuple: (长径, 短径, 长短径比值)
-# """
-# if edge_img is None or edge_img.any() == 0:
-# return (0, 0)
-# # 最小外接矩形
-# rect = cv2.minAreaRect(cv2.findContours(edge_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0][0])
-# major_axis, minor_axis = rect[1]
-# # aspect_ratio = max(major_axis, minor_axis) / min(major_axis, minor_axis)
-#
-# # # 最小外接圆
-# # (x, y), radius = cv2.minEnclosingCircle(
-# # cv2.findContours(edge_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0][0])
-# # diameter = 2 * radius
-# # aspect_ratio_circle = 1.0
-#
-# return (max(major_axis, minor_axis), min(major_axis, minor_axis))
-
-# def get_defect_info(defect_img):
-# """
-# 根据区域缺陷二值化轮廓图,计算缺陷区域的个数和总面积。
-#
-# 参数:
-# defect_img (numpy.ndarray): 番茄区域缺陷二值化轮廓图,背景为黑色,番茄区域为白色,缺陷区域为黑色连通域。
-#
-# 返回:
-# tuple: (缺陷区域个数, 缺陷区域像素面积,缺陷像素总面积)
-# """
-# # 检查输入是否为空
-# if defect_img is None or defect_img.any() == 0:
-# return (0, 0)
-#
-# nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(defect_img, connectivity=4)
-# max_area = max(stats[i, cv2.CC_STAT_AREA] for i in range(1, nb_components))
-# areas = []
-# for i in range(1, nb_components):
-# area = stats[i, cv2.CC_STAT_AREA]
-# if area != max_area:
-# areas.append(area)
-# number_defects = len(areas)
-# total_pixels = sum(areas)
-# return number_defects, total_pixels
-
-def analyze_ellipse(image_array):
- # 查找白色区域的轮廓
- _, binary_image = cv2.threshold(image_array, 127, 255, cv2.THRESH_BINARY)
- contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
-
- # 初始化变量用于存储最大轮廓的长径和短径
- major_axis = 0
- minor_axis = 0
-
- # 对每个找到的轮廓,找出可以包围它的最小椭圆,并计算长径和短径
- for contour in contours:
- if len(contour) >= 5: # 至少需要5个点来拟合椭圆
- ellipse = cv2.fitEllipse(contour)
- (center, axes, orientation) = ellipse
- major_axis0 = max(axes)
- minor_axis0 = min(axes)
- # 更新最大的长径和短径
- if major_axis0 > major_axis:
- major_axis = major_axis0
- minor_axis = minor_axis0
-
- return major_axis, minor_axis
-
-# 示例用法
-# image_array = cv2.imread('path_to_your_image.bmp', cv2.IMREAD_GRAYSCALE)
-# major_axis, minor_axis = analyze_ellipse(image_array)
-# print(f"Major Axis: {major_axis}, Minor Axis: {minor_axis}")
-
-# 加载新上传的图像进行分析
-new_ellipse_image_path = '/mnt/data/未标题-2.png'
-new_ellipse_image = cv2.imread(new_ellipse_image_path, cv2.IMREAD_GRAYSCALE)
-
-# 使用上述函数进行分析
-analyze_ellipse(new_ellipse_image)
-
-
-def analyze_defect(image_array):
- # 查找白色区域的轮廓
- _, binary_image = cv2.threshold(image_array, 127, 255, cv2.THRESH_BINARY)
- contours_white, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
-
- # 初始化统计数据
- count_black_areas = 0
- total_pixels_black_areas = 0
-
- # 对于每个白色区域,查找内部的黑色小区域
- for contour in contours_white:
- # 创建一个mask以查找内部的黑色区域
- mask = np.zeros_like(image_array)
- cv2.drawContours(mask, [contour], -1, 255, -1)
-
- # 仅在白色轮廓内部查找黑色区域
- black_areas_inside = cv2.bitwise_and(cv2.bitwise_not(image_array), mask)
-
- # 查找黑色区域的轮廓
- contours_black, _ = cv2.findContours(black_areas_inside, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
- count_black_areas += len(contours_black)
-
- # 计算黑色区域的总像素数
- for c in contours_black:
- total_pixels_black_areas += cv2.contourArea(c)
-
- number_defects = count_black_areas
- total_pixels = total_pixels_black_areas
- return number_defects, total_pixels
-
-
-# 示例用法
-# image_array = cv2.imread('path_to_your_image.bmp', cv2.IMREAD_GRAYSCALE)
-# black_areas_count, total_pixels = analyze_black_areas_in_white(image_array)
-# print(f"Number of black areas: {black_areas_count}, Total pixels in black areas: {
-
-
-def analyze_tomato(img):
- """
- 分析给定图像,提取和返回西红柿的长径、短径、缺陷数量和缺陷总面积,并返回处理后的图像。
- 使用 Tomoto 类的图像处理方法,以及自定义的尺寸和缺陷信息获取函数。
- 参数:
- img (numpy.ndarray): 输入的 BGR 图像
- 返回:
- tuple: (长径, 短径, 缺陷区域个数, 缺陷区域总像素, 处理后的图像)
- """
- tomato = Tomato() # 创建 Tomato 类的实例
- # 设置 S-L 通道阈值并处理图像
- threshold_s_l = 180
- s_l = tomato.extract_s_l(img)
- thresholded_s_l = tomato.threshold_segmentation(s_l, threshold_s_l)
- new_bin_img = tomato.largest_connected_component(thresholded_s_l)
- # 绘制西红柿边缘并获取缺陷信息
- edge, mask = tomato.draw_tomato_edge(img, new_bin_img)
- org_defect = tomato.bitwise_and_rgb_with_binary(edge, new_bin_img)
- # 获取西红柿的尺寸信息
- long_axis, short_axis = analyze_ellipse(mask)
- # 获取缺陷信息
- number_defects, total_pixels = analyze_defect(new_bin_img)
- # 将处理后的图像转换为 RGB 格式
- rp = cv2.cvtColor(org_defect, cv2.COLOR_BGR2RGB)
- return long_axis, short_axis, number_defects, total_pixels, rp
-
-
-def analyze_passion_fruit(img, hue_value=37, hue_delta=10, value_target=25, value_delta=10):
- if img is None:
- print("Error: 无图像数据.")
- return None
-
- # 创建PassionFruit类的实例
- pf = Passion_fruit(hue_value=hue_value, hue_delta=hue_delta, value_target=value_target, value_delta=value_delta)
-
- hsv_image = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
- combined_mask = pf.create_mask(hsv_image)
- combined_mask = pf.apply_morphology(combined_mask)
- max_mask = pf.find_largest_component(combined_mask)
-
- # if max_mask is None:
- # print("No significant components found.")
- # return None
- contour_mask = contour_process(max_mask)
- long_axis, short_axis = analyze_ellipse(contour_mask)
- number_defects, total_pixels = analyze_defect(max_mask)
- edge = pf.draw_contours_on_image(img, contour_mask)
- org_defect = pf.bitwise_and_rgb_with_binary(edge, max_mask)
- rp = cv2.cvtColor(org_defect, cv2.COLOR_BGR2RGB)
-
- return long_axis, short_axis, number_defects, total_pixels, rp
+ print(content)
\ No newline at end of file
diff --git a/20240529RGBtest3/xs/01.py b/20240529RGBtest3/xs/01.py
new file mode 100644
index 0000000..043a68a
--- /dev/null
+++ b/20240529RGBtest3/xs/01.py
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+# @Time : 2024/6/15 15:40
+# @Author : TG
+# @File : 01.py
+# @Software: PyCharm
+import joblib
+import numpy as np
+import os
+from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
+from sklearn.svm import SVR
+from sklearn.model_selection import train_test_split
+from sklearn.metrics import mean_squared_error
+
+
+def prepare_data(data):
+ """Reshape data and select specified spectral bands."""
+ reshaped_data = data.reshape(data.shape[0], -1) # 使用动态批量大小
+ selected_bands = [8, 9, 10, 48, 49, 50, 77, 80, 103, 108, 115, 143, 145]
+ return reshaped_data[:, selected_bands]
+
+class SpectralModelingAndPrediction:
+ def __init__(self, model_paths=None):
+ self.models = {
+ "RandomForest": RandomForestRegressor(n_estimators=100),
+ "GradientBoosting": GradientBoostingRegressor(n_estimators=100),
+ "SVR": SVR(kernel='rbf', C=100, gamma=0.1, epsilon=.1),
+ }
+ self.model_paths = model_paths or {}
+
+ def split_data(self, X, y, test_size=0.20, random_state=12):
+ """Split data into training and test sets."""
+ return train_test_split(X, y, test_size=test_size, random_state=random_state)
+
+ def evaluate_model(self, model, X_test, y_test):
+ """Evaluate the model and return MSE and predictions."""
+ y_pred = model.predict(X_test)
+ mse = mean_squared_error(y_test, y_pred)
+ return mse, y_pred
+
+ def print_predictions(self, y_test, y_pred, model_name):
+ """Print actual and predicted values."""
+ print(f"Test Set Predictions for {model_name}:")
+ for i, (real, pred) in enumerate(zip(y_test, y_pred)):
+ print(f"Sample {i + 1}: True Value = {real:.2f}, Predicted Value = {pred:.2f}")
+
+ def fit_and_evaluate(self, X_train, y_train, X_test, y_test):
+ for model_name, model in self.models.items():
+ model.fit(X_train, y_train)
+ if model_name in self.model_paths:
+ joblib.dump(model, self.model_paths[model_name])
+
+ mse, y_pred = self.evaluate_model(model, X_test, y_test)
+ print(f"Model: {model_name}")
+ print(f"Mean Squared Error on the test set: {mse}")
+ self.print_predictions(y_test, y_pred, model_name)
+ print("\n" + "-" * 50 + "\n")
+
+ def load_model(self, model_path):
+ """加载模型"""
+ return joblib.load(model_path)
+
+ def read_spectral_data(self, hdr_path, raw_path):
+ """读取光谱数据"""
+ with open(hdr_path, 'r', encoding='latin1') as hdr_file:
+ lines = hdr_file.readlines()
+ height = width = bands = 0
+ for line in lines:
+ if line.startswith('lines'):
+ height = int(line.split()[-1])
+ elif line.startswith('samples'):
+ width = int(line.split()[-1])
+ elif line.startswith('bands'):
+ bands = int(line.split()[-1])
+
+ raw_image = np.fromfile(raw_path, dtype='uint16')
+ formatImage = np.zeros((height, width, bands))
+
+ for row in range(height):
+ for dim in range(bands):
+ formatImage[row, :, dim] = raw_image[(dim + row * bands) * width:(dim + 1 + row * bands) * width]
+
+ target_height, target_width, target_bands = 30, 30, 224
+ formatImage = self._crop_or_pad(formatImage, height, width, bands, target_height, target_width, target_bands)
+ return formatImage
+
+ def _crop_or_pad(self, formatImage, height, width, bands, target_height, target_width, target_bands):
+ """裁剪或填充图像"""
+ if height > target_height:
+ formatImage = formatImage[:target_height, :, :]
+ elif height < target_height:
+ pad_height = target_height - height
+ formatImage = np.pad(formatImage, ((0, pad_height), (0, 0), (0, 0)), mode='constant', constant_values=0)
+
+ if width > target_width:
+ formatImage = formatImage[:, :target_width, :]
+ elif width < target_width:
+ pad_width = target_width - width
+ formatImage = np.pad(formatImage, ((0, 0), (0, pad_width), (0, 0)), mode='constant', constant_values=0)
+
+ if bands > target_bands:
+ formatImage = formatImage[:, :, :target_bands]
+ elif bands < target_bands:
+ pad_bands = target_bands - bands
+ formatImage = np.pad(formatImage, ((0, 0), (0, 0), (0, pad_bands)), mode='constant', constant_values=0)
+
+ return formatImage
+
+ def predict(self, data, model_name):
+ """预测数据"""
+ model = self.load_model(self.model_paths[model_name])
+ return model.predict(data)
+
+ def run_training_and_prediction(self, training_data, training_target, prediction_directory):
+ """运行训练和预测流程"""
+ # 将数据重塑为2维
+ training_data = training_data.reshape(training_data.shape[0], -1)
+
+ # 训练阶段
+ X_train, X_test, y_train, y_test = self.split_data(training_data, training_target)
+ self.fit_and_evaluate(X_train, y_train, X_test, y_test)
+
+ # 预测阶段
+ all_spectral_data = []
+ for i in range(1, 101):
+ hdr_path = os.path.join(prediction_directory, f'{i}.HDR')
+ raw_path = os.path.join(prediction_directory, f'{i}')
+ if not os.path.exists(hdr_path) or not os.path.exists(raw_path):
+ print(f"File {hdr_path} or {raw_path} does not exist.")
+ continue
+ spectral_data = self.read_spectral_data(hdr_path, raw_path)
+ all_spectral_data.append(spectral_data)
+
+ if not all_spectral_data:
+ print("No spectral data was read. Please check the file paths and try again.")
+ return
+
+ all_spectral_data = np.stack(all_spectral_data)
+ print(all_spectral_data.shape) # This should print (100, 30, 30, 224) or fewer if some files are missing
+
+ data_prepared = prepare_data(all_spectral_data)
+ for model_name in self.models.keys():
+ predictions = self.predict(data_prepared, model_name)
+ print(f"Predictions for {model_name}:")
+ print(predictions)
+ print("\n" + "-" * 50 + "\n")
+
+
+if __name__ == "__main__":
+ model_paths = {
+ "RandomForest": '../20240529RGBtest3/models/random_forest_model_3.joblib',
+ "GradientBoosting": '../20240529RGBtest3/models/gradient_boosting_model_3.joblib',
+ "SVR": '../20240529RGBtest3/models/svr_model_3.joblib',
+ }
+
+ sweetness_acidity = np.array([
+ 16.2, 16.1, 17, 16.9, 16.8, 17.8, 18.1, 17.2, 17, 17.2, 17.1, 17.2,
+ 17.2, 17.2, 18.1, 17, 17.6, 17.4, 17.1, 17.1, 16.9, 17.6, 17.3, 16.3,
+ 16.5, 18.7, 17.6, 16.2, 16.8, 17.2, 16.8, 17.3, 16, 16.6, 16.7, 16.7,
+ 17.3, 16.3, 16.8, 17.4, 17.3, 16.3, 16.1, 17.2, 18.6, 16.8, 16.1, 17.2,
+ 18.3, 16.5, 16.6, 17, 17, 17.8, 16.4, 18, 17.7, 17, 18.3, 16.8, 17.5,
+ 17.7, 18.5, 18, 17.7, 17, 18.3, 18.1, 17.4, 17.7, 17.8, 16.3, 17.1, 16.8,
+ 17.2, 17.5, 16.6, 17.7, 17.1, 17.7, 19.4, 20.3, 17.3, 15.8, 18, 17.7,
+ 17.2, 15.2, 18, 18.4, 18.3, 15.7, 17.2, 18.6, 15.6, 17, 16.9, 17.4, 17.8,
+ 16.5
+ ])
+
+ # Specify the directory containing the HDR and RAW files
+ directory = r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\xs\光谱数据3030'
+
+ modeling = SpectralModelingAndPrediction(model_paths)
+
+ # Initialize a list to hold all the spectral data arrays
+ all_spectral_data = []
+
+ # Loop through each data set (assuming there are 100 datasets)
+ for i in range(1, 101):
+ hdr_path = os.path.join(directory, f'{i}.HDR')
+ raw_path = os.path.join(directory, f'{i}')
+
+ # Check if files exist
+ if not os.path.exists(hdr_path) or not os.path.exists(raw_path):
+ print(f"File {hdr_path} or {raw_path} does not exist.")
+ continue
+
+ # Read data
+ spectral_data = modeling.read_spectral_data(hdr_path, raw_path)
+ all_spectral_data.append(spectral_data)
+
+ # Stack all data into a single numpy array if not empty
+ if all_spectral_data:
+ all_spectral_data = np.stack(all_spectral_data)
+ print(all_spectral_data.shape) # This should print (100, 30, 30, 224) or fewer if some files are missing
+
+ # Run training and prediction
+ modeling.run_training_and_prediction(all_spectral_data, sweetness_acidity, directory)
+ else:
+ print("No spectral data was read. Please check the file paths and try again.")
diff --git a/20240529RGBtest3/xs/dimensionality_reduction.py b/20240529RGBtest3/xs/dimensionality_reduction.py
index b9e266f..50b586e 100644
--- a/20240529RGBtest3/xs/dimensionality_reduction.py
+++ b/20240529RGBtest3/xs/dimensionality_reduction.py
@@ -6,14 +6,15 @@ from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from spec_read import all_spectral_data
+import joblib
def prepare_data(data):
"""Reshape data and select specified spectral bands."""
reshaped_data = data.reshape(100, -1)
- selected_bands = [1, 2, 3, 58, 59, 60, 106, 107, 108, 112, 113, 114, 142, 146, 200, 201, 202]
+ selected_bands = [8, 9, 10, 48, 49, 50, 77, 80, 103, 108, 115, 143, 145]
return reshaped_data[:, selected_bands]
-def split_data(X, y, test_size=0.20, random_state=1):
+def split_data(X, y, test_size=0.20, random_state=12):
"""Split data into training and test sets."""
return train_test_split(X, y, test_size=test_size, random_state=random_state)
@@ -49,11 +50,13 @@ def main():
"RandomForest": RandomForestRegressor(n_estimators=100),
"GradientBoosting": GradientBoostingRegressor(n_estimators=100),
"SVR": SVR(kernel='rbf', C=100, gamma=0.1, epsilon=.1),
- "KNeighbors": KNeighborsRegressor(n_neighbors=5)
}
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')
+
mse, y_pred = evaluate_model(model, X_test, y_test)
print(f"Model: {model_name}")
print(f"Mean Squared Error on the test set: {mse}")
diff --git a/20240529RGBtest3/xs/graient.py b/20240529RGBtest3/xs/graient.py
new file mode 100644
index 0000000..e46cbfc
--- /dev/null
+++ b/20240529RGBtest3/xs/graient.py
@@ -0,0 +1,117 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from sklearn.ensemble import RandomForestRegressor
+from sklearn.model_selection import train_test_split
+from sklearn.metrics import mean_squared_error
+from spec_read import all_spectral_data
+
+def prepare_data(data):
+ """Calculate the average spectral values and their gradients for each fruit across all pixels."""
+ avg_spectra = np.mean(data, axis=(1, 2))
+ gradients = np.gradient(avg_spectra, axis=1)
+ second_gradients = np.gradient(gradients, axis=1)
+ return avg_spectra, gradients, second_gradients
+
+def train_model(X, y):
+ """Train a RandomForest model."""
+ rf = RandomForestRegressor(n_estimators=100)
+ rf.fit(X, y)
+ return rf
+
+def split_data(X, y, test_size=0.20, random_state=2):
+ """Split data into training and test sets."""
+ return train_test_split(X, y, test_size=test_size, random_state=random_state)
+
+def evaluate_model(model, X_test, y_test):
+ """Evaluate the model and return MSE and predictions."""
+ y_pred = model.predict(X_test)
+ mse = mean_squared_error(y_test, y_pred)
+ return mse, y_pred
+
+def print_predictions(y_test, y_pred):
+ """Print actual and predicted values."""
+ print("Test Set Predictions:")
+ for i, (real, pred) in enumerate(zip(y_test, y_pred)):
+ print(f"Sample {i + 1}: True Value = {real:.2f}, Predicted Value = {pred:.2f}")
+
+def plot_spectra(X, y):
+ """Plot the average spectra for all samples and annotate with sweetness_acidity values."""
+ plt.figure(figsize=(10, 6))
+ for i in range(X.shape[0]):
+ plt.plot(X[i], label=f'Sample {i+1}')
+ plt.annotate(f'{y[i]:.1f}', xy=(len(X[i])-1, X[i][-1]), xytext=(5, 0),
+ textcoords='offset points', ha='left', va='center')
+ plt.xlabel('Wavelength Index')
+ plt.ylabel('Average Spectral Value')
+ plt.title('Average Spectral Curves for All Samples')
+ plt.legend(loc='upper right', bbox_to_anchor=(1.1, 1.05))
+ plt.show()
+
+def plot_gradients(gradients):
+ """Plot the gradient of the average spectra for all samples."""
+ plt.figure(figsize=(10, 6))
+ for i in range(gradients.shape[0]):
+ plt.plot(gradients[i], label=f'Sample {i+1}')
+ plt.xlabel('Wavelength Index')
+ plt.ylabel('Gradient Value')
+ plt.title('Gradient of Average Spectral Curves for All Samples')
+ plt.legend(loc='upper right', bbox_to_anchor=(1.1, 1.05))
+ plt.show()
+
+def plot_second_gradients(second_gradients):
+ """Plot the second gradient of the average spectra for all samples."""
+ plt.figure(figsize=(10, 6))
+ for i in range(second_gradients.shape[0]):
+ plt.plot(second_gradients[i], label=f'Sample {i+1}')
+ plt.xlabel('Wavelength Index')
+ plt.ylabel('Second Gradient Value')
+ plt.title('Second Gradient of Average Spectral Curves for All Samples')
+ plt.legend(loc='upper right', bbox_to_anchor=(1.1, 1.05))
+ plt.show()
+
+def main():
+ sweetness_acidity = np.array([
+ 16.2, 16.1, 17, 16.9, 16.8, 17.8, 18.1, 17.2, 17, 17.2, 17.1, 17.2,
+ 17.2, 17.2, 18.1, 17, 17.6, 17.4, 17.1, 17.1, 16.9, 17.6, 17.3, 16.3,
+ 16.5, 18.7, 17.6, 16.2, 16.8, 17.2, 16.8, 17.3, 16, 16.6, 16.7, 16.7,
+ 17.3, 16.3, 16.8, 17.4, 17.3, 16.3, 16.1, 17.2, 18.6, 16.8, 16.1, 17.2,
+ 18.3, 16.5, 16.6, 17, 17, 17.8, 16.4, 18, 17.7, 17, 18.3, 16.8, 17.5,
+ 17.7, 18.5, 18, 17.7, 17, 18.3, 18.1, 17.4, 17.7, 17.8, 16.3, 17.1, 16.8,
+ 17.2, 17.5, 16.6, 17.7, 17.1, 17.7, 19.4, 20.3, 17.3, 15.8, 18, 17.7,
+ 17.2, 15.2, 18, 18.4, 18.3, 15.7, 17.2, 18.6, 15.6, 17, 16.9, 17.4, 17.8,
+ 16.5
+ ])
+
+ X_avg, X_grad, X_second_grad = prepare_data(all_spectral_data)
+
+ plot_spectra(X_avg, sweetness_acidity) # Plot average spectral curves
+ plot_gradients(X_grad) # Plot gradient curves
+ plot_second_gradients(X_second_grad) # Plot second gradient curves
+
+ # Train and evaluate using average spectral values
+ X_train_avg, X_test_avg, y_train_avg, y_test_avg = split_data(X_avg, sweetness_acidity)
+ rf_model_avg = train_model(X_train_avg, y_train_avg)
+ mse_avg, y_pred_avg = evaluate_model(rf_model_avg, X_test_avg, y_test_avg)
+ print("Mean Squared Error using average spectral values:", mse_avg)
+
+ # Train and evaluate using first gradients
+ X_train_grad, X_test_grad, y_train_grad, y_test_grad = split_data(X_grad, sweetness_acidity)
+ rf_model_grad = train_model(X_train_grad, y_train_grad)
+ mse_grad, y_pred_grad = evaluate_model(rf_model_grad, X_test_grad, y_test_grad)
+ print("Mean Squared Error using first gradients:", mse_grad)
+
+ # Train and evaluate using second gradients
+ X_train_second_grad, X_test_second_grad, y_train_second_grad, y_test_second_grad = split_data(X_second_grad, sweetness_acidity)
+ rf_model_second_grad = train_model(X_train_second_grad, y_train_second_grad)
+ mse_second_grad, y_pred_second_grad = evaluate_model(rf_model_second_grad, X_test_second_grad, y_test_second_grad)
+ print("Mean Squared Error using second gradients:", mse_second_grad)
+
+ print("Predictions using average spectral values:")
+ print_predictions(y_test_avg, y_pred_avg)
+ print("Predictions using first gradients:")
+ print_predictions(y_test_grad, y_pred_grad)
+ print("Predictions using second gradients:")
+ print_predictions(y_test_second_grad, y_pred_second_grad)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/20240529RGBtest3/xs/graient_gui.py b/20240529RGBtest3/xs/graient_gui.py
new file mode 100644
index 0000000..a1d73f5
--- /dev/null
+++ b/20240529RGBtest3/xs/graient_gui.py
@@ -0,0 +1,135 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from sklearn.ensemble import RandomForestRegressor
+from sklearn.model_selection import train_test_split
+from sklearn.metrics import mean_squared_error
+from sklearn.preprocessing import MinMaxScaler
+from spec_read import all_spectral_data
+
+
+def prepare_data(data):
+ """Calculate the average spectral values and their gradients for each fruit across all pixels, and normalize them."""
+ avg_spectra = np.mean(data, axis=(1, 2))
+ gradients = np.gradient(avg_spectra, axis=1)
+ second_gradients = np.gradient(gradients, axis=1)
+
+ scaler = MinMaxScaler()
+ avg_spectra = scaler.fit_transform(avg_spectra)
+ gradients = scaler.fit_transform(gradients)
+ second_gradients = scaler.fit_transform(second_gradients)
+
+ return avg_spectra, gradients, second_gradients
+
+
+def train_model(X, y):
+ """Train a RandomForest model."""
+ rf = RandomForestRegressor(n_estimators=100)
+ rf.fit(X, y)
+ return rf
+
+
+def split_data(X, y, test_size=0.20, random_state=2):
+ """Split data into training and test sets."""
+ return train_test_split(X, y, test_size=test_size, random_state=random_state)
+
+
+def evaluate_model(model, X_test, y_test):
+ """Evaluate the model and return MSE and predictions."""
+ y_pred = model.predict(X_test)
+ mse = mean_squared_error(y_test, y_pred)
+ return mse, y_pred
+
+
+def print_predictions(y_test, y_pred):
+ """Print actual and predicted values."""
+ print("Test Set Predictions:")
+ for i, (real, pred) in enumerate(zip(y_test, y_pred)):
+ print(f"Sample {i + 1}: True Value = {real:.2f}, Predicted Value = {pred:.2f}")
+
+
+def plot_spectra(X, y):
+ """Plot the average spectra for all samples and annotate with sweetness_acidity values."""
+ plt.figure(figsize=(10, 6))
+ for i in range(X.shape[0]):
+ plt.plot(X[i], label=f'Sample {i + 1}')
+ plt.annotate(f'{y[i]:.1f}', xy=(len(X[i]) - 1, X[i][-1]), xytext=(5, 0),
+ textcoords='offset points', ha='left', va='center')
+ plt.xlabel('Wavelength Index')
+ plt.ylabel('Average Spectral Value')
+ plt.title('Average Spectral Curves for All Samples')
+ plt.legend(loc='upper right', bbox_to_anchor=(1.1, 1.05))
+ plt.show()
+
+
+def plot_gradients(gradients):
+ """Plot the gradient of the average spectra for all samples."""
+ plt.figure(figsize=(10, 6))
+ for i in range(gradients.shape[0]):
+ plt.plot(gradients[i], label=f'Sample {i + 1}')
+ plt.xlabel('Wavelength Index')
+ plt.ylabel('Gradient Value')
+ plt.title('Gradient of Average Spectral Curves for All Samples')
+ plt.legend(loc='upper right', bbox_to_anchor=(1.1, 1.05))
+ plt.show()
+
+
+def plot_second_gradients(second_gradients):
+ """Plot the second gradient of the average spectra for all samples."""
+ plt.figure(figsize=(10, 6))
+ for i in range(second_gradients.shape[0]):
+ plt.plot(second_gradients[i], label=f'Sample {i + 1}')
+ plt.xlabel('Wavelength Index')
+ plt.ylabel('Second Gradient Value')
+ plt.title('Second Gradient of Average Spectral Curves for All Samples')
+ plt.legend(loc='upper right', bbox_to_anchor=(1.1, 1.05))
+ plt.show()
+
+
+def main():
+ sweetness_acidity = np.array([
+ 16.2, 16.1, 17, 16.9, 16.8, 17.8, 18.1, 17.2, 17, 17.2, 17.1, 17.2,
+ 17.2, 17.2, 18.1, 17, 17.6, 17.4, 17.1, 17.1, 16.9, 17.6, 17.3, 16.3,
+ 16.5, 18.7, 17.6, 16.2, 16.8, 17.2, 16.8, 17.3, 16, 16.6, 16.7, 16.7,
+ 17.3, 16.3, 16.8, 17.4, 17.3, 16.3, 16.1, 17.2, 18.6, 16.8, 16.1, 17.2,
+ 18.3, 16.5, 16.6, 17, 17, 17.8, 16.4, 18, 17.7, 17, 18.3, 16.8, 17.5,
+ 17.7, 18.5, 18, 17.7, 17, 18.3, 18.1, 17.4, 17.7, 17.8, 16.3, 17.1, 16.8,
+ 17.2, 17.5, 16.6, 17.7, 17.1, 17.7, 19.4, 20.3, 17.3, 15.8, 18, 17.7,
+ 17.2, 15.2, 18, 18.4, 18.3, 15.7, 17.2, 18.6, 15.6, 17, 16.9, 17.4, 17.8,
+ 16.5
+ ])
+
+ X_avg, X_grad, X_second_grad = prepare_data(all_spectral_data)
+
+ plot_spectra(X_avg, sweetness_acidity) # Plot average spectral curves
+ plot_gradients(X_grad) # Plot gradient curves
+ plot_second_gradients(X_second_grad) # Plot second gradient curves
+
+ # Train and evaluate using average spectral values
+ X_train_avg, X_test_avg, y_train_avg, y_test_avg = split_data(X_avg, sweetness_acidity)
+ rf_model_avg = train_model(X_train_avg, y_train_avg)
+ mse_avg, y_pred_avg = evaluate_model(rf_model_avg, X_test_avg, y_test_avg)
+ print("Mean Squared Error using average spectral values:", mse_avg)
+
+ # Train and evaluate using first gradients
+ X_train_grad, X_test_grad, y_train_grad, y_test_grad = split_data(X_grad, sweetness_acidity)
+ rf_model_grad = train_model(X_train_grad, y_train_grad)
+ mse_grad, y_pred_grad = evaluate_model(rf_model_grad, X_test_grad, y_test_grad)
+ print("Mean Squared Error using first gradients:", mse_grad)
+
+ # Train and evaluate using second gradients
+ X_train_second_grad, X_test_second_grad, y_train_second_grad, y_test_second_grad = split_data(X_second_grad,
+ sweetness_acidity)
+ rf_model_second_grad = train_model(X_train_second_grad, y_train_second_grad)
+ mse_second_grad, y_pred_second_grad = evaluate_model(rf_model_second_grad, X_test_second_grad, y_test_second_grad)
+ print("Mean Squared Error using second gradients:", mse_second_grad)
+
+ print("Predictions using average spectral values:")
+ print_predictions(y_test_avg, y_pred_avg)
+ print("Predictions using first gradients:")
+ print_predictions(y_test_grad, y_pred_grad)
+ print("Predictions using second gradients:")
+ print_predictions(y_test_second_grad, y_pred_second_grad)
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/20240529RGBtest3/xs/hsv.py b/20240529RGBtest3/xs/hsv.py
index f06a7ad..0548714 100644
--- a/20240529RGBtest3/xs/hsv.py
+++ b/20240529RGBtest3/xs/hsv.py
@@ -84,6 +84,6 @@ def process_images_in_folder(input_folder, output_folder):
# 主函数调用
-input_folder = r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\data\passion_fruit_img' # 替换为你的输入文件夹路径
-output_folder = r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\data\01' # 替换为你的输出文件夹路径
+input_folder = '/Users/xs/PycharmProjects/super-tomato/baixiangguo/rgb效果/test' # 替换为你的输入文件夹路径
+output_folder = '/Users/xs/PycharmProjects/super-tomato/baixiangguo/rgb效果/testfore' # 替换为你的输出文件夹路径
process_images_in_folder(input_folder, output_folder)
\ No newline at end of file
diff --git a/20240529RGBtest3/xs/mean.py b/20240529RGBtest3/xs/mean.py
index d3d1505..dd5c363 100644
--- a/20240529RGBtest3/xs/mean.py
+++ b/20240529RGBtest3/xs/mean.py
@@ -15,7 +15,7 @@ def train_model(X, y):
rf.fit(X, y)
return rf
-def split_data(X, y, test_size=0.20, random_state=42):
+def split_data(X, y, test_size=0.20, random_state=4):
"""Split data into training and test sets."""
return train_test_split(X, y, test_size=test_size, random_state=random_state)
diff --git a/20240529RGBtest3/xs/predict.py b/20240529RGBtest3/xs/predict.py
new file mode 100644
index 0000000..b1c3058
--- /dev/null
+++ b/20240529RGBtest3/xs/predict.py
@@ -0,0 +1,85 @@
+import joblib
+import numpy as np
+import os
+from dimensionality_reduction import prepare_data
+
+def read_spectral_data(hdr_path, raw_path):
+ # Read HDR file for image dimensions information
+ with open(hdr_path, 'r', encoding='latin1') as hdr_file:
+ lines = hdr_file.readlines()
+ height = width = bands = 0
+ for line in lines:
+ if line.startswith('lines'):
+ height = int(line.split()[-1])
+ elif line.startswith('samples'):
+ width = int(line.split()[-1])
+ elif line.startswith('bands'):
+ bands = int(line.split()[-1])
+
+ # Read spectral data from RAW file
+ raw_image = np.fromfile(raw_path, dtype='uint16')
+ # Initialize the image with the actual read dimensions
+ formatImage = np.zeros((height, width, bands))
+
+ for row in range(height):
+ for dim in range(bands):
+ formatImage[row, :, dim] = raw_image[(dim + row * bands) * width:(dim + 1 + row * bands) * width]
+
+ # Ensure the image is 30x30x224 by cropping or padding
+ target_height, target_width, target_bands = 30, 30, 224
+ # Crop or pad height
+ if height > target_height:
+ formatImage = formatImage[:target_height, :, :]
+ elif height < target_height:
+ pad_height = target_height - height
+ formatImage = np.pad(formatImage, ((0, pad_height), (0, 0), (0, 0)), mode='constant', constant_values=0)
+
+ # Crop or pad width
+ if width > target_width:
+ formatImage = formatImage[:, :target_width, :]
+ elif width < target_width:
+ pad_width = target_width - width
+ formatImage = np.pad(formatImage, ((0, 0), (0, pad_width), (0, 0)), mode='constant', constant_values=0)
+
+ # Crop or pad bands if necessary (usually bands should not change)
+ if bands > target_bands:
+ formatImage = formatImage[:, :, :target_bands]
+ elif bands < target_bands:
+ pad_bands = target_bands - bands
+ formatImage = np.pad(formatImage, ((0, 0), (0, 0), (0, pad_bands)), mode='constant', constant_values=0)
+
+ return formatImage
+
+def load_model(model_path):
+ """加载模型"""
+ return joblib.load(model_path)
+
+def predict(model, data):
+ """预测数据"""
+ return model.predict(data)
+
+def main():
+ # 加载模型
+ model = load_model('../models/random_forest_model_2.joblib')
+
+ # 读取数据
+ directory = '/Users/xs/PycharmProjects/super-tomato/baixiangguo/光谱数据3030/'
+ all_spectral_data = []
+ for i in range(1, 101):
+ hdr_path = os.path.join(directory, f'{i}.HDR')
+ raw_path = os.path.join(directory, f'{i}')
+ spectral_data = read_spectral_data(hdr_path, raw_path)
+ all_spectral_data.append(spectral_data)
+ all_spectral_data = np.stack(all_spectral_data)
+
+ # 预处理数据
+ data_prepared = prepare_data(all_spectral_data)
+
+ # 预测数据
+ predictions = predict(model, data_prepared)
+
+ # 打印预测结果
+ print(predictions)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/20240529RGBtest3/xs/rgb.py b/20240529RGBtest3/xs/rgb.py
index 8aa3af1..c42d1a0 100644
--- a/20240529RGBtest3/xs/rgb.py
+++ b/20240529RGBtest3/xs/rgb.py
@@ -66,5 +66,5 @@ def dual_threshold_and_max_component(image_path, hue_value=37, hue_delta=10, val
plt.show()
# 使用函数
-image_path = r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\data\passion_fruit_img\50.bmp' # 替换为你的图片路径
+image_path = '/Users/xs/PycharmProjects/super-tomato/baixiangguo/middle/52.bmp' # 替换为你的图片路径
dual_threshold_and_max_component(image_path)
\ No newline at end of file
diff --git a/20240529RGBtest3/通信协议(20240612).md b/20240529RGBtest3/通信协议(20240612).md
index fbdc10c..ac1e960 100644
--- a/20240529RGBtest3/通信协议(20240612).md
+++ b/20240529RGBtest3/通信协议(20240612).md
@@ -8,7 +8,7 @@
## 长度
-一个32位无符号数length,长度 = 数据字节数i + 6 。
`长度1`指length[31:24],`长度2`指length[23:16],`长度3`指length[15:8],`长度4`指length[7:0]
+一个32位无符号数length,长度 = 数据字节数i + 2 。
`长度1`指length[31:24],`长度2`指length[23:16],`长度3`指length[15:8],`长度4`指length[7:0]
## 指令
@@ -38,7 +38,7 @@ $$
**光谱数据包:' 指令1''指令2 '**,`数据1`~`数据i`包含了光谱数据的行数rows(高度)、列数cols(宽度)、谱段数bands、以及光谱数据,组合方式为**高度+宽度+谱段数+光谱数据**
$$
-i-6=rows \times cols \times bands \times 4
+i-6=rows \times cols \times bands \times 2
$$
`数据1`~`数据i`的分布具体如下: