Python中拆分DataFrame列内多列表并生成目标结构DataFrame及图像边界框标注方案问询
嘿,我来帮你搞定这三个需求,全部用pandas和常用工具实现,步骤清晰易懂:
首先先明确下假设的原始DataFrame结构(方便对应你的数据):
| img_name | bbox_label |
|---|---|
| 001 | [[[0.0,0.0,1024.0,1024.0], [595.97,601.39,776.93,817.03]], ['Effusion', 'Effusion']] |
| 002 | [[[0.0,0.0,1024.0,1024.0], [395.97,351.39,866.93,917.03]], ['Mass', 'any disease']] |
需求2:生成结构化的
img_name/class/xmin/ymin/xmax/ymax DataFrame 这是最常用的结构化格式,用explode完全可以实现,步骤如下:
- 先从嵌套列里拆分出边界框列表和标签列表:
import pandas as pd # 假设你的原始DataFrame叫df df['bboxes'] = df['bbox_label'].apply(lambda x: x[0]) # 提取所有边界框 df['labels'] = df['bbox_label'].apply(lambda x: x[1]) # 提取对应疾病标签
- 同时
explode边界框和标签列,确保它们一一对应:
# explode后每一行对应一个边界框+标签,ignore_index重置索引 df_exploded = df.explode(['bboxes', 'labels'], ignore_index=True)
- 把嵌套的边界框拆分成单独的坐标列:
# 将bboxes的列表拆分成xmin/ymin/xmax/ymax四个列 df_exploded[['xmin', 'ymin', 'xmax', 'ymax']] = pd.DataFrame( df_exploded['bboxes'].tolist(), index=df_exploded.index )
- 整理最终的结构化DataFrame:
final_df = df_exploded[['img_name', 'labels', 'xmin', 'ymin', 'xmax', 'ymax']].rename( columns={'labels': 'class'} )
最终输出就和你给出的示例结构完全一致啦!
需求1:为每种疾病生成对应新列
如果要把每种疾病作为单独的列,值是对应图像的边界框列表,我们可以基于上面的final_df来转换:
# 先按图像名称和疾病分组,把同一图像同一疾病的边界框合并成列表 grouped = final_df.groupby(['img_name', 'class'])['bboxes'].apply(list).reset_index() # 转成宽表,每个疾病对应一列 wide_df = grouped.pivot(index='img_name', columns='class', values='bboxes').reset_index() # 给空值填充空列表(可选) wide_df = wide_df.fillna(value=pd.Series([[]], index=wide_df.columns))
这样每个疾病列的值就是对应图像的所有边界框列表,比如Effusion列里会是[[0.0,0.0,1024.0,1024.0], [595.97,601.39,776.93,817.03]]这样的结构。
需求3:遍历行标注边界框到图像上
用OpenCV就可以轻松实现,步骤如下:
import cv2 import os # 替换成你的图像存储路径 img_dir = "path/to/your/image/directory" # 遍历每个唯一的图像名称 for img_name in final_df['img_name'].unique(): # 构建图像路径(根据你的图像后缀调整,比如jpg/png) img_path = os.path.join(img_dir, f"{img_name}.png") img = cv2.imread(img_path) if img is None: print(f"警告:无法读取图像 {img_name},跳过") continue # 获取当前图像的所有标注信息 img_annotations = final_df[final_df['img_name'] == img_name] # 遍历每个标注画框 for _, row in img_annotations.iterrows(): # 把浮点坐标转成整数(OpenCV需要整数坐标) xmin, ymin = int(row['xmin']), int(row['ymin']) xmax, ymax = int(row['xmax']), int(row['ymax']) label = row['class'] # 画绿色矩形框,厚度2 cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2) # 在框上方添加标签文本 cv2.putText( img, label, (xmin, ymin-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2 ) # 保存标注后的图像,或者直接显示 save_path = os.path.join(img_dir, f"annotated_{img_name}.png") cv2.imwrite(save_path, img) # 如果需要实时显示图像,取消下面注释 # cv2.imshow(f"Annotated: {img_name}", img) # cv2.waitKey(0) # cv2.destroyAllWindows()
内容的提问来源于stack exchange,提问作者Engr Ali
相关产品推荐
相关产品推荐

