侧边栏壁纸
博主头像
钱学超博主等级

火星人,1万小时法则的忠实拥趸。技术宅,象棋和羽毛球爱好者,马拉松PB成绩:4小时零8分。坚持认为算法是计算机的灵魂。喜欢解决问题,喜欢手工,喜欢与朋友们聊天喝酒吹牛X。

  • 累计撰写 83 篇文章
  • 累计创建 464 个标签
  • 累计收到 88 条评论
标签搜索

目 录CONTENT

文章目录

逆天大坑,为啥网上的资料这么少呢,记录一下我辛苦的半个月时间

钱学超
2023-12-27 / 0 评论 / 0 点赞 / 353 阅读 / 1,982 字 / 正在检测是否收录...
  1. 之前突发奇想做个机器学习的项目,当然是自己的产品,也不急,于是慢慢搞吧。
  2. 准备了一大堆资料,架构分析了半天,最终屈服于经验,因为之前用的基本都是tf,所以这次,还是用tensorflow吧。
  3. 标注当然还是大名鼎鼎的labelme,但是由于犯懒,我自己只是做了大概50张标注。
  4. 剩下的资料,让别人用手机拍照片,标注再一起打包发给我。简单看了下,也没啥问题。
  5. 然后就是按部就班的进行数据清洗,数据整理,训练前的各种准备工作。
  6. 关键步骤就是训练,tf图像分割,使用的是deeplabev3plus,这里得说下,之前自建了一个模型,训练完了之后发现效果不行,基本上就相当于没有吧。
  7. 这个deeplabv3都已经不错了,plus版本更牛,我基本没有怎么进行改动,拿过来直接使用就好了。
  8. 但是居然发现了一个逆天大坑,不训练之前,直接使用的是pascal_voc的数据集,训练已经完成,我试验了一下小男孩骑自行车的图片,效果是蛮不错的。
  9. 但是我自己进行了训练之后,发现,训练完的模型,变成了一个弱智。丫居然啥也不会了,训练之前,pascal_voc数据集有21个类别,我训练的类别比较少,只有5个,训练完了之后,不仅我这5个不行,完全识别不了,之前人家21个类别,也搞不定了。
  10. 于是反思,到底是哪里出错了。
  11. deeplabv3的模型,肯定是没有问题的,训练也最终精简为最简单的方案了,fit还能出啥问题吗,过拟合我也忍了,但是它是完全的弱智啊,一点儿都不对。
  12. 于是做了个测试,把数据集中的所有的原始图像、mask、预测图像,在一起展示出来,想找找规律,看看预测出来的到底是个什么鬼。
  13. 不曾想,居然发现数据集中,有一大半的图像和mask对不上!!!
  14. mask居然旋转了90度!我反复查看了代码,所有的图像处理和mask的处理,全都是同步进行的,没有任何区别的。
  15. 关键问题是,还有一半的图像跟mask是对的上的,没有问题。
  16. 所以到底是哪里出的错?想着数据标注出现了问题,在电脑上把两批数据全都打开,查看,导入labelme,没有任何问题。
  17. 那所以肯定是图像处理的阶段出的问题,于是在数据集创建的时候大改特改,基本上把之前的代码全都改了一遍。
  18. 甚至推翻重新写了好多函数。当然,感觉这样做,也更合理了。可是问题依然没有找到。
  19. dataset的创建,是有一个map函数的,这个函数里边的内容,是没有办法进行debug的,而且也不能使用很多tf以外的函数,比如tf对象Tensor的numpy()方法,就是不能用。
  20. 简单说,就是把文件读取过来的内容,转化为dataset的过程,在这个过程中,最开始的时候,以及最终的时候,打印日志,查看图像的size,有些宽高对不上,但是是图片啊,不是mask,图像可是没有做任何处理的。
  21. 处理过程,也是在最后进行了一次resize,重写了好几次这个resize函数,各种情况全都进行了单元测试。确认resize方法没有问题。
  22. 那么,原始图像为什么会有问题呢?图像文件—>tfrecords—>dataset这个过程中,dataset没有问题,那么,查看tfrecords这里,有没有问题呢?
  23. 奇怪的是,看来看去没有任何问题,因为tfrecords读取图像的时候,就是原始图像读取进来,直接二进制塞进流里,动都没动过,咋会出问题呢?
  24. 百度了半天,基本无解,当然,现在看来,是方向错了。
  25. 补充一下,甚至想过是标注完毕之后,对图像进行了旋转,但是太多了,不可能全都进行一次这个处理,也太费时间了。检查了半天,之前我自己做标注的50张图里边,也有几张图有类似的情况。
  26. 尼玛,那么肯定是土本身的问题了。我都想把它翻个底儿看看到底啥做的。
  27. 出海看了看,有人说tf对exif的支持不太好,2019年的帖子。我想,是不是有可能是这个问题呢?于是翻出原始图片来看,确实有问题的那些图片,Orientation是6,没问题的图片,Orientation是1.
  28. 所以,这个到底是什么含义?查了半天资料,发现手机拍摄的照片,原始照片原始显示当然没有问题,但是不符合人类的使用习惯。
  29. 举例说明,即便是你横屏拍了一张照片,当你竖着拿起手机来查看的时候,看到的照片,依然是照片中的人物头部是向上的。这就是手机中的陀螺仪在起作用。
  30. 拍摄照片的一瞬间,它给照片记录了一下你当时手机的放置状态,不过做了一下转化,就是在原始的状态下,怎样进行旋转,才能达到最佳效果。比如Orientation=6时,表示要逆时针旋转90度才能达到最佳效果。
  31. 这样,在电脑上查看照片的时候,他会旋转成类似的效果。
  32. 但是我在拍摄的时候,手机是水平放置,摄像头垂直向下拍的,这个陀螺仪就有时候会变成头朝上,有时候变成手朝上了。于是就有了不同的旋转角度。
  33. 无论是labeleme还是电脑查看图片,都是一样的,所以没有意识到是这个问题,而当使用代码读取照片的时候,他读取到了原始的图像(PS:原始图像都是横屏的),也读取到了Orientation,但就是没有按照Orientation的指示,自动进行旋转。所以mask没有问题,而原始图像,旋转了90度。
  34. 找到了问题,就好解决了,写一个函数,专门处理所有的原始图片,按照Orientation的要求旋转图像,之后去掉所有的exif信息,就万事大吉了。
  35. 贴个代码吧,这一大片全是文字,我自己看着都头疼。
def clear_exif(pic_path):
    image = Image.open(pic_path)
    # get correction based on 'Orientation' from Exif (==Tag 274)
    try:
        deg = {3: 180, 6: 270, 8: 90}.get(image._getexif().get(274, 0), 0)
    except:
        deg = 0
    if deg != 0:
        image = image.rotate(deg, expand=True)
        image_data = list(image.getdata())
        image_without_exif = Image.new(image.mode, image.size)
        image_without_exif.putdata(image_data)
        image_without_exif.save(pic_path)
        print(f"旋转了:{pic_path}")

0

评论区