在深度学习训练当中,遇到有些图在不同平台上看到的方向不一样,会导致出错,这些图一般都是携带方向信息的。例如:我在训练yolo过程中遇到一些图,图片方向是在windows显示是正方向,opencv 读取的图片宽高也是我在屏幕中看到的正方向,但是实际上图片携带了方向信息,导致宽高读错,处理标签时发生了错误,因此训练不佳。使用pil库可以读出来真正的方向信息,记录一下问题解决方法:
fromPILimportImage,ExifTagsimportnumpyasnpdefget_orientation_pil(image_path):""" 使用PIL获取图片的EXIF方向信息 参数: image_path: 图片路径 返回: orientation: 方向值 (1-8) """try:img=Image.open(image_path)exif=img._getexif()ifexifisnotNone:# 查找方向标签 (EXIF标签274)fortag,valueinexif.items():# ExifTags.TAGS是一个字典,将数值标签映射到字符串标签ifExifTags.TAGS.get(tag)=='Orientation':returnvalueexcept(AttributeError,KeyError,IndexError):# 图片可能没有EXIF信息passreturn1# 如果没有方向信息,默认为1(正常方向)defcorrect_image_orientation_pil(image_path,output_path=None,save_rotated=True):""" 使用PIL校正图片方向 参数: image_path: 输入图片路径 output_path: 输出图片路径(如果为None则不保存) save_rotated: 是否保存旋转后的图片 返回: img_rotated: 旋转校正后的PIL Image对象 """# 获取方向信息orientation=get_orientation_pil(image_path)print(f"原始方向标记:{orientation}")# 打开图片img=Image.open(image_path)# 根据方向标记进行旋转iforientation==3:# 旋转180度print("执行:旋转180度")img_rotated=img.transpose(Image.Transpose.ROTATE_180)eliforientation==6:# 顺时针90度(相机逆时针旋转90度拍摄)# 需要逆时针旋转90度来校正print("执行:逆时针旋转90度(校正顺时针90度)")img_rotated=img.transpose(Image.Transpose.ROTATE_270)# 逆时针90度eliforientation==8:# 逆时针90度(相机顺时针旋转90度拍摄)# 需要顺时针旋转90度来校正print("执行:顺时针旋转90度(校正逆时针90度)")img_rotated=img.transpose(Image.Transpose.ROTATE_90)# 顺时针90度else:# 方向1或其他:正常方向,无需旋转print("方向正常,无需旋转")img_rotated=img# 如果需要保存ifsave_rotatedandoutput_path:# 创建新的EXIF信息,移除方向标记exif_data=img.info.get('exif')ifexif_data:# 移除方向标记(避免再次被旋转)# 这里需要处理EXIF二进制数据,较为复杂# 简单的方法是重新保存而不保留EXIF的方向标记img_rotated.save(output_path,quality=95)print(f"已保存校正后的图片到:{output_path}")else:img_rotated.save(output_path,quality=95)print(f"已保存校正后的图片到:{output_path}")returnimg_rotateddefcorrect_and_display_all_orientations():""" 展示所有方向标记的校正效果 """# 模拟不同方向标记的图片(实际应用中需要准备测试图片)orientations=[1,3,6,8]fororientationinorientations:print(f"\n=== 测试方向标记:{orientation}===")# 这里只是演示,实际需要准备相应方向的图片print(f"方向标记{orientation}对应的旋转操作:")iforientation==1:print(" - 无旋转 (正常)")eliforientation==3:print(" - 旋转 180 度")print(" - PIL操作: img.transpose(Image.ROTATE_180)")eliforientation==6:print(" - 逆时针旋转 90 度")print(" - PIL操作: img.transpose(Image.ROTATE_270)")eliforientation==8:print(" - 顺时针旋转 90 度")print(" - PIL操作: img.transpose(Image.ROTATE_90)")defbatch_correct_orientation(input_folder,output_folder,extensions=None):""" 批量校正文件夹中所有图片的方向 参数: input_folder: 输入文件夹路径 output_folder: 输出文件夹路径 extensions: 要处理的图片扩展名列表 """importosifextensionsisNone:extensions=['.jpg','.jpeg','.png','.tiff','.bmp']# 创建输出文件夹os.makedirs(output_folder,exist_ok=True)corrected_count=0total_count=0forfilenameinos.listdir(input_folder):# 检查文件扩展名ifany(filename.lower().endswith(ext)forextinextensions):input_path=os.path.join(input_folder,filename)output_path=os.path.join(output_folder,filename)total_count+=1try:# 获取方向orientation=get_orientation_pil(input_path)iforientationin[3,6,8]:# 需要校正corrected_img=correct_image_orientation_pil(input_path,output_path,save_rotated=True)corrected_count+=1print(f"✓ 已校正:{filename}(方向:{orientation})")else:# 方向正常,直接复制img=Image.open(input_path)img.save(output_path)print(f" 正常方向:{filename}(方向:{orientation})")exceptExceptionase:print(f"✗ 处理失败:{filename}-{str(e)}")print(f"\n批量处理完成!")print(f"总共处理:{total_count}个文件")print(f"校正了:{corrected_count}个文件")# 使用示例if__name__=="__main__":# 示例1: 校正单个图片input_image="path/to/your/image.jpg"output_image="path/to/your/image_corrected.jpg"corrected_img=correct_image_orientation_pil(input_image,output_image,save_rotated=True)# 显示图片信息print(f"\n校正后的图片信息:")print(f" 尺寸:{corrected_img.size}")print(f" 模式:{corrected_img.mode}")print(f" 格式:{corrected_img.format}")# 示例2: 批量处理# batch_correct_orientation("input_folder", "output_folder")# 示例3: 查看方向标记说明print("\n"+"="*50)print("方向标记说明:")print("="*50)print("1: 正常 (无旋转)")print("3: 旋转 180 度")print("6: 顺时针 90 度 (相机逆时针旋转90度拍摄)")print("8: 逆时针 90 度 (相机顺时针旋转90度拍摄)")在处理数据之前,用上面代码跑一跑,可以将图片转到应该的方向上,避免标签处理失误的情况。原来遇到过一张图,图片方向是看着没问题,然后使用opencv测试也没问题,但是一在部署的平台上(使用了其他图像库)测试结果就不一样了。搞了好久,发现是图片方向问题。