批量处理图像计算天顶角温度均值代码执行过慢,求优化方案
哇,1分30秒处理一张图确实有点拖后腿了,咱们来一步步把速度拉上来!你的代码里有几个核心性能瓶颈,我帮你拆解并给出具体的优化方案:
核心问题分析
你的代码慢主要来自三个地方:Python嵌套循环处理像素(几十万次循环效率极低)、重复读取Excel文件、以及不必要的数组拼接和DataFrame合并操作。下面是针对性的优化:
1. 用NumPy向量化替代嵌套循环
Python的for循环在处理几十万像素时效率极低,我们可以用NumPy的向量化操作一次性处理所有像素,这能把速度提升几个数量级:
预先生成坐标与天顶角映射
提前创建整个图像的坐标网格,一次性计算所有像素到中心的距离和对应的天顶角,完全去掉i和j的嵌套循环:
# 预先生成图像的像素坐标网格(对应480行640列) i, j = np.meshgrid(np.arange(480), np.arange(640), indexing='ij') # 计算所有像素到中心(235, 332)的距离 distances = np.sqrt((332 - j)**2 + (235 - i)**2) # 天顶角计算:直接用距离线性映射,不用匹配theta数组(原代码的theta匹配完全冗余) # 当距离<200时,天顶角=距离*90/200;否则设为120 zenith_map = np.where(distances < 200, np.round(distances * 90 / 200, 6), 120)
向量化温度转换
直接对整个灰度图应用温度公式,不用逐个像素计算:
# 温度转换参数(提前定义,不用每次循环重复计算) Tmax, Tmin = 25, -10 Zmax, Zmin = 255, 0 m = (Tmax - Tmin) / (Zmax - Zmin) c = -10 # 一次性计算所有像素的温度,再处理距离>=200的像素 grey = cv.cvtColor(image_data[r], cv.COLOR_BGR2GRAY) Tem = m * grey + c Tem[distances >= 200] = 255
2. 只读取一次Excel掩码文件
原代码在每个图像循环里都重复读取contour.xlsx,这会反复打开文件、加载数据,耗时极多。把这一步提到循环外面,只做一次:
# 提前读取掩码数据,仅执行一次! df_con = pd.read_excel('contour.xlsx') # 预先生成有效像素的掩码数组(pxl_new <255的位置为True) valid_mask = df_con['pxl_new'].values < 255
3. 简化DataFrame操作,用掩码直接过滤
原代码里的多次merge操作完全没必要,直接用预先生成的掩码过滤有效像素,再筛选天顶角范围:
# 把图像数据展平,用掩码提取有效像素 flattened_zenith = zenith_map.flatten() flattened_Tem = Tem.flatten() # 提取有效像素的天顶角和温度 valid_zenith = flattened_zenith[valid_mask] valid_Tem = flattened_Tem[valid_mask] # 筛选65-85度的天顶角,计算平均温度 target_mask = (valid_zenith >= 65) & (valid_zenith <= 85) mean_temp = np.mean(valid_Tem[target_mask]) T_hot = np.append(T_hot, mean_temp)
完整优化后的代码
import glob import os import cv2 as cv import numpy as np import pandas as pd from tqdm import tqdm # ---------------------- 预处理:仅执行一次的操作 ---------------------- # 读取所有图像 files = glob.glob("Images/*.jpg") files.sort(key=os.path.getmtime, reverse=True) image_data = np.array([cv.imread(img) for img in files]) # 预先生成像素坐标网格和距离矩阵(针对480*640的图像) i, j = np.meshgrid(np.arange(480), np.arange(640), indexing='ij') distances = np.sqrt((332 - j)**2 + (235 - i)**2) # 预先生成天顶角映射 zenith_map = np.where(distances < 200, np.round(distances * 90 / 200, 6), 120) # 温度转换参数 Tmax, Tmin = 25, -10 Zmax, Zmin = 255, 0 m = (Tmax - Tmin) / (Zmax - Zmin) c = -10 # 读取掩码数据(仅一次) df_con = pd.read_excel('contour.xlsx') valid_mask = df_con['pxl_new'].values < 255 # ---------------------- 批量处理图像 ---------------------- T_hot = [] # 用列表替代np.append,效率更高 for img in tqdm(image_data): # RGB转灰度图 grey = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 向量化计算温度 Tem = m * grey + c Tem[distances >= 200] = 255 # 提取有效像素并计算目标范围的平均温度 flattened_Tem = Tem.flatten() flattened_zenith = zenith_map.flatten() valid_Tem = flattened_Tem[valid_mask] valid_zenith = flattened_zenith[valid_mask] target_mask = (valid_zenith >= 65) & (valid_zenith <= 85) mean_temp = np.mean(valid_Tem[target_mask]) T_hot.append(mean_temp) # 转成numpy数组(如果需要) T_hot = np.array(T_hot)
额外优化建议
- 如果图像数量极大(17000张),可以考虑用多进程/多线程并行处理(比如
multiprocessing模块或者joblib),把图像分成多个批次同时处理。 - 用列表
T_hot.append()替代np.append(),因为列表的append操作是O(1)的,而np.append每次都会重新分配数组内存。 - 如果你用的是OpenCV 4.x,确保
cv.imread读取的图像格式是最优的,或者可以考虑用PIL读取图像,有时候速度会更快。
这些优化应该能把单张图的处理时间从1分30秒压缩到几秒甚至更短,24张图的处理时间会大幅降低!
内容的提问来源于stack exchange,提问作者hrpandey
相关产品推荐
相关产品推荐

