mirror of
https://github.com/NanjingForestryUniversity/supermachine--tomato-passion_fruit.git
synced 2025-11-08 22:34:00 +00:00
feat:新增百香果rgb部分代码;
refactor:重构部分代码逻辑
This commit is contained in:
parent
ea62ca237c
commit
828015c206
84
.gitignore
vendored
Normal file
84
.gitignore
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
!/20240529RGBtest3/data/
|
||||
!/20240529RGBtest3/data/
|
||||
!/20240410RGBtest1/super-tomato/defect_big.bmp
|
||||
!/20240410RGBtest1/super-tomato/defect_mask.bmp
|
||||
!/20240410RGBtest1/defect_big.bmp
|
||||
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
||||
04average.ipynb
|
||||
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@ -1,4 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="tengg" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="tengg" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
6
.idea/other.xml
generated
Normal file
6
.idea/other.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PySciProjectComponent">
|
||||
<option name="PY_INTERACTIVE_PLOTS_SUGGESTED" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
4
.idea/supermachine--tomato-passion_fruit.iml
generated
4
.idea/supermachine--tomato-passion_fruit.iml
generated
@ -1,7 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.idea/copilot/chatSessions" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
|
||||
@ -214,7 +214,7 @@ def extract_max_connected_area(image, lower_hsv, upper_hsv):
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||
parser.add_argument('--dir_path', type=str, default=r'D:\project\Tomato\20240410RGBtest2\datatest',
|
||||
parser.add_argument('--dir_path', type=str, default=r'D:\project\supermachine--tomato-passion_fruit\20240419RGBtest2\data',
|
||||
help='the directory path of images')
|
||||
parser.add_argument('--threshold_s_l', type=int, default=180,
|
||||
help='the threshold for s_l')
|
||||
@ -224,7 +224,7 @@ def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
for img_file in os.listdir(args.dir_path):
|
||||
if img_file.endswith('.png'):
|
||||
if img_file.endswith('.bmp'):
|
||||
img_path = os.path.join(args.dir_path, img_file)
|
||||
s_l = extract_s_l(img_path)
|
||||
otsu_thresholded = otsu_threshold(s_l)
|
||||
|
||||
@ -211,7 +211,7 @@ def extract_max_connected_area(image_path, lower_hsv, upper_hsv):
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||
parser.add_argument('--dir_path', type=str, default=r'D:\project\Tomato\20240410RGBtest2\data',
|
||||
parser.add_argument('--dir_path', type=str, default=r'D:\project\supermachine--tomato-passion_fruit\20240419RGBtest2\data',
|
||||
help='the directory path of images')
|
||||
parser.add_argument('--threshold_s_l', type=int, default=180,
|
||||
help='the threshold for s_l')
|
||||
|
||||
@ -20,7 +20,10 @@ ASCII字符,比如`类型1`为' '(空格),`类型2`为' '(空格),`类型3
|
||||
|
||||
- **RGB图像数据包' (空格)''(空格) ''I''M'**,`数据1`~`数据i`包含了图像的行数rows(高度)、列数cols(宽度)、以及图像的RGB数据
|
||||
|
||||
$i-4=rows \times cols \times 3$具体如下:
|
||||
$$
|
||||
i-4=rows \times cols \times 3
|
||||
$$
|
||||
具体如下:
|
||||
|
||||
| 行数1 | 行数2 | 列数1 | 列数2 | 图像数据1 | ... | 图像数据(i-4) |
|
||||
| :--------: | :-------: | :--------: | :-------: | :-------: | :--: | :-----------: |
|
||||
@ -28,7 +31,11 @@ ASCII字符,比如`类型1`为' '(空格),`类型2`为' '(空格),`类型3
|
||||
|
||||
**返回结果数据包' (空格)''R''I''M'**,`数据1`~`数据i`包含了长径long、短径short、缺陷个数num、缺陷面积area、结果图像的行数rows(高度)、列数cols(宽度)、以及结果图像的RGB数据
|
||||
|
||||
$i-14=rows \times cols \times 3$具体如下:
|
||||
|
||||
$$
|
||||
i-14=rows \times cols \times 3
|
||||
$$
|
||||
具体如下:
|
||||
|
||||
| 长径1 | 长径2 | 短径1 | 短径2 | 缺陷个数1 | 缺陷个数2 | 缺陷面积1 | 缺陷面积2 | 缺陷面积3 | 缺陷面积4 | 行数1 | 行数2 | 列数1 | 列数2 | 图像数据1 | 图像数据(i-14) |
|
||||
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
|
||||
@ -36,7 +43,10 @@ ASCII字符,比如`类型1`为' '(空格),`类型2`为' '(空格),`类型3
|
||||
|
||||
- **光谱数据包' (空格)''(空格) ''S''P'**,`数据1`~`数据i`包含了光谱数据的行数rows(高度)、列数cols(宽度)、谱段数bands、以及图像的光谱数据
|
||||
|
||||
$i-6=rows \times cols \times bands \times 4$具体如下:
|
||||
$$
|
||||
i-6=rows \times cols \times bands \times 4
|
||||
$$
|
||||
具体如下:
|
||||
|
||||
| 行数1 | 行数2 | 列数1 | 列数2 | 谱段1 | 谱段2 | 图像数据1 | ... | 图像数据(i-6) |
|
||||
| :--------: | :-------: | :--------: | :-------: | :---------: | :--------: | :-------: | :--: | :-----------: |
|
||||
|
||||
224
20240529RGBtest3/classifer.py
Normal file
224
20240529RGBtest3/classifer.py
Normal file
@ -0,0 +1,224 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2024/6/4 21:34
|
||||
# @Author : GG
|
||||
# @File : classifer.py
|
||||
# @Software: PyCharm
|
||||
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
class Tomato:
|
||||
def __init__(self):
|
||||
''' 初始化 Tomato 类。'''
|
||||
pass
|
||||
|
||||
def extract_s_l(self, image):
|
||||
'''
|
||||
提取图像的 S 通道(饱和度)和 L 通道(亮度),并将两者相加。
|
||||
:param image: 输入的 BGR 图像
|
||||
:return: S 通道和 L 通道相加的结果
|
||||
'''
|
||||
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
||||
lab = cv2.cvtColor(image, cv2.COLOR_BGR2Lab)
|
||||
s_channel = hsv[:, :, 1]
|
||||
l_channel = lab[:, :, 0]
|
||||
result = cv2.add(s_channel, l_channel)
|
||||
return result
|
||||
|
||||
def find_reflection(self, image, threshold=190):
|
||||
'''
|
||||
通过阈值处理识别图像中的反射区域。
|
||||
:param image: 输入的单通道图像
|
||||
:param threshold: 用于二值化的阈值
|
||||
:return: 二值化后的图像,高于阈值的部分为白色,其余为黑色
|
||||
'''
|
||||
_, reflection = cv2.threshold(image, threshold, 255, cv2.THRESH_BINARY)
|
||||
return reflection
|
||||
|
||||
def otsu_threshold(self, image):
|
||||
'''
|
||||
使用 Otsu 大津法自动计算并应用阈值,进行图像的二值化处理。
|
||||
:param image: 输入的单通道图像
|
||||
:return: 二值化后的图像
|
||||
'''
|
||||
_, binary = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
|
||||
return binary
|
||||
|
||||
def extract_g_r(self, image):
|
||||
'''
|
||||
提取图像中的 G 通道(绿色),放大并减去 R 通道(红色)。
|
||||
:param image: 输入的 BGR 图像
|
||||
:return: G 通道乘以 1.5 后减去 R 通道的结果
|
||||
'''
|
||||
g_channel = image[:, :, 1]
|
||||
r_channel = image[:, :, 2]
|
||||
result = cv2.subtract(cv2.multiply(g_channel, 1.5), r_channel)
|
||||
return result
|
||||
|
||||
def extract_r_b(self, image):
|
||||
'''
|
||||
提取图像中的 R 通道(红色)和 B 通道(蓝色),并进行相减。
|
||||
:param image: 输入的 BGR 图像
|
||||
:return: R 通道减去 B 通道的结果
|
||||
'''
|
||||
r_channel = image[:, :, 2]
|
||||
b_channel = image[:, :, 0]
|
||||
result = cv2.subtract(r_channel, b_channel)
|
||||
return result
|
||||
|
||||
def extract_r_g(self, image):
|
||||
'''
|
||||
提取图像中的 R 通道(红色)和 G 通道(绿色),并进行相减。
|
||||
:param image: 输入的 BGR 图像
|
||||
:return: R 通道减去 G 通道的结果
|
||||
'''
|
||||
r_channel = image[:, :, 2]
|
||||
g_channel = image[:, :, 1]
|
||||
result = cv2.subtract(r_channel, g_channel)
|
||||
return result
|
||||
|
||||
def threshold_segmentation(self, image, threshold, color=255):
|
||||
'''
|
||||
对图像进行阈值分割,高于阈值的部分设置为指定的颜色。
|
||||
:param image: 输入的单通道图像
|
||||
:param threshold: 阈值
|
||||
:param color: 设置的颜色值
|
||||
:return: 分割后的二值化图像
|
||||
'''
|
||||
_, result = cv2.threshold(image, threshold, color, cv2.THRESH_BINARY)
|
||||
return result
|
||||
|
||||
def bitwise_operation(self, image1, image2, operation='and'):
|
||||
'''
|
||||
对两幅图像执行位运算(与或运算)。
|
||||
:param image1: 第一幅图像
|
||||
:param image2: 第二幅图像
|
||||
:param operation: 执行的操作类型('and' 或 'or')
|
||||
:return: 位运算后的结果
|
||||
'''
|
||||
if operation == 'and':
|
||||
result = cv2.bitwise_and(image1, image2)
|
||||
elif operation == 'or':
|
||||
result = cv2.bitwise_or(image1, image2)
|
||||
else:
|
||||
raise ValueError("operation must be 'and' or 'or'")
|
||||
return result
|
||||
|
||||
def largest_connected_component(self, bin_img):
|
||||
'''
|
||||
提取二值图像中的最大连通区域。
|
||||
:param bin_img: 输入的二值图像
|
||||
:return: 只包含最大连通区域的二值图像
|
||||
'''
|
||||
num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(bin_img, connectivity=8)
|
||||
if num_labels <= 1:
|
||||
return np.zeros_like(bin_img)
|
||||
largest_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA])
|
||||
new_bin_img = np.zeros_like(bin_img)
|
||||
new_bin_img[labels == largest_label] = 255
|
||||
return new_bin_img
|
||||
|
||||
def close_operation(self, bin_img, kernel_size=(5, 5)):
|
||||
'''
|
||||
对二值图像进行闭运算,用于消除内部小孔和连接接近的对象。
|
||||
:param bin_img: 输入的二值图像
|
||||
:param kernel_size: 核的大小
|
||||
:return: 进行闭运算后的图像
|
||||
'''
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)
|
||||
closed_img = cv2.morphologyEx(bin_img, cv2.MORPH_CLOSE, kernel)
|
||||
return closed_img
|
||||
|
||||
def open_operation(self, bin_img, kernel_size=(5, 5)):
|
||||
'''
|
||||
对二值图像进行开运算,用于去除小的噪点。
|
||||
:param bin_img: 输入的二值图像
|
||||
:param kernel_size: 核的大小
|
||||
:return: 进行开运算后的图像
|
||||
'''
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)
|
||||
opened_img = cv2.morphologyEx(bin_img, cv2.MORPH_OPEN, kernel)
|
||||
return opened_img
|
||||
|
||||
def draw_tomato_edge(self, original_img, bin_img):
|
||||
'''
|
||||
在原始图像上绘制最大西红柿轮廓的近似多边形。
|
||||
:param original_img: 原始 BGR 图像
|
||||
:param bin_img: 西红柿的二值图像
|
||||
:return: 带有绘制边缘的原始图像和边缘掩码
|
||||
'''
|
||||
bin_img_processed = self.close_operation(bin_img, kernel_size=(15, 15))
|
||||
contours, _ = cv2.findContours(bin_img_processed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
if not contours:
|
||||
return original_img, np.zeros_like(bin_img)
|
||||
max_contour = max(contours, key=cv2.contourArea)
|
||||
epsilon = 0.0006 * cv2.arcLength(max_contour, True)
|
||||
approx = cv2.approxPolyDP(max_contour, epsilon, True)
|
||||
cv2.drawContours(original_img, [approx], -1, (0, 255, 0), 3)
|
||||
mask = np.zeros_like(bin_img)
|
||||
cv2.drawContours(mask, [max_contour], -1, (255), thickness=cv2.FILLED)
|
||||
return original_img, mask
|
||||
|
||||
def draw_tomato_edge_convex_hull(self, original_img, bin_img):
|
||||
'''
|
||||
在原始图像上绘制最大西红柿轮廓的凸包。
|
||||
:param original_img: 原始 BGR 图像
|
||||
:param bin_img: 西红柿的二值图像
|
||||
:return: 带有绘制凸包的原始图像
|
||||
'''
|
||||
bin_img_blurred = cv2.GaussianBlur(bin_img, (5, 5), 0)
|
||||
contours, _ = cv2.findContours(bin_img_blurred, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
if not contours:
|
||||
return original_img
|
||||
max_contour = max(contours, key=cv2.contourArea)
|
||||
hull = cv2.convexHull(max_contour)
|
||||
cv2.drawContours(original_img, [hull], -1, (0, 255, 0), 3)
|
||||
return original_img
|
||||
|
||||
def fill_holes(self, bin_img):
|
||||
'''
|
||||
使用 floodFill 算法填充图像中的孔洞。
|
||||
:param bin_img: 输入的二值图像
|
||||
:return: 填充后的图像
|
||||
'''
|
||||
img_filled = bin_img.copy()
|
||||
height, width = bin_img.shape
|
||||
mask = np.zeros((height + 2, width + 2), np.uint8)
|
||||
cv2.floodFill(img_filled, mask, (0, 0), 255)
|
||||
img_filled_inv = cv2.bitwise_not(img_filled)
|
||||
img_filled = cv2.bitwise_or(bin_img, img_filled_inv)
|
||||
return img_filled
|
||||
|
||||
def bitwise_and_rgb_with_binary(self, rgb_img, bin_img):
|
||||
'''
|
||||
将 RGB 图像与二值图像进行按位与操作,用于将二值区域应用于原始图像。
|
||||
:param rgb_img: 原始 RGB 图像
|
||||
:param bin_img: 二值图像
|
||||
:return: 按位与后的结果图像
|
||||
'''
|
||||
bin_img_3channel = cv2.cvtColor(bin_img, cv2.COLOR_GRAY2BGR)
|
||||
result = cv2.bitwise_and(rgb_img, bin_img_3channel)
|
||||
return result
|
||||
|
||||
def extract_max_connected_area(self, image, lower_hsv, upper_hsv):
|
||||
'''
|
||||
提取图像中满足 HSV 范围条件的最大连通区域,并填充孔洞。
|
||||
:param image: 输入的 BGR 图像
|
||||
:param lower_hsv: HSV 范围的下限
|
||||
:param upper_hsv: HSV 范围的上限
|
||||
:return: 处理后的图像
|
||||
'''
|
||||
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
||||
mask = cv2.inRange(hsv, lower_hsv, upper_hsv)
|
||||
num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(mask, connectivity=8)
|
||||
largest_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA])
|
||||
new_bin_img = np.zeros_like(mask)
|
||||
new_bin_img[labels == largest_label] = 255
|
||||
img_filled = new_bin_img.copy()
|
||||
height, width = new_bin_img.shape
|
||||
mask = np.zeros((height + 2, width + 2), np.uint8)
|
||||
cv2.floodFill(img_filled, mask, (0, 0), 255)
|
||||
img_filled_inv = cv2.bitwise_not(img_filled)
|
||||
img_filled = cv2.bitwise_or(new_bin_img, img_filled_inv)
|
||||
return img_filled
|
||||
125
20240529RGBtest3/main.py
Normal file
125
20240529RGBtest3/main.py
Normal file
@ -0,0 +1,125 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2024/4/20 18:45
|
||||
# @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
|
||||
import logging
|
||||
from utils import create_pipes, receive_rgb_data, send_data, receive_spec_data, analyze_tomato
|
||||
from collections import deque
|
||||
import time
|
||||
import io
|
||||
from PIL import Image
|
||||
import threading
|
||||
import queue
|
||||
|
||||
def process_data(img: any) -> tuple:
|
||||
"""
|
||||
处理指令
|
||||
|
||||
:param cmd: 指令类型
|
||||
:param data: 指令内容
|
||||
:param connected_sock: socket
|
||||
:param detector: 模型
|
||||
:return: 是否处理成功
|
||||
"""
|
||||
# if cmd == 'IM':
|
||||
|
||||
long_axis, short_axis, number_defects, total_pixels, rp = analyze_tomato(img)
|
||||
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',
|
||||
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
|
||||
|
||||
while True:
|
||||
long_axis_list = []
|
||||
short_axis_list = []
|
||||
defect_num_sum = 0
|
||||
total_defect_area_sum = 0
|
||||
rp = None
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
for i in range(5):
|
||||
|
||||
# start_time = time.time()
|
||||
|
||||
|
||||
img_data = receive_rgb_data(rgb_receive)
|
||||
image = Image.open(io.BytesIO(img_data))
|
||||
img = np.array(image)
|
||||
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(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)
|
||||
if i == 1:
|
||||
rp_result = rp
|
||||
|
||||
defect_num_sum += number_defects
|
||||
total_defect_area_sum += total_pixels
|
||||
|
||||
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)
|
||||
print(f'光谱数据接收长度:', len(spec_data))
|
||||
|
||||
|
||||
response = send_data(pipe_send=rgb_send, long_axis=long_axis, short_axis=short_axis,
|
||||
defect_num=defect_num_sum, total_defect_area=total_defect_area_sum, 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 __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)
|
||||
|
||||
|
||||
|
||||
|
||||
79
20240529RGBtest3/picture.ipynb
Normal file
79
20240529RGBtest3/picture.ipynb
Normal file
@ -0,0 +1,79 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "initial_id",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-06-03T08:44:12.688855Z",
|
||||
"start_time": "2024-06-03T08:44:07.661963Z"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"import cv2\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# 读取彩色图像,使用原始字符串处理文件路径\n",
|
||||
"image = cv2.imread(r\"D:\\project\\supermachine--tomato-passion_fruit\\20240529RGBtest3\\data\\bad\\36.bmp\")\n",
|
||||
"\n",
|
||||
"# 将RGB图像转换到HSV颜色空间\n",
|
||||
"hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)\n",
|
||||
"\n",
|
||||
"# 将RGB图像转换到Lab颜色空间\n",
|
||||
"lab_image = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)\n",
|
||||
"\n",
|
||||
"# 提取S分量\n",
|
||||
"s_channel = hsv_image[:,:,1]\n",
|
||||
"\n",
|
||||
"# 提取L分量\n",
|
||||
"l_channel = lab_image[:,:,0]\n",
|
||||
"\n",
|
||||
"# 计算S+L图像\n",
|
||||
"sl_image = cv2.addWeighted(s_channel, 0.5, l_channel, 0.5, 0)\n",
|
||||
"\n",
|
||||
"# 使用Otsu阈值分割\n",
|
||||
"_, otsu_segmentation = cv2.threshold(sl_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)\n",
|
||||
"\n",
|
||||
"# 显示原始图像和分割结果\n",
|
||||
"cv2.imshow(\"Original Image\", image)\n",
|
||||
"cv2.imshow(\"Otsu Segmentation\", otsu_segmentation)\n",
|
||||
"cv2.waitKey(0)\n",
|
||||
"cv2.destroyAllWindows()\n",
|
||||
"#存图\n",
|
||||
"# cv2.imwrite(r\"D:\\project\\supermachine--tomato-passion_fruit\\20240529RGBtest3\\33_otsu.bmp\", otsu_segmentation)\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 5
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": "",
|
||||
"id": "29d27b11f43683db"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
292
20240529RGBtest3/test.py
Normal file
292
20240529RGBtest3/test.py
Normal file
@ -0,0 +1,292 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import os
|
||||
import argparse
|
||||
# from svm import predict_image_array, load_model
|
||||
|
||||
|
||||
|
||||
#提取西红柿,使用S+L的图像
|
||||
def extract_s_l(image_path):
|
||||
image = cv2.imread(image_path)
|
||||
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
||||
lab = cv2.cvtColor(image, cv2.COLOR_BGR2Lab)
|
||||
s_channel = hsv[:,:,1]
|
||||
l_channel = lab[:,:,0]
|
||||
result = cv2.add(s_channel, l_channel)
|
||||
return result
|
||||
|
||||
def find_reflection(image_path, threshold=190):
|
||||
# 读取图像
|
||||
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
|
||||
|
||||
# 应用阈值分割
|
||||
_, reflection = cv2.threshold(image, threshold, 255, cv2.THRESH_BINARY)
|
||||
|
||||
return reflection
|
||||
|
||||
def otsu_threshold(image):
|
||||
|
||||
# 将图像转换为灰度图像
|
||||
# gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
# 使用Otsu阈值分割
|
||||
_, binary = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
|
||||
|
||||
return binary
|
||||
|
||||
# 提取花萼,使用G-R的图像
|
||||
def extract_g_r(image):
|
||||
# image = cv2.imread(image_path)
|
||||
g_channel = image[:,:,1]
|
||||
r_channel = image[:,:,2]
|
||||
result = cv2.subtract(cv2.multiply(g_channel, 1.5), r_channel)
|
||||
return result
|
||||
|
||||
|
||||
#提取西红柿,使用R-B的图像
|
||||
def extract_r_b(image_path):
|
||||
image = cv2.imread(image_path)
|
||||
r_channel = image[:,:,2]
|
||||
b_channel = image[:,:,0]
|
||||
result = cv2.subtract(r_channel, b_channel)
|
||||
return result
|
||||
|
||||
def extract_r_g(image_path):
|
||||
image = cv2.imread(image_path)
|
||||
r_channel = image[:,:,2]
|
||||
g_channel = image[:,:,1]
|
||||
result = cv2.subtract(r_channel, g_channel)
|
||||
return result
|
||||
|
||||
def threshold_segmentation(image, threshold, color=255):
|
||||
_, result = cv2.threshold(image, threshold, color, cv2.THRESH_BINARY)
|
||||
return result
|
||||
|
||||
def bitwise_operation(image1, image2, operation='and'):
|
||||
if operation == 'and':
|
||||
result = cv2.bitwise_and(image1, image2)
|
||||
elif operation == 'or':
|
||||
result = cv2.bitwise_or(image1, image2)
|
||||
else:
|
||||
raise ValueError("operation must be 'and' or 'or'")
|
||||
return result
|
||||
|
||||
def largest_connected_component(bin_img):
|
||||
# 使用connectedComponentsWithStats函数找到连通区域
|
||||
num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(bin_img, connectivity=8)
|
||||
|
||||
# 找到最大的连通区域(除了背景)
|
||||
largest_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA])
|
||||
|
||||
# 创建一个新的二值图像,只显示最大的连通区域
|
||||
new_bin_img = np.zeros_like(bin_img)
|
||||
new_bin_img[labels == largest_label] = 255
|
||||
|
||||
return new_bin_img
|
||||
|
||||
def close_operation(bin_img, kernel_size=(5, 5)):
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)
|
||||
closed_img = cv2.morphologyEx(bin_img, cv2.MORPH_CLOSE, kernel)
|
||||
return closed_img
|
||||
|
||||
def open_operation(bin_img, kernel_size=(5, 5)):
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)
|
||||
opened_img = cv2.morphologyEx(bin_img, cv2.MORPH_OPEN, kernel)
|
||||
return opened_img
|
||||
|
||||
|
||||
def draw_tomato_edge(original_img, bin_img):
|
||||
bin_img_processed = close_operation(bin_img, kernel_size=(15, 15))
|
||||
# cv2.imshow('Close Operation', bin_img_processed)
|
||||
# bin_img_processed = open_operation(bin_img_processed, kernel_size=(19, 19))
|
||||
# cv2.imshow('Open Operation', bin_img_processed)
|
||||
# 现在使用处理后的bin_img_processed查找轮廓
|
||||
contours, _ = cv2.findContours(bin_img_processed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
|
||||
# 如果没有找到轮廓,直接返回原图
|
||||
if not contours:
|
||||
return original_img
|
||||
# 找到最大轮廓
|
||||
max_contour = max(contours, key=cv2.contourArea)
|
||||
# 多边形近似的精度调整
|
||||
epsilon = 0.0006 * cv2.arcLength(max_contour, True) # 可以调整这个值
|
||||
approx = cv2.approxPolyDP(max_contour, epsilon, True)
|
||||
# 绘制轮廓
|
||||
cv2.drawContours(original_img, [approx], -1, (0, 255, 0), 3)
|
||||
mask = np.zeros_like(bin_img)
|
||||
|
||||
# 使用白色填充最大轮廓
|
||||
cv2.drawContours(mask, [max_contour], -1, (255), thickness=cv2.FILLED)
|
||||
|
||||
return original_img, mask
|
||||
|
||||
def draw_tomato_edge_convex_hull(original_img, bin_img):
|
||||
bin_img_blurred = cv2.GaussianBlur(bin_img, (5, 5), 0)
|
||||
contours, _ = cv2.findContours(bin_img_blurred, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
if not contours:
|
||||
return original_img
|
||||
max_contour = max(contours, key=cv2.contourArea)
|
||||
hull = cv2.convexHull(max_contour)
|
||||
cv2.drawContours(original_img, [hull], -1, (0, 255, 0), 3)
|
||||
return original_img
|
||||
|
||||
# 得到完整的西红柿二值图像,除了绿色花萼
|
||||
def fill_holes(bin_img):
|
||||
# 复制 bin_img 到 img_filled
|
||||
img_filled = bin_img.copy()
|
||||
|
||||
# 获取图像的高度和宽度
|
||||
height, width = bin_img.shape
|
||||
|
||||
# 创建一个掩码,比输入图像大两个像素点
|
||||
mask = np.zeros((height + 2, width + 2), np.uint8)
|
||||
|
||||
# 使用 floodFill 函数填充黑色区域
|
||||
cv2.floodFill(img_filled, mask, (0, 0), 255)
|
||||
|
||||
# 反转填充后的图像
|
||||
img_filled_d = cv2.bitwise_not(img_filled)
|
||||
|
||||
# 使用 bitwise_or 操作合并原图像和填充后的图像
|
||||
img_filled = cv2.bitwise_or(bin_img, img_filled)
|
||||
# 裁剪 img_filled 和 img_filled_d 到与 bin_img 相同的大小
|
||||
# img_filled = img_filled[:height, :width]
|
||||
img_filled_d = img_filled_d[:height, :width]
|
||||
|
||||
return img_filled, img_filled_d
|
||||
|
||||
def bitwise_and_rgb_with_binary(rgb_img, bin_img):
|
||||
# 将二值图像转换为三通道图像
|
||||
bin_img_3channel = cv2.cvtColor(bin_img, cv2.COLOR_GRAY2BGR)
|
||||
|
||||
# 使用 bitwise_and 操作合并 RGB 图像和二值图像
|
||||
result = cv2.bitwise_and(rgb_img, bin_img_3channel)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def extract_max_connected_area(image_path, lower_hsv, upper_hsv):
|
||||
# 读取图像
|
||||
image = cv2.imread(image_path)
|
||||
|
||||
# 将图像从BGR转换到HSV
|
||||
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
||||
|
||||
# 使用阈值获取指定区域的二值图像
|
||||
mask = cv2.inRange(hsv, lower_hsv, upper_hsv)
|
||||
|
||||
# 找到二值图像的连通区域
|
||||
num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(mask, connectivity=8)
|
||||
|
||||
# 找到最大的连通区域(除了背景)
|
||||
largest_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA])
|
||||
|
||||
# 创建一个新的二值图像,只显示最大的连通区域
|
||||
new_bin_img = np.zeros_like(mask)
|
||||
new_bin_img[labels == largest_label] = 255
|
||||
|
||||
# 复制 new_bin_img 到 img_filled
|
||||
img_filled = new_bin_img.copy()
|
||||
|
||||
# 获取图像的高度和宽度
|
||||
height, width = new_bin_img.shape
|
||||
|
||||
# 创建一个掩码,比输入图像大两个像素点
|
||||
mask = np.zeros((height + 2, width + 2), np.uint8)
|
||||
|
||||
# 使用 floodFill 函数填充黑色区域
|
||||
cv2.floodFill(img_filled, mask, (0, 0), 255)
|
||||
|
||||
# 反转填充后的图像
|
||||
img_filled_inv = cv2.bitwise_not(img_filled)
|
||||
|
||||
# 使用 bitwise_or 操作合并原图像和填充后的图像
|
||||
img_filled = cv2.bitwise_or(new_bin_img, img_filled_inv)
|
||||
|
||||
return img_filled
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||
parser.add_argument('--dir_path', type=str, default=r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\data\broken',
|
||||
help='the directory path of images')
|
||||
parser.add_argument('--threshold_s_l', type=int, default=180,
|
||||
help='the threshold for s_l')
|
||||
parser.add_argument('--threshold_r_b', type=int, default=15,
|
||||
help='the threshold for r_b')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
for img_file in os.listdir(args.dir_path):
|
||||
if img_file.endswith('.bmp'):
|
||||
img_path = os.path.join(args.dir_path, img_file)
|
||||
s_l = extract_s_l(img_path)
|
||||
otsu_thresholded = otsu_threshold(s_l)
|
||||
img_fore = bitwise_and_rgb_with_binary(cv2.imread(img_path), otsu_thresholded)
|
||||
img_fore_defect = extract_g_r(img_fore)
|
||||
img_fore_defect = threshold_segmentation(img_fore_defect, args.threshold_r_b)
|
||||
# cv2.imshow('img_fore_defect', img_fore_defect)
|
||||
thresholded_s_l = threshold_segmentation(s_l, args.threshold_s_l)
|
||||
new_bin_img = largest_connected_component(thresholded_s_l)
|
||||
# zhongggggg = cv2.bitwise_or(new_bin_img, cv2.imread('defect_mask.bmp', cv2.IMREAD_GRAYSCALE))
|
||||
# cv2.imshow('zhongggggg', zhongggggg)
|
||||
new_otsu_bin_img = largest_connected_component(otsu_thresholded)
|
||||
filled_img, defect = fill_holes(new_bin_img)
|
||||
defect = bitwise_and_rgb_with_binary(cv2.imread(img_path), defect)
|
||||
cv2.imshow('defect', defect)
|
||||
edge, mask = draw_tomato_edge(cv2.imread(img_path), new_bin_img)
|
||||
org_defect = bitwise_and_rgb_with_binary(edge, new_bin_img)
|
||||
fore = bitwise_and_rgb_with_binary(cv2.imread(img_path), mask)
|
||||
fore_g_r_t = threshold_segmentation(extract_g_r(fore), 20)
|
||||
fore_g_r_t_ture = bitwise_and_rgb_with_binary(cv2.imread(img_path), fore_g_r_t)
|
||||
cv2.imwrite('defect_big.bmp', fore_g_r_t_ture)
|
||||
res = cv2.bitwise_or(new_bin_img, fore_g_r_t)
|
||||
white = find_reflection(img_path)
|
||||
|
||||
# SVM预测
|
||||
# 加载模型
|
||||
# model, scaler = load_model('/Users/xs/PycharmProjects/super-tomato/svm_green.joblib')
|
||||
|
||||
# 对图像进行预测
|
||||
# predicted_mask = predict_image_array(image, model, scaler)
|
||||
|
||||
|
||||
|
||||
cv2.imshow('white', white)
|
||||
|
||||
cv2.imshow('fore', fore)
|
||||
cv2.imshow('fore_g_r_t', fore_g_r_t)
|
||||
cv2.imshow('mask', mask)
|
||||
print('mask', mask.shape)
|
||||
print('filled', filled_img.shape)
|
||||
print('largest', new_bin_img.shape)
|
||||
print('rp', org_defect.shape)
|
||||
cv2.imshow('res', res)
|
||||
|
||||
|
||||
|
||||
# 显示原始图像
|
||||
original_img = cv2.imread(img_path)
|
||||
cv2.imshow('Original', original_img)
|
||||
cv2.imshow('thresholded_s_l', thresholded_s_l)
|
||||
cv2.imshow('Largest Connected Component', new_bin_img)
|
||||
cv2.imshow('Filled', filled_img)
|
||||
cv2.imshow('Defect', defect)
|
||||
cv2.imshow('Org_defect', org_defect)
|
||||
cv2.imshow('otsu_thresholded', new_otsu_bin_img)
|
||||
|
||||
|
||||
#显示轮廓
|
||||
cv2.imshow('Edge', edge)
|
||||
|
||||
# 等待用户按下任意键
|
||||
cv2.waitKey(0)
|
||||
|
||||
# 关闭所有窗口
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
280
20240529RGBtest3/utils.py
Normal file
280
20240529RGBtest3/utils.py
Normal file
@ -0,0 +1,280 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2024/4/20 18:24
|
||||
# @Author : TG
|
||||
# @File : utils.py
|
||||
# @Software: PyCharm
|
||||
|
||||
import time
|
||||
import logging
|
||||
import numpy as np
|
||||
import shutil
|
||||
import cv2
|
||||
import os
|
||||
from scipy.ndimage.measurements import label, find_objects
|
||||
import win32pipe
|
||||
import win32file
|
||||
import io
|
||||
from PIL import Image
|
||||
import select
|
||||
import msvcrt
|
||||
from classifer import Tomato
|
||||
|
||||
def receive_rgb_data(pipe):
|
||||
try:
|
||||
# 读取图片数据
|
||||
len_img = win32file.ReadFile(pipe, 4, None)
|
||||
data_size = int.from_bytes(len_img[1], byteorder='big')
|
||||
result, img_data = win32file.ReadFile(pipe, data_size, None)
|
||||
return img_data
|
||||
except Exception as e:
|
||||
print(f"数据接收失败,错误原因: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def receive_spec_data(pipe):
|
||||
try:
|
||||
# 读取图片数据长度
|
||||
len_spec = win32file.ReadFile(pipe, 4, None)
|
||||
if len_spec is None:
|
||||
# 未能读取到数据长度,返回"0"
|
||||
return "0"
|
||||
data_size = int.from_bytes(len_spec[1], byteorder='big')
|
||||
if data_size == 0:
|
||||
# 接收到空数据,返回"0"
|
||||
return "0"
|
||||
|
||||
# 读取图片数据
|
||||
result, spec_data = win32file.ReadFile(pipe, data_size, None)
|
||||
return spec_data
|
||||
except Exception as e:
|
||||
print(f"数据接收失败,错误原因: {e}")
|
||||
return '0'
|
||||
|
||||
def create_pipes(rgb_receive_name, rgb_send_name, spec_receive_name):
|
||||
while True:
|
||||
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
|
||||
|
||||
except Exception as e:
|
||||
print(f"管道创建连接失败,失败原因: {e}")
|
||||
print("等待5秒后重试...")
|
||||
time.sleep(5)
|
||||
continue
|
||||
|
||||
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)
|
||||
|
||||
# 将 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')
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
def mkdir_if_not_exist(dir_name, is_delete=False):
|
||||
"""
|
||||
创建文件夹
|
||||
:param dir_name: 文件夹
|
||||
:param is_delete: 是否删除
|
||||
:return: 是否成功
|
||||
"""
|
||||
try:
|
||||
if is_delete:
|
||||
if os.path.exists(dir_name):
|
||||
shutil.rmtree(dir_name)
|
||||
print('[Info] 文件夹 "%s" 存在, 删除文件夹.' % dir_name)
|
||||
|
||||
if not os.path.exists(dir_name):
|
||||
os.makedirs(dir_name)
|
||||
print('[Info] 文件夹 "%s" 不存在, 创建文件夹.' % dir_name)
|
||||
return True
|
||||
except Exception as e:
|
||||
print('[Exception] %s' % e)
|
||||
return False
|
||||
|
||||
def create_file(file_name):
|
||||
"""
|
||||
创建文件
|
||||
:param file_name: 文件名
|
||||
:return: None
|
||||
"""
|
||||
if os.path.exists(file_name):
|
||||
print("文件存在:%s" % file_name)
|
||||
return False
|
||||
# os.remove(file_name) # 删除已有文件
|
||||
if not os.path.exists(file_name):
|
||||
print("文件不存在,创建文件:%s" % file_name)
|
||||
open(file_name, 'a').close()
|
||||
return True
|
||||
|
||||
|
||||
class Logger(object):
|
||||
def __init__(self, is_to_file=False, path=None):
|
||||
self.is_to_file = is_to_file
|
||||
if path is None:
|
||||
path = "tomato.log"
|
||||
self.path = path
|
||||
create_file(path)
|
||||
|
||||
def log(self, content):
|
||||
if self.is_to_file:
|
||||
with open(self.path, "a") as f:
|
||||
print(time.strftime("[%Y-%m-%d_%H-%M-%S]:"), file=f)
|
||||
print(content, file=f)
|
||||
else:
|
||||
print(content)
|
||||
|
||||
|
||||
|
||||
|
||||
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_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 = get_tomato_dimensions(mask)
|
||||
# 获取缺陷信息
|
||||
number_defects, total_pixels = get_defect_info(new_bin_img)
|
||||
# 将处理后的图像转换为 RGB 格式
|
||||
rp = cv2.cvtColor(org_defect, cv2.COLOR_BGR2RGB)
|
||||
return long_axis, short_axis, number_defects, total_pixels, rp
|
||||
64
20240529RGBtest3/xs/dimensionality_reduction.py
Normal file
64
20240529RGBtest3/xs/dimensionality_reduction.py
Normal file
@ -0,0 +1,64 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
|
||||
from sklearn.svm import SVR
|
||||
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
|
||||
|
||||
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]
|
||||
return reshaped_data[:, selected_bands]
|
||||
|
||||
def split_data(X, y, test_size=0.20, random_state=1):
|
||||
"""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, 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 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 = prepare_data(all_spectral_data)
|
||||
X_train, X_test, y_train, y_test = split_data(X, sweetness_acidity)
|
||||
|
||||
models = {
|
||||
"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)
|
||||
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}")
|
||||
print_predictions(y_test, y_pred, model_name)
|
||||
print("\n" + "-"*50 + "\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
89
20240529RGBtest3/xs/hsv.py
Normal file
89
20240529RGBtest3/xs/hsv.py
Normal file
@ -0,0 +1,89 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import os
|
||||
|
||||
def create_mask(hsv_image, hue_value, hue_delta, value_target, value_delta):
|
||||
# 创建H通道阈值掩码
|
||||
lower_hue = np.array([hue_value - hue_delta, 0, 0])
|
||||
upper_hue = np.array([hue_value + hue_delta, 255, 255])
|
||||
hue_mask = cv2.inRange(hsv_image, lower_hue, upper_hue)
|
||||
|
||||
# 创建V通道排除中心值的掩码
|
||||
lower_value_1 = np.array([0, 0, 0])
|
||||
upper_value_1 = np.array([180, 255, value_target - value_delta])
|
||||
lower_value_2 = np.array([0, 0, value_target + value_delta])
|
||||
upper_value_2 = np.array([180, 255, 255])
|
||||
|
||||
value_mask_1 = cv2.inRange(hsv_image, lower_value_1, upper_value_1)
|
||||
value_mask_1 = cv2.bitwise_not(value_mask_1)
|
||||
cv2.imshow('value_mask_1', value_mask_1)
|
||||
value_mask_2 = cv2.inRange(hsv_image, lower_value_2, upper_value_2)
|
||||
cv2.imshow('value_mask_2', value_mask_2)
|
||||
value_mask = cv2.bitwise_and(value_mask_1, value_mask_2)
|
||||
cv2.imshow('value_mask', value_mask)
|
||||
# 等待用户按下任意键
|
||||
cv2.waitKey(0)
|
||||
|
||||
# 关闭所有窗口
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
# 合并H通道和V通道掩码
|
||||
return cv2.bitwise_and(hue_mask, value_mask)
|
||||
|
||||
def apply_morphology(mask):
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
|
||||
return cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
|
||||
|
||||
def find_largest_component(mask):
|
||||
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, 4, cv2.CV_32S)
|
||||
if num_labels < 2:
|
||||
return None # No significant components found
|
||||
max_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA]) # Skip background
|
||||
return (labels == max_label).astype(np.uint8) * 255
|
||||
|
||||
def process_image(image_path, hue_value=37, hue_delta=10, value_target=25, value_delta=10):
|
||||
image = cv2.imread(image_path)
|
||||
if image is None:
|
||||
print(f"Error: Image at {image_path} could not be read.")
|
||||
return None
|
||||
|
||||
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
||||
combined_mask = create_mask(hsv_image, hue_value, hue_delta, value_target, value_delta)
|
||||
combined_mask = apply_morphology(combined_mask)
|
||||
max_mask = find_largest_component(combined_mask)
|
||||
cv2.imshow('max_mask', max_mask)
|
||||
# 等待用户按下任意键
|
||||
cv2.waitKey(0)
|
||||
# 关闭所有窗口
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
if max_mask is None:
|
||||
print(f"No significant components found in {image_path}.")
|
||||
return None
|
||||
|
||||
result_image = cv2.bitwise_and(image, image, mask=max_mask)
|
||||
result_image[max_mask == 0] = [255, 255, 255] # Set background to white
|
||||
return result_image
|
||||
|
||||
def save_image(image, output_path):
|
||||
cv2.imwrite(output_path, image)
|
||||
|
||||
def process_images_in_folder(input_folder, output_folder):
|
||||
if not os.path.exists(output_folder):
|
||||
os.makedirs(output_folder)
|
||||
|
||||
for filename in os.listdir(input_folder):
|
||||
if filename.lower().endswith(".bmp"):
|
||||
image_path = os.path.join(input_folder, filename)
|
||||
result_image = process_image(image_path)
|
||||
if result_image is not None:
|
||||
output_path = os.path.join(output_folder, filename)
|
||||
save_image(result_image, output_path)
|
||||
print(f"Processed and saved {filename} to {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' # 替换为你的输出文件夹路径
|
||||
process_images_in_folder(input_folder, output_folder)
|
||||
71
20240529RGBtest3/xs/mean.py
Normal file
71
20240529RGBtest3/xs/mean.py
Normal file
@ -0,0 +1,71 @@
|
||||
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 for each fruit across all pixels."""
|
||||
return np.mean(data, axis=(1, 2))
|
||||
|
||||
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=42):
|
||||
"""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 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 = prepare_data(all_spectral_data)
|
||||
plot_spectra(X, sweetness_acidity) # 绘制光谱曲线并添加标注
|
||||
X_train, X_test, y_train, y_test = split_data(X, sweetness_acidity)
|
||||
rf_model = train_model(X_train, y_train)
|
||||
mse, y_pred = evaluate_model(rf_model, X_test, y_test)
|
||||
|
||||
print("Transformed data shape:", X_train.shape)
|
||||
print("Mean Squared Error on the test set:", mse)
|
||||
print_predictions(y_test, y_pred)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
70
20240529RGBtest3/xs/rgb.py
Normal file
70
20240529RGBtest3/xs/rgb.py
Normal file
@ -0,0 +1,70 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def dual_threshold_and_max_component(image_path, hue_value=37, hue_delta=10, value_target=30, value_delta=10):
|
||||
# 读取图像
|
||||
image = cv2.imread(image_path)
|
||||
|
||||
# 检查图像是否读取成功
|
||||
if image is None:
|
||||
print("Error: Image could not be read.")
|
||||
return
|
||||
|
||||
# 将图像从BGR转换到HSV色彩空间
|
||||
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
||||
|
||||
# 创建H通道阈值掩码
|
||||
lower_hue = np.array([hue_value - hue_delta, 0, 0])
|
||||
upper_hue = np.array([hue_value + hue_delta, 255, 255])
|
||||
hue_mask = cv2.inRange(hsv_image, lower_hue, upper_hue)
|
||||
|
||||
# 创建V通道排除中心值的掩码
|
||||
lower_value_1 = np.array([0, 0, 0])
|
||||
upper_value_1 = np.array([180, 255, value_target - value_delta])
|
||||
lower_value_2 = np.array([0, 0, value_target + value_delta])
|
||||
upper_value_2 = np.array([180, 255, 255])
|
||||
|
||||
value_mask_1 = cv2.inRange(hsv_image, lower_value_1, upper_value_1)
|
||||
value_mask_2 = cv2.inRange(hsv_image, lower_value_2, upper_value_2)
|
||||
value_mask = cv2.bitwise_or(value_mask_1, value_mask_2)
|
||||
|
||||
# 合并H通道和V通道掩码
|
||||
combined_mask = cv2.bitwise_and(hue_mask, value_mask)
|
||||
|
||||
# 形态学操作 - 开运算,去除小的粘连
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
|
||||
combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_OPEN, kernel)
|
||||
|
||||
# 连通域分析
|
||||
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(combined_mask, 4, cv2.CV_32S)
|
||||
|
||||
# 找出最大的连通区域(除了背景)
|
||||
max_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA]) # 跳过背景
|
||||
max_mask = (labels == max_label).astype(np.uint8) * 255
|
||||
|
||||
# 使用掩码生成结果图像
|
||||
result_image = cv2.bitwise_and(image, image, mask=max_mask)
|
||||
# 设置背景为白色
|
||||
result_image[max_mask == 0] = [255, 255, 255]
|
||||
|
||||
# 将结果图像从BGR转换到RGB以便正确显示
|
||||
result_image_rgb = cv2.cvtColor(result_image, cv2.COLOR_BGR2RGB)
|
||||
|
||||
# 使用matplotlib显示原始图像和结果图像
|
||||
plt.figure(figsize=(10, 5))
|
||||
plt.subplot(1, 2, 1)
|
||||
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
||||
plt.title('Original Image')
|
||||
plt.axis('off')
|
||||
|
||||
plt.subplot(1, 2, 2)
|
||||
plt.imshow(result_image_rgb)
|
||||
plt.title('Largest Connected Component on White Background')
|
||||
plt.axis('off')
|
||||
|
||||
plt.show()
|
||||
|
||||
# 使用函数
|
||||
image_path = r'D:\project\supermachine--tomato-passion_fruit\20240529RGBtest3\data\passion_fruit_img\50.bmp' # 替换为你的图片路径
|
||||
dual_threshold_and_max_component(image_path)
|
||||
70
20240529RGBtest3/xs/spec_read.py
Normal file
70
20240529RGBtest3/xs/spec_read.py
Normal file
@ -0,0 +1,70 @@
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
# Specify the directory containing the HDR and RAW files
|
||||
directory = '/Users/xs/PycharmProjects/super-tomato/baixiangguo/光谱数据3030/'
|
||||
|
||||
# Initialize a list to hold all the spectral data arrays
|
||||
all_spectral_data = []
|
||||
|
||||
# Loop through each data set (assuming there are 40 datasets)
|
||||
for i in range(1, 101):
|
||||
hdr_path = os.path.join(directory, f'{i}.HDR')
|
||||
raw_path = os.path.join(directory, f'{i}')
|
||||
|
||||
# Read data
|
||||
spectral_data = read_spectral_data(hdr_path, raw_path)
|
||||
all_spectral_data.append(spectral_data)
|
||||
|
||||
# Stack all data into a single numpy array
|
||||
all_spectral_data = np.stack(all_spectral_data)
|
||||
print(all_spectral_data.shape) # This should print (40, 30, 30, 224)
|
||||
@ -11,7 +11,6 @@
|
||||
"start_time": "2024-03-18T12:58:35.489144Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import cv2\n",
|
||||
@ -19,73 +18,12 @@
|
||||
"import numpy as np\n",
|
||||
"import cv2 as cv\n",
|
||||
"import os"
|
||||
]
|
||||
],
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"<class 'str'>\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(39911424,)\n",
|
||||
"(87, 2048, 224)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"[[[1686. 1654. 1654. ... 1654. 1622. 1654.]\n",
|
||||
" [1689. 1673. 1673. ... 1689. 1689. 1673.]\n",
|
||||
" [1673. 1657. 1657. ... 1673. 1753. 1609.]\n",
|
||||
" ...\n",
|
||||
" [1609. 1689. 1721. ... 1657. 1705. 1577.]\n",
|
||||
" [1718. 1702. 1654. ... 1574. 1638. 1686.]\n",
|
||||
" [1686. 1670. 1686. ... 1590. 1686. 1670.]]\n",
|
||||
"\n",
|
||||
" [[1654. 1670. 1718. ... 1686. 1654. 1734.]\n",
|
||||
" [1721. 1657. 1641. ... 1689. 1657. 1721.]\n",
|
||||
" [1641. 1625. 1705. ... 1705. 1689. 1609.]\n",
|
||||
" ...\n",
|
||||
" [1625. 1673. 1689. ... 1673. 1673. 1641.]\n",
|
||||
" [1686. 1622. 1654. ... 1686. 1654. 1606.]\n",
|
||||
" [1734. 1654. 1670. ... 1510. 1654. 1654.]]\n",
|
||||
"\n",
|
||||
" [[1718. 1702. 1670. ... 1622. 1670. 1686.]\n",
|
||||
" [1657. 1641. 1641. ... 1705. 1689. 1657.]\n",
|
||||
" [1673. 1673. 1689. ... 1673. 1625. 1657.]\n",
|
||||
" ...\n",
|
||||
" [1625. 1673. 1705. ... 1625. 1609. 1625.]\n",
|
||||
" [1702. 1686. 1654. ... 1638. 1670. 1654.]\n",
|
||||
" [1638. 1702. 1686. ... 1670. 1702. 1638.]]\n",
|
||||
"\n",
|
||||
" ...\n",
|
||||
"\n",
|
||||
" [[1638. 1606. 1686. ... 1654. 1670. 1638.]\n",
|
||||
" [1721. 1673. 1673. ... 1689. 1641. 1625.]\n",
|
||||
" [1641. 1641. 1673. ... 1657. 1641. 1625.]\n",
|
||||
" ...\n",
|
||||
" [1625. 1609. 1689. ... 1657. 1657. 1673.]\n",
|
||||
" [1638. 1606. 1702. ... 1622. 1622. 1654.]\n",
|
||||
" [1574. 1654. 1622. ... 1718. 1670. 1622.]]\n",
|
||||
"\n",
|
||||
" [[1590. 1686. 1638. ... 1654. 1654. 1638.]\n",
|
||||
" [1641. 1657. 1609. ... 1673. 1657. 1641.]\n",
|
||||
" [1721. 1657. 1641. ... 1657. 1673. 1577.]\n",
|
||||
" ...\n",
|
||||
" [1657. 1673. 1641. ... 1593. 1609. 1609.]\n",
|
||||
" [1622. 1670. 1670. ... 1686. 1734. 1622.]\n",
|
||||
" [1670. 1590. 1670. ... 1638. 1590. 1638.]]\n",
|
||||
"\n",
|
||||
" [[1654. 1654. 1638. ... 1606. 1606. 1558.]\n",
|
||||
" [1689. 1657. 1689. ... 1657. 1625. 1673.]\n",
|
||||
" [1657. 1561. 1657. ... 1657. 1673. 1609.]\n",
|
||||
" ...\n",
|
||||
" [1657. 1625. 1689. ... 1657. 1609. 1625.]\n",
|
||||
" [1638. 1654. 1654. ... 1622. 1606. 1590.]\n",
|
||||
" [1590. 1686. 1606. ... 1574. 1686. 1686.]]]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"##合成真彩色图像\n",
|
||||
"#读取raw文件\n",
|
||||
@ -126,21 +64,11 @@
|
||||
"start_time": "2024-03-18T13:06:04.869067Z"
|
||||
}
|
||||
},
|
||||
"id": "3443037608cc60f6"
|
||||
"id": "3443037608cc60f6",
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"<class 'str'>\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(50462720,)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"##合成真彩色图像\n",
|
||||
"#读取raw文件\n",
|
||||
@ -192,97 +120,12 @@
|
||||
}
|
||||
},
|
||||
"id": "283f370b2401221b",
|
||||
"execution_count": 5
|
||||
"execution_count": 5,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"(928, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(848, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(902, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(795, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(783, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(708, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(747, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(630, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(709, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(699, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(796, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(865, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(791, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(723, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(797, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(760, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(701, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(770, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(637, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(729, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(762, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(732, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(839, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(760, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(711, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(736, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(758, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(772, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(744, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(775, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(821, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(775, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(820, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(772, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(772, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(747, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(770, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(645, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n",
|
||||
"(756, 1200, 3)\n",
|
||||
"<class 'numpy.ndarray'>\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"##循环合成真彩色图像\n",
|
||||
"# 指定文件夹路径\n",
|
||||
@ -357,27 +200,28 @@
|
||||
"start_time": "2023-11-24T02:50:24.958389400Z"
|
||||
}
|
||||
},
|
||||
"id": "15a3889f7bf1917f"
|
||||
"id": "15a3889f7bf1917f",
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "17b929b3de3fa2ed"
|
||||
"id": "17b929b3de3fa2ed",
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "e00c8e929ee57b60"
|
||||
"id": "e00c8e929ee57b60",
|
||||
"outputs": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user