TypeError: in user code: TypeError: outer_factory.<locals>.inner_factory.<locals>.tf__combine_features() takes 1 positional argument but 2 were given,下面是这个出现这个问题的原代码,你帮我修改一下import os
import re
import glob
import tensorflow as tf
import numpy as np
from tqdm import tqdm
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.model_selection import train_test_split
import imageio
import sys
from skimage.transform import resize
import traceback
from tensorflow.keras import layers, models, Input, Model
from tensorflow.keras.optimizers import Adam
from pathlib import Path
from tensorflow.keras.losses import MeanSquaredError
from tensorflow.keras.metrics import MeanAbsoluteError
from skimage import measure, morphology, filters
# =============== 配置参数=====================================
BASE_DIR = "F:/2025.7.2wavelengthtiff" # 根目录路径
START_WAVELENGTH = 788.55500 # 起始波长
END_WAVELENGTH = 788.55600 # 结束波长
STEP = 0.00005 # 波长步长
BATCH_SIZE = 8 # 批处理大小
IMAGE_SIZE = (256, 256) # 图像尺寸
TARGET_CHANNELS = 1 # 目标通道数 - 使用灰度图像
TEST_SIZE = 0.2 # 测试集比例
RANDOM_SEED = 42 # 随机种子
MODEL_SAVE_PATH = Path.home() / "Documents" / "wavelength_model.keras" # 修改为.keras格式
# ================================================================
# 设置中文字体支持
try:
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
mpl.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
print("已设置中文字体支持")
except:
print("警告:无法设置中文字体,图表可能无法正确显示中文")
def generate_folder_names(start, end, step):
"""生成波长文件夹名称列表"""
num_folders = int((end - start) / step) + 1
folder_names = []
for i in range(num_folders):
wavelength = start + i * step
folder_name = f"{wavelength:.5f}"
folder_names.append(folder_name)
return folder_names
def find_best_match_file(folder_path, target_wavelength):
"""在文件夹中找到波长最接近目标值的TIFF文件"""
tiff_files = glob.glob(os.path.join(folder_path, "*.tiff")) + glob.glob(os.path.join(folder_path, "*.tif"))
if not tiff_files:
return None
best_match = None
min_diff = float('inf')
for file_path in tiff_files:
filename = os.path.basename(file_path)
match = re.search(r'\s*([\d.]+)_', filename)
if not match:
continue
try:
file_wavelength = float(match.group(1))
diff = abs(file_wavelength - target_wavelength)
if diff < min_diff:
min_diff = diff
best_match = file_path
except ValueError:
continue
return best_match
def extract_shape_features(binary_image):
"""从二值化图像中提取形状和边界特征"""
features = np.zeros(6, dtype=np.float32) # 初始化特征向量
try:
contours = measure.find_contours(binary_image, 0.5)
if not contours:
return features
main_contour = max(contours, key=len)
contour_length = len(main_contour)
label_image = morphology.label(binary_image)
region = measure.regionprops(label_image)[0]
contour_area = region.area
hull = morphology.convex_hull_image(label_image)
hull_area = np.sum(hull)
solidity = region.solidity
eccentricity = region.eccentricity
orientation = region.orientation
features[0] = contour_length / 1000 # 归一化
features[1] = contour_area / 1000 # 归一化
features[2] = solidity
features[3] = eccentricity
features[4] = orientation
features[5] = hull_area / 1000 # 凸包面积
except Exception as e:
print(f"形状特征提取错误: {e}")
traceback.print_exc()
return features
def load_and_preprocess_image(file_path):
"""加载并预处理TIFF图像"""
try:
image = imageio.imread(file_path)
if image.dtype == np.uint16:
image = image.astype(np.float32) / 65535.0
elif image.dtype == np.uint8:
image = image.astype(np.float32) / 255.0
else:
image = image.astype(np.float32)
if np.max(image) > 1.0:
image = image / np.max(image)
if len(image.shape) == 3 and image.shape[2] > 1:
image = 0.299 * image[:, :, 0] + 0.587 * image[:, :, 1] + 0.114 * image[:, :, 2]
image = np.expand_dims(image, axis=-1)
image = resize(image, (IMAGE_SIZE[0], IMAGE_SIZE[1]), anti_aliasing=True)
blurred = filters.gaussian(image[..., 0], sigma=1.0)
thresh = filters.threshold_otsu(blurred)
binary = blurred > thresh * 0.8
return image, binary
except Exception as e:
print(f"图像加载失败: {e}, 使用空白图像代替")
return np.zeros((IMAGE_SIZE[0], IMAGE_SIZE[1], 1), dtype=np.float32), np.zeros((IMAGE_SIZE[0], IMAGE_SIZE[1]), dtype=np.bool)
def create_tiff_dataset(file_paths):
"""从文件路径列表创建TensorFlow数据集"""
dataset = tf.data.Dataset.from_tensor_slices(file_paths)
def load_wrapper(file_path):
file_path_str = file_path.numpy().decode('utf-8')
image, binary = load_and_preprocess_image(file_path_str)
features = extract_shape_features(binary)
return image, features
def tf_load_wrapper(file_path):
result = tf.py_function(
func=load_wrapper,
inp=[file_path],
Tout=(tf.float32, tf.float32)
)
image = result[0]
features = result[1]
image.set_shape((IMAGE_SIZE[0], IMAGE_SIZE[1], 1)) # 单通道
features.set_shape((6,)) # 6个形状特征
return image, features
dataset = dataset.map(tf_load_wrapper, num_parallel_calls=tf.data.experimental.AUTOTUNE)
dataset = dataset.batch(BATCH_SIZE).prefetch(tf.data.experimental.AUTOTUNE)
return dataset
def load_and_prepare_data():
"""加载所有数据并准备训练/测试集"""
folder_names = generate_folder_names(START_WAVELENGTH, END_WAVELENGTH, STEP)
print(f"\n生成的文件夹数量: {len(folder_names)}")
print(f"起始文件夹: {folder_names[0]}")
print(f"结束文件夹: {folder_names[-1]}")
valid_files = []
wavelengths = []
print("\n扫描文件夹并匹配文件...")
for folder_name in tqdm(folder_names, desc="处理文件夹"):
folder_path = os.path.join(BASE_DIR, folder_name)
if not os.path.isdir(folder_path):
continue
try:
target_wavelength = float(folder_name)
file_path = find_best_match_file(folder_path, target_wavelength)
if file_path:
valid_files.append(file_path)
wavelengths.append(target_wavelength)
except ValueError:
continue
print(f"\n找到的有效文件: {len(valid_files)}/{len(folder_names)}")
if not valid_files:
raise ValueError("未找到任何有效文件,请检查路径和文件夹名称")
wavelengths = np.array(wavelengths)
min_wavelength = np.min(wavelengths)
max_wavelength = np.max(wavelengths)
wavelength_range = max_wavelength - min_wavelength
wavelengths_normalized = (wavelengths - min_wavelength) / wavelength_range
print(f"波长范围: {min_wavelength:.6f} 到 {max_wavelength:.6f}, 范围大小: {wavelength_range:.6f}")
train_files, test_files, train_wavelengths, test_wavelengths = train_test_split(
valid_files, wavelengths_normalized, test_size=TEST_SIZE, random_state=RANDOM_SEED
)
print(f"训练集大小: {len(train_files)}")
print(f"测试集大小: {len(test_files)}")
train_dataset = create_tiff_dataset(train_files)
test_dataset = create_tiff_dataset(test_files)
train_labels = tf.data.Dataset.from_tensor_slices(train_wavelengths)
test_labels = tf.data.Dataset.from_tensor_slices(test_wavelengths)
# 修复后的 combine_features 函数
def combine_features(data):
"""将图像特征和标签组合成模型需要的格式"""
image_features, label = data
image, shape_features = image_features
return (image, shape_features), label
train_dataset_unet = tf.data.Dataset.zip((train_dataset, train_labels)).map(
combine_features,
num_parallel_calls=tf.data.experimental.AUTOTUNE
)
test_dataset_unet = tf.data.Dataset.zip((test_dataset, test_labels)).map(
combine_features,
num_parallel_calls=tf.data.experimental.AUTOTUNE
)
train_dataset_cnn_dense = tf.data.Dataset.zip((train_dataset.map(lambda x: x[0]), train_labels))
test_dataset_cnn_dense = tf.data.Dataset.zip((test_dataset.map(lambda x: x[0]), test_labels))
return train_dataset_unet, test_dataset_unet, train_dataset_cnn_dense, test_dataset_cnn_dense, valid_files, min_wavelength, wavelength_range
def build_unet_model(input_shape, shape_feature_size):
"""构建 U-Net 模型,同时接受图像输入和形状特征输入"""
# 图像输入
image_input = Input(shape=input_shape, name='image_input')
# Encoder
conv1 = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(image_input)
conv1 = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
pool1 = layers.MaxPooling2D(pool_size=(2, 2))(conv1)
conv2 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(pool1)
conv2 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
pool2 = layers.MaxPooling2D(pool_size=(2, 2))(conv2)
conv3 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(pool2)
conv3 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)
pool3 = layers.MaxPooling2D(pool_size=(2, 2))(conv3)
# Bottleneck
conv4 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(pool3)
conv4 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(conv4)
drop4 = layers.Dropout(0.5)(conv4)
# Decoder
up5 = layers.Conv2D(128, (2, 2), activation='relu', padding='same')(layers.UpSampling2D(size=(2, 2))(drop4))
merge5 = layers.Concatenate()([conv3, up5])
conv5 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(merge5)
conv5 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(conv5)
up6 = layers.Conv2D(64, (2, 2), activation='relu', padding='same')(layers.UpSampling2D(size=(2, 2))(conv5))
merge6 = layers.Concatenate()([conv2, up6])
conv6 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(merge6)
conv6 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(conv6)
up7 = layers.Conv2D(32, (2, 2), activation='relu', padding='same')(layers.UpSampling2D(size=(2, 2))(conv6))
merge7 = layers.Concatenate()([conv1, up7])
conv7 = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(merge7)
conv7 = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(conv7)
# 形状特征输入
shape_input = Input(shape=(shape_feature_size,), name='shape_input')
shape_dense = layers.Dense(128, activation='relu')(shape_input)
shape_dense = layers.Dense(64, activation='relu')(shape_dense)
# 合并图像特征和形状特征
flat = layers.GlobalAveragePooling2D()(conv7)
combined = layers.Concatenate()([flat, shape_dense])
# 输出层
outputs = layers.Dense(1, activation='linear')(combined)
model = Model(inputs=[image_input, shape_input], outputs=outputs)
model.compile(optimizer=Adam(learning_rate=1e-4), loss='mean_squared_error', metrics=['mae'])
return model
def build_dense_model(input_shape):
"""构建简单的全连接网络"""
inputs = Input(shape=input_shape)
x = layers.Flatten()(inputs)
x = layers.Dense(128, activation='relu')(x)
x = layers.Dense(64, activation='relu')(x)
outputs = layers.Dense(1, activation='linear')(x)
model = Model(inputs=[inputs], outputs=[outputs])
model.compile(optimizer=Adam(learning_rate=1e-4), loss='mean_squared_error', metrics=['mae'])
return model
def build_cnn_model(input_shape):
"""构建传统的 CNN 模型"""
inputs = Input(shape=input_shape)
x = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(inputs)
x = layers.MaxPooling2D((2, 2))(x)
x = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2))(x)
x = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2))(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(x)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(256, activation='relu')(x)
outputs = layers.Dense(1, activation='linear')(x)
model = Model(inputs=[inputs], outputs=[outputs])
model.compile(optimizer=Adam(learning_rate=1e-4), loss='mean_squared_error', metrics=['mae'])
return model
def train_models(train_dataset_unet, test_dataset_unet, train_dataset_cnn_dense, test_dataset_cnn_dense, input_shape, shape_feature_size, wavelength_range):
"""训练多个模型"""
unet_model = build_unet_model(input_shape, shape_feature_size)
dense_model = build_dense_model(input_shape)
cnn_model = build_cnn_model(input_shape)
unet_model.summary()
dense_model.summary()
cnn_model.summary()
callbacks = [
tf.keras.callbacks.EarlyStopping(patience=30, restore_best_weights=True, monitor='val_loss', min_delta=1e-6),
tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=10, min_lr=1e-7)
]
unet_history = unet_model.fit(train_dataset_unet, epochs=300, validation_data=test_dataset_unet, callbacks=callbacks, verbose=2)
dense_history = dense_model.fit(train_dataset_cnn_dense, epochs=300, validation_data=test_dataset_cnn_dense, callbacks=callbacks, verbose=2)
cnn_history = cnn_model.fit(train_dataset_cnn_dense, epochs=300, validation_data=test_dataset_cnn_dense, callbacks=callbacks, verbose=2)
return unet_model, dense_model, cnn_model
def predict_with_voting(models, test_image_path, min_wavelength, wavelength_range):
"""使用多个模型进行预测,并通过投票机制决定最终结果"""
image, binary = load_and_preprocess_image(test_image_path)
image = np.expand_dims(image, axis=0)
shape_features = extract_shape_features(binary)
shape_features = np.expand_dims(shape_features, axis=0)
predictions = []
for model in models:
if model.name == 'unet_model':
predicted_normalized = model.predict([image, shape_features], verbose=0)[0][0]
else:
predicted_normalized = model.predict(image, verbose=0)[0][0]
predicted_wavelength = predicted_normalized * wavelength_range + min_wavelength
predictions.append(predicted_wavelength)
# 使用投票机制(例如取平均值)
final_prediction = np.mean(predictions)
print(f"最终预测波长: {final_prediction:.8f} 纳米")
return final_prediction
def main():
"""主函数"""
print(f"TensorFlow 版本: {tf.__version__}")
try:
train_dataset_unet, test_dataset_unet, train_dataset_cnn_dense, test_dataset_cnn_dense, all_files, min_wavelength, wavelength_range = load_and_prepare_data()
print(f"最小波长: {min_wavelength:.6f}, 波长范围: {wavelength_range:.6f}")
except Exception as e:
print(f"数据加载失败: {str(e)}")
traceback.print_exc()
return
print("\n开始训练模型...")
try:
unet_model, dense_model, cnn_model = train_models(train_dataset_unet, test_dataset_unet, train_dataset_cnn_dense, test_dataset_cnn_dense, (IMAGE_SIZE[0], IMAGE_SIZE[1], 1), 6, wavelength_range)
except Exception as e:
print(f"模型训练失败: {str(e)}")
traceback.print_exc()
return
print("\n从测试集中随机选择一张图片进行预测...")
try:
for (images, features), labels in test_dataset_unet.take(1):
if images.shape[0] > 0:
test_image = images[0].numpy()
test_features = features[0].numpy()
labels_np = labels.numpy()
if labels_np.ndim == 0:
true_wavelength_normalized = labels_np.item()
else:
true_wavelength_normalized = labels_np[0]
true_wavelength = true_wavelength_normalized * wavelength_range + min_wavelength
test_image_path = "f:/phD/代码/test_image.tiff"
imageio.imwrite(test_image_path, (test_image[..., 0] * 255).astype(np.uint8))
predicted_wavelength = predict_with_voting([unet_model, dense_model, cnn_model], test_image_path, min_wavelength, wavelength_range)
print(f"真实波长: {true_wavelength:.6f} 纳米")
print(f"预测波长: {predicted_wavelength:.6f} 纳米")
print(f"绝对误差: {abs(predicted_wavelength - true_wavelength):.8f} 纳米")
print(f"相对误差: {abs(predicted_wavelength - true_wavelength) / wavelength_range * 100:.4f}%")
else:
print("错误:测试批次中没有样本")
except Exception as e:
print(f"测试失败: {str(e)}")
traceback.print_exc()
print("\n您可以使用自己的图片进行测试:")
model = tf.keras.models.load_model(MODEL_SAVE_PATH)
image_path = input("请输入您要测试的图片路径(例如:'test_image.tiff'): ")
predicted = predict_with_voting([unet_model, dense_model, cnn_model], image_path, min_wavelength, wavelength_range)
print(f"预测波长: {predicted:.6f} 纳米")
print("\n程序执行完成。")
if __name__ == "__main__":
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
try:
from skimage import filters, measure, morphology
except ImportError:
print("安装必要的库...")
import subprocess
subprocess.run([sys.executable, "-m", "pip", "install", "scikit-image", "imageio"])
from skimage import filters, measure, morphology
main()
最新发布