热帧是否被转为RGB?TIFF热帧温度值提取正确性问询
问题
我有一批TIFF帧,想通过计算温度值来确定呼吸速率,但不确定代码是否正确提取了温度值——目前输出的信号看起来像是随机值,怀疑代码自动把帧转成了RGB或8位灰度图,导致原始16位温度数据丢失。
原始代码
import tifffile as tiff import cv2 import numpy as np import os import argparse import csv import pandas as pd import matplotlib.pyplot as plt # Construct argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-v", "--video", required=True, help="Path to input directory containing TIFF files") args = vars(ap.parse_args()) input_dir = args["video"] print("Input directory: " + input_dir) def select_roi(image): """ Allows user to select a region of interest (ROI) from the 16-bit image. """ # Normalize 16-bit data for display without altering its original values normalized_image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) color_map = cv2.applyColorMap(normalized_image, cv2.COLORMAP_JET) cv2.imshow("Select Nose", color_map) bbox = cv2.selectROI("Select Nose", color_map, fromCenter=False, showCrosshair=True) cv2.destroyAllWindows() # Print ROI coordinates x, y, w, h = bbox print(f"ROI's boundary is x1={x}, y1={y}, x2={x+w}, y2={y+h}") return bbox # Open CSV file for writing results csv_file = "nose_pixel_values.csv" with open(csv_file, mode='w', newline='') as file: writer = csv.writer(file) writer.writerow(["Frame", "Average Pixel Value"]) # CSV header # Initialize ROI coordinates x, y, w, h = None, None, None, None # Loop through all TIFF files in the specified directory for tiff_file in sorted(os.listdir(input_dir)): if tiff_file.endswith(".tiff"): file_path = os.path.join(input_dir, tiff_file) with tiff.TiffFile(file_path) as tif: gray16_frames = tif.asarray() print(f"Processing '{tiff_file}' with {len(gray16_frames)} frames.") # Get ROI from the first frame of the first TIFF file only if x is None: first_frame = gray16_frames[0] bbox = select_roi(first_frame) x, y, w, h = bbox for i, frame in enumerate(gray16_frames): # Extract the ROI based on the selected bbox roi = frame[y:y+h, x:x+w] # Calculate the average pixel value in the ROI (16-bit) avg_pixel_value = np.mean(roi) print(f"Frame {i}: Average pixel value : {avg_pixel_value}") print(f"Frame {i}: shape : {frame.shape}, data type : {frame.dtype}, min: {frame.min()}, max: {frame.max()}") # Write the result to the CSV file with open(csv_file, mode='a', newline='') as file: writer = csv.writer(file) writer.writerow([i, avg_pixel_value]) print(f"Finished processing all files.")
问题分析
你的代码并未丢失16位原始数据(tifffile.asarray()默认会保留uint16格式),但输出看起来像随机值的核心原因是:
- 每个TIFF文件内的帧索引都从0开始,导致CSV中帧索引重复,序列完全混乱
- 频繁打开/关闭CSV文件的操作可能导致数据写入不连续,进一步加剧"随机"假象
- 缺少像素值到实际温度的校准转换(如果预期输出是温度值而非原始像素值)
修正后的代码
import tifffile as tiff import cv2 import numpy as np import os import argparse import pandas as pd import matplotlib.pyplot as plt # 构造参数解析器 ap = argparse.ArgumentParser() ap.add_argument("-v", "--video", required=True, help="输入TIFF文件所在目录路径") args = vars(ap.parse_args()) input_dir = args["video"] print(f"输入目录: {input_dir}") def select_roi(image): """从16位图像中选择感兴趣区域(ROI)""" # 仅为显示做归一化,不修改原始16位数据 normalized_image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) color_map = cv2.applyColorMap(normalized_image, cv2.COLORMAP_JET) cv2.imshow("选择鼻子区域", color_map) bbox = cv2.selectROI("选择鼻子区域", color_map, fromCenter=False, showCrosshair=True) cv2.destroyAllWindows() x, y, w, h = bbox print(f"ROI边界: x1={x}, y1={y}, x2={x+w}, y2={y+h}") return bbox # 初始化全局帧计数器和结果缓存列表 total_frame_idx = 0 results = [] # 初始化ROI坐标 x, y, w, h = None, None, None, None # 遍历目录下所有TIFF文件 for tiff_file in sorted(os.listdir(input_dir)): if tiff_file.endswith(".tiff"): file_path = os.path.join(input_dir, tiff_file) # 读取原始16位TIFF帧 with tiff.TiffFile(file_path) as tif: gray16_frames = tif.asarray() print(f"处理文件: {tiff_file}, 帧数量: {len(gray16_frames)}") # 仅从第一个TIFF文件的第一帧选择ROI if x is None: first_frame = gray16_frames[0] bbox = select_roi(first_frame) x, y, w, h = bbox # 处理当前文件的每帧 for frame in gray16_frames: # 提取ROI,确保使用原始16位数据 roi = frame[y:y+h, x:x+w] # 计算ROI平均像素值,保留高精度 avg_pixel_value = np.mean(roi, dtype=np.float64) print(f"全局帧索引: {total_frame_idx}, 平均像素值: {avg_pixel_value}") print(f"帧属性: 形状={frame.shape}, 数据类型={frame.dtype}, 最小值={frame.min()}, 最大值={frame.max()}") # 缓存结果,避免频繁IO results.append([total_frame_idx, avg_pixel_value]) total_frame_idx += 1 # 批量写入CSV csv_file = "nose_pixel_values.csv" df = pd.DataFrame(results, columns=["Frame", "Average Pixel Value"]) df.to_csv(csv_file, index=False) print(f"处理完成,结果已保存至 {csv_file}") # 绘制温度变化曲线,方便与预期输出对比 plt.figure(figsize=(10,6)) plt.plot(df["Frame"], df["Average Pixel Value"], label="ROI平均像素值") plt.xlabel("帧索引") plt.ylabel("平均像素值(对应温度)") plt.title("呼吸相关温度变化曲线") plt.legend() plt.savefig("temperature_curve.png") plt.show()
关键改进点
- 全局帧索引:用
total_frame_idx替代局部索引,保证所有TIFF文件的帧序列连贯,彻底解决索引重复导致的"随机值"问题 - 批量IO操作:用列表缓存所有结果,最后通过Pandas一次性写入CSV,提升效率并避免数据写入异常
- 保留数据精度:计算均值时指定
np.float64,确保16位原始数据的精度不丢失 - 可视化验证:新增曲线绘制功能,直接生成变化趋势图,方便和预期输出对比
额外建议
如果你的预期输出是实际温度值而非原始像素值,需要添加设备校准转换:
# 示例:根据设备校准公式转换为温度(请替换为你的设备参数) calibration_a = 0.1 # 斜率 calibration_b = 20 # 截距 df["Temperature"] = df["Average Pixel Value"] * calibration_a + calibration_b
内容的提问来源于stack exchange,提问作者Kingshook
相关产品推荐
相关产品推荐

