87 lines
3.3 KiB
Python
87 lines
3.3 KiB
Python
|
|
import matplotlib
|
|||
|
|
import matplotlib.pyplot as plt
|
|||
|
|
matplotlib.use('TkAgg')
|
|||
|
|
from plantcv import plantcv as pcv
|
|||
|
|
import numpy as np
|
|||
|
|
import cv2
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
def process_images_background(full_bil_path, mask, outdir='None', debug="None"):
|
|||
|
|
# 初始化参数
|
|||
|
|
class options:
|
|||
|
|
def __init__(self):
|
|||
|
|
self.image = full_bil_path # 输入的光谱图像路径
|
|||
|
|
self.debug = debug # 设置调试模式:'plot' 或 'print'
|
|||
|
|
self.writeimg = False # 是否保存图片
|
|||
|
|
self.result = outdir # 输出结果文件路径
|
|||
|
|
self.outdir = outdir # 输出文件夹路径
|
|||
|
|
|
|||
|
|
args = options()
|
|||
|
|
|
|||
|
|
# 设置 PlantCV 的全局参数
|
|||
|
|
pcv.params.debug = args.debug
|
|||
|
|
pcv.params.dpi = 100 # 设置 DPI
|
|||
|
|
pcv.params.text_size = 1 # 文本大小
|
|||
|
|
pcv.params.text_thickness = 1 # 文本粗细
|
|||
|
|
|
|||
|
|
# 读取光谱图像(ENVI 格式)
|
|||
|
|
spectral_array = pcv.readimage(filename=args.image, mode='envi')
|
|||
|
|
bath_100 = spectral_array.array_data[:, :, 100]
|
|||
|
|
bath_over = pcv.threshold.binary(gray_img=bath_100, threshold=5500, object_type='light')
|
|||
|
|
|
|||
|
|
# 将PIL 16位掩膜转换为8位二值化格式
|
|||
|
|
# 如果mask是非零值则设置为255(塑料区域),否则为0(背景)
|
|||
|
|
mask_array = np.array(mask) if not isinstance(mask, np.ndarray) else mask
|
|||
|
|
b_thresh_unit8 = ((mask_array > 0).astype(np.uint8)) * 255
|
|||
|
|
|
|||
|
|
# 填充小的孔洞,并反转掩膜
|
|||
|
|
b_fill = pcv.fill(bin_img=b_thresh_unit8, size=250)
|
|||
|
|
b_fill_inverted = pcv.invert(b_fill)
|
|||
|
|
|
|||
|
|
# 创建形态统计和光谱统计掩膜
|
|||
|
|
dilate_img = pcv.dilate(gray_img=b_fill_inverted, ksize=3, i=4)
|
|||
|
|
bath_erode = pcv.erode(gray_img=bath_over, ksize=3, i=4)
|
|||
|
|
|
|||
|
|
# 塑料掩膜的反转和非黑色背景的掩膜相乘
|
|||
|
|
dilate_img = dilate_img * bath_erode / 255
|
|||
|
|
dilate_img = pcv.fill(bin_img=dilate_img, size=10000)
|
|||
|
|
|
|||
|
|
# 使用cv2.connectedComponents代替pcv.create_labels,避免污染plantcv outputs
|
|||
|
|
num1, labeled_spectral_mask = cv2.connectedComponents(dilate_img.astype(np.uint8))
|
|||
|
|
|
|||
|
|
# plt.figure(figsize=(10, 8))
|
|||
|
|
# plt.imshow(dilate_img, cmap='nipy_spectral')
|
|||
|
|
# plt.colorbar(label='Object Label')
|
|||
|
|
# plt.title(f'Labeled Spectral Mask - {num1} objects detected')
|
|||
|
|
# plt.xlabel('X coordinate')
|
|||
|
|
# plt.ylabel('Y coordinate')
|
|||
|
|
# plt.show()
|
|||
|
|
print(f"Number of objects (second mask): {num1 - 1}") # -1 because first label is background
|
|||
|
|
|
|||
|
|
# 直接计算每个对象的面积并找到最大面积的对象
|
|||
|
|
max_area = 0
|
|||
|
|
max_label = 0
|
|||
|
|
|
|||
|
|
# 遍历所有标签(从1开始,0是背景)
|
|||
|
|
for label in range(1, num1):
|
|||
|
|
# 创建当前标签的掩膜
|
|||
|
|
obj_mask = labeled_spectral_mask == label
|
|||
|
|
# 计算面积
|
|||
|
|
area = np.sum(obj_mask)
|
|||
|
|
if area > max_area:
|
|||
|
|
max_area = area
|
|||
|
|
max_label = label
|
|||
|
|
|
|||
|
|
# 提取最大面积对象的光谱
|
|||
|
|
if max_label > 0:
|
|||
|
|
max_obj_mask = labeled_spectral_mask == max_label
|
|||
|
|
# 获取最大对象在所有波段的光谱值
|
|||
|
|
spectral_values = spectral_array.array_data[max_obj_mask, :]
|
|||
|
|
# 计算平均光谱
|
|||
|
|
mean_spectrum = np.mean(spectral_values, axis=0)
|
|||
|
|
# 返回最大面积对象的平均光谱
|
|||
|
|
return mean_spectrum/10000
|
|||
|
|
else:
|
|||
|
|
# 如果没有找到有效背景对象,返回全零光谱
|
|||
|
|
return np.zeros(spectral_array.array_data.shape[-1]) / 10000
|