建议使用以下浏览器,以获得最佳体验。 IE 9.0+以上版本 Chrome 31+ 谷歌浏览器 Firefox 30+ 火狐浏览器
设置昵称

在此一键设置昵称,即可参与社区互动!

确定
我再想想
选择版块
CANN 主题:1258帖子:5198

【 问题求助-DVPP/AIPP】

透过img2bin.py存在的巨大暗坑浅谈samples仓和tools仓现存的已知乱象

不要脸到家... 2021/9/14 596

我看昇腾主论坛上大家把设计模式讲的头头是道,挺嗨的,关键是用户遇到问题的时候没见嗨的人则么积极去实际解决使能啊!!!有点颠覆我的三观,开发是使能客户,技术支持同样是使能客户,大客户是客户,小客户也是客户,我觉得这也没啥丢人低级的。你们中间某些人既然自诩开发那可以去问问你们的HR你们工作到底是个啥性质,问清楚啦去转到真正的开发岗好吗,别高不成低不就。

因为常识里开发的功底普遍要比技术支持高得多,那我就以曾经作为技术支持的人聊两句偏现实的,看看某些自诩开发人员的肚子里真实功底到底可以高到哪个层面,就看你们想不想改了。就直接聊聊你们的开源代码,开源仓库呗。咱们从img2bin.py  https://gitee.com/ascend/tools/blob/master/img2bin/img2bin.py

开始吧,本人逐行拜读了 @chen68 大神的大作 img2bin.py 说句实话啊感慨蛮深的,发现了不少的问题,逻辑组织上的矛盾点,究竟是雀雀实实,还是我蓄意抹黑?且看我下面的条理论证。接下来我就用最通俗的语言配合代码一一举例说明问题出在哪里:

convert_img 函数

https://gitee.com/ascend/tools/blob/master/img2bin/img2bin.py#L157

157行的cv.cvtColor(input_img, cv.COLOR_BGR2YUV_I420)

如果用户要求输出的图像数据为YUV格式,cv.imread读取图像BGR数据,然后在此行通过cv.cvtColor的第二个参数cv.COLOR_BGR2YUV_I420转化为YUVI420格式,也即YU12格式。YUVI420(YU12)格式的图像数据内存排布如下图所示(关于这张图描述的正确性欢迎大家随意验证哈)

YUVI420 的 各类型像素排布方式可知:

  1.    Y像素排布完毕之后,再排布U像素,最后排布V像素
  2.     420指得是(BGR/RGB -> U和V)像素的转换采样规则,那三个数字凭啥就可以描述采样规则呢?其实就是以一个采样块的采样规律来看待全图。第一个4指的是采样块的像素宽度为4个点,后面俩数字一个2,一个0,这儿有俩数字所以表示有两行。据此就先明确了采样块的形状是宽度为4高度为2总共8个像素点的一个像素块。数字2和0本身的含义是第一行取俩像素点最为代表点,第二行取零个像素点最为代表点。代表点是干嘛的?就是取这些位置点的RGB/BGR三个数据各自乘个系数,加到一起,位移一下,再加减一个数,得到的那个结果就是U或V的值。
  3.   结合上图就是取Y1 Y3 Y9 Y11的位置的BGR/RGB像素来计算出U和V的值,所以一对U V被4个位置的像素共用。举例说明:
    Y1 Y2 Y5 Y6位置的像素选出左上角的Y1位置的像素的BGR数值来算出 U1和V1的值;Y11 Y12 Y15 Y16位置的像素选出左上角的Y11位置的像素的BGR数值来算出 U4和V4的值。如果w指代BGR图片的宽,h指代BGR图片的高,那么420采样规则的U和V所占的像素点个数就是w/2 * h/2  = w*h/4。因为在opencv和python数组中要先排满一行再排下一行,所以U和V各自的高度就是 w*h/4/w = h/4 那么U和V总共的高度就是h/4*2 = h/2,也就是U V像素总共的高度为图片真实高度的1/2,单论U或是V像素各自的高度,只是图片真实高度的1/4。因此U 和 V 像素的所占行数只与图片的高度有关,与图片的宽度无关。
    那照这样看来,貌似210就可以描述清UV采样规律啊,为啥非得叫420呢?可能是存在411这种冷门采样规律吧,为了兼容才叫420,同样411为啥不干脆就叫41呢?可能是相互的为了兼容210才叫411把,由此看来真正对高度有偶数限制的应该也就420这种采样规律的,422都能看成21,对高度没限制
  4.  说完了U和V,再说下Y。Y没有采样规则,如果非得说的话那就是一一对应可以叫11 或111或444,只不过是一个点的RGB三个数对应到Y这一个数而已,至于对应规则也是线性的乘加,位移,整体加减,只不过具体每个操作数不同罢了,具体的操作数该怎么选合理,自然有数学家们给出,我们一会再举例说公式。
    这就是YUV I420格式图像数据Y U V内存排布的规律,之所以搞清规律是为了后续正确的遍历Y U V各类型像素的存放地址,正确的在Y U V格式的图像数据上进行相应像素类型的减均值和乘系数操作。

扯淡啦这么多全是为后面做铺垫,要不然后面解释起来太突兀,我就担心这samples仓和tools仓里某些人不理解我。可是一旦真正搞清楚内存排布后,代码中矛盾点就显而易见,接踵而来啦!!!!

mean 减均值函数中:

当分支走到else 就是当输出图像格式为YUV时,


逗号之前为划分图像数据的高度这一维度,联系上下文可知,mean函数的调用在convert_img resize_img 之后, 也就是说input_img这个传参的图像数据在不考虑每一个像素的具体数据类型的情况下大小已经满足了模型要求的输入大小。

上述这些话看似是废话,但举实例说明,你们就明白我说的意思啦哈,假如用户传参要求的输出图片数据高度为400宽度为902且格式为YUV(虽然YUV格式很多,但只要采样规则是420)时,经过convert_img函数的格式转换之后在python解释器中键入 input_img.shape 返回值必然是 [600902].

这个600指的是Y像素占的400U V 共占的200, 为 Y高度的1/2。分三份取前两份(32等价于除1.5)也就是找到Y像素的数据。但这个被除数选的太搞笑,太愚蠢了,竟然是args.width难不成还能是902除以1.5 ? 关键是根本除不尽啊!!!那为什么numpy数组不报错呢??? 原来是通过int()强转为了整形,这是双刃剑,索引要求整形,即便小数位是0float也不行,但正确的情况应该是小数位是0float数被转为了int型。你现在的情况就是小数位有数的float被转成了int, 这TMD不是摆明了造假嘛!!!我就不说作者划分像素界限是否正确了,更严重的是按照仓里代码现在的写法,当要求输出的图片宽度的2/3大于图片高度的1.5倍时,岂不是会有数组越界的风险???我们加一些打印语句实地看一下哈,如下图所示:

运行如下图所示的命令,读取任意一张形状的图片,只要指明输出图片的宽度的2/3大于输出图片高度的1.5倍时,就必定会越界,事实证明果真如此。

可是那就奇怪啦呀!!!为什么没有报错也没有报警告呢???? 我们手动构造下numpy数组做下验证,见下图,可见python numpy数组越界后对于越界的部分操作无效,正是这种连警告都不报的防呆机制,埋下了暗坑,导致了Y像素的越界操作和UV像素的无效操作。

正确的做法应该是

dst_h = int(input_img.shape[0] / 1.5)

input_img[: dst_h, :] -= args.mean[0]

到这一步就完成了给Y像素遍历减均值的操作,那么接下来就是给U V 像素进行减均值的操作。img2bin.py中关于U像素的减均值是这样写的,简直就是不负责任的乱写一气

首先逗号之前的取高度2/3处作为分界点被除数args.width选错是第一点;其次逗号右面的取宽度 :: 2 是指根据逗号左边所选定的每一行数据都从下标0开始间隔俩像素点进行选定,然后每个选定点减去U像素应该减的均值。这种像素点选定方法不是乱搞吗????因为每一个U都是紧挨排列的,间隔为2进行选定明显矛盾啊!!!!不急我们先不给出正确答案,再看下下一行中关于V像素的减均值是怎么写的。

首先,同样的逗号之前的取高度2/3处作为分界点被除数args.width选错是第一点;其次取高度2/3处作为分界点是YU的分界点不是UV的分界点这是错误的第二点。再来看逗号右边的表达式就离谱到家啦!!! 1: 2 表达的是指根据逗号左边所选定的每一行数据都选定各自下标为1的数据。也就是说作者认为,V像素会排列在某些行的第二列数据上,与上面数据排布图对照来看简直就是驴唇不对马嘴!!!!这是错误的第三点。

代码到这里其实就已经彻彻底底得混乱不堪啦!!!!我不禁要想为什么代码会乱到这种程度啦????为什么????,理性的思索一下啊,本人感觉有两种情况: 第一种就是真的,作者他自己在乱写一气,就图个花架子,应付个需求,糊弄个任务。 第二种看他按照这种方法来给 UV像素进行采样减均值,貌似是按照NV12的方式来搞得。如果真的是这样的话,那可是就糗大了呀!!!为什么则么讲呢? NV12是这样的

UV交替排列,你要是对V数据进行操作,就算那堆行选错了,可是每行里的V数据也能选错?大家看下面这个图里的红框,你交替取值也应该写成 1::2 呀,1:21::2是完全不同的意思!不知道作者是真的笔误,还是说就是对python的基本列表切片的表达方式在理解上存在什么误区。

我就权当你是笔误啦,你就是想着这个YUV他就是NV12或是NV21的。可以的,那就算你像素位置索引错啦,你的cvtColor 的转换参数也选错啦? 在你看来是不是 cv.COLOR_BGR2YUV_I420 就是把 BGR数据转换成NV12或是NV21的呢?那咱们就验证下你选的这个参数到底是否正确,我们把数据在不经过缩放减均值乘系数时,当成NV12或是NV21转换回去,然后写成图片看看到底能花到什么程度,脏到什么程度

我们在如下图所示中加如下代码:

结果见下:

那这样看来I420并不是等价于NV12或是NV21嘛,那这个I420是真的I420吗,咱们按I420转回去看看还花不花?

还真不花啦,卧槽,那看来I420这个转换参数跟NV12/NV21 就没有半毛钱关系啊!!!那么 I420的格式的YUV图像数据减均值的时候到底应该咋写?其实就是正确地找到UV的位置。先分两种情况,第一种是UV各自只占整数行,第二种是有一行是UV共占的,他们各自半行。但考虑到python列表切片的语法表达,第二种情况再分两种方便表达,一种是只有一行有UV,且这两个像素各占半行,另一种就是UV各自都有相同个数的整数行,但是也有一行是共用的,这两个像素各占半行。

这就是正确的I420格式YUV各通道减均值的写法,至于乘系数-=换成*=就完了。

但是我不明白作者为什么会像将YUV格式指定为I420,是有哪一个适配310芯片的深度学习模型要求读入的图片数据格式会是YUVI420???那这个模型也太奇葩啦吧,从来就没有见过啊。哦,我突然明白了,你是想适配固化有aipp功能的om模型是吧???那你自己去aipp的色域转换配置里看看 https://support.huaweicloud.com/atctool-cann503alpha2infer/atlasatc_16_0020.html

根本就不支持YUVI420这种格式的输入,aippYUV的支持就两种YUV420spNV12/NV21默认NV12),YUV400。哦,我突然就明白了呀,因为采样规律都是420,只是采样后UV像素具体的排布不同,所以从BGR/RGB转成YUV时,YUVI420的数据大小是等于YUV420sp的,你们就是这样鱼目混珠的?就是这样不负责任的变相抹黑aipp?你知不知道cv.cvtColor压根就没有参数支持直接从BGR转成那个NV12或是NV21的。你想转成NV12/NV21配合msame去推理固化有aippom模型,且aipp参数input_format : YUV420SP_U8 。那真正送给原始模型去推理的数据就彻底乱套了,你竟然还用Faster R-CNN 模型来举例说明,请问你验证过使用这个模型配合aippinput_format : YUV420SP_U8img2bin.py msame

推理出正确的数据?如果推理出了正确的数据?你的msame推理出的数据从哪个开始到哪个数据结束表示的是一个目标框的信息?如果msame 压根就不在乎推理数据的正确性,而只是简单打通一个流程,甚至强调构造所谓的全0 数据,只看单次推理速度,那么在这种限制的使用范围下,还有什么必要加那么多的功能,难道只是简单堆砌,验证编译运行无误?那结果推理的正确性呢?加载一次循环推理多次的正确性呢?如果你要为你的img2bin.py配合msameaipp 参数为input_format : YUV420SP_U8 时的推理验证做辩解,我劝你最好录一段视频放到论坛,看看img2bin.py以及msame的可用性,价值到底在什么地方,好不好???你就用你举例的Faster R-CNN模型记得固化aipp input_format : YUV420SP_U8,推理出数据后,你说下有效数据在什么位置???我就不信这种垃圾搭配能行得通,单从语法方面就直接崩盘了,锦玉其外败絮其中,让你们自检,还视若罔闻,你难道要让用户去踩坑,我就不相信你在写的时候内心就通透无比?,哪里来的自信把这种垃圾组合放出来,破绽是不是太大,太离谱,太明显了?就你这种水平,这种负责任的态度,还给别人 /lgtm /approve 我真的要怀疑你们整体水平到底是啥啦?摆烂吗?

你是不会写BGR->YUV420sp(NV12/NV21)的转换吗?你们组里不是有人知道C++版本的吗?为啥不去请教?你就是这样对待自己交付的作品的?除啦摆烂我TMD也没法用别的词语去形容你了,就你这种水平给人上代码你自己不觉得有点匪夷所思?,你TMD能不能先把自己摘干净啦再说,网上的这种代码泛滥的到处都是,就懒得去扣过来测一下能不能用是吧?是没去试还是没有试验成功,又或是嫌弃for循环太多,某人看着觉得土,到底是看着土还是压根看不懂别人写的???

 

那咱就给你好好说说到底该咋做,TMD如何才能手动把cv读进来的BGR转成YUV420sp(NV12/NV21)?思路就两步:1. 就是根据采样规则找代表点 2. 再就是套线性公式操作每一个代表点的数据了。两步没啥固定的先后顺序,只不过先对每个点都套公式,一个矩阵乘公式就行了,写法上简略点,只不过多算了。先找代表点,要用两次矩阵乘,但不用多算。咱TMD都给你们试一遍

 

先搜一下转换公式: https://www.cnblogs.com/luoyinjie/p/7219319.html

因为imread直接读进BGR uint8的数据,为了方便直接处理,就选这个了

正如https://support.huaweicloud.com/atctool-cann503alpha2infer/atlasatc_16_0020.html 中描述的

你不想用for循环,就用矩阵乘不就完了,先找点后套公式如下所示:

这不就是把420采样,加套那组公式用进来就行啦?咱们先验证NV12的,转回BGR,写入本地看看咋样?

查看图片,如下没问题,试验BGRNV12成功。

那咱们转NV21呢?换换UV顺序不就完了?

那要是先套公式矩阵乘,再选代表点呢?

这不就完啦?

YUV是事咱说完了,你再看看你其他的地方,你对入参的-i -t 做强制要求,为啥TM的不对-w -h做强制要求?你知不知道,不强制要求,你的target_size 就是俩个NoneType

还有你的process函数

TMif else判断呢?我确定的告诉你补齐的全零padding边绝不会因为转RGB/GRAY,而改变,全都是resize完就convert就行了,还分情况调整顺序?你在哗众取宠吗?你自己不会列表切片看看啊?擦

还有change_type 你竟然全然不顾输出图像的格式,随便转?我实话告诉你,我TM就没停过YUV单个数据还有float32的?不能因为numpyastype不报错,你就乱来呀?啊?你转成非UINT8的数据,别减均值乘系数直接tofilebin文件,用YUV VIEWER看看画不画,操,获知用cv. cvtColor YUV回转乘BGRTMD就直接根据数据类型报错啦?该加if else判断的不加,不该加的乱加,我TM真的是无语啦!!!

除此以外 你读取文件,cv.imread 你不做后缀校验,cv.imread是不会报错的,但返回的数据是NoneType,结果到你 

resize_img 里 读shape的时候就TM直接挂啦!!!! 纯摆烂的东西,还有脸放在makesd的前面,不知道是谁的眼睛瞎了。

    巨大无比的暗坑.docx 5.19 MB,下载次数:4

回复1

cjl68
0 0
2021/9/15 11:51

非常感谢你花了这么多时间来确认img2bin的问题,img2bin这个脚本确实有问题。
img2bin是为了使用msame准备数据的,由于msame的定位是快速评估模型是否能够正常推理(不考虑精度);
当前masme已经支持不带输入直接跑推理,它会自动创建全0的数据作为输入,所以当前img2bin中隐藏的这个问题到现在还没有人发现;
幸亏有你才发现了这个问题,深表感谢;同时能看出来你对技术的专业以及精益求精,非常值得我们学习。

img2bin的问题已经在改进,等我们测试完毕后上库。

上划加载中
直达楼层
标签
您还可以添加5个标签
  • 没有搜索到和“关键字”相关的标签
  • 云产品
  • 解决方案
  • 技术领域
  • 通用技术
  • 平台功能
取消

采纳成功

您已采纳当前回复为最佳回复
发表于2021年09月14日 23:16:37 596 1
直达本楼层的链接
楼主
显示全部楼层
[DVPP/AIPP] 透过img2bin.py存在的巨大暗坑浅谈samples仓和tools仓现存的已知乱象

我看昇腾主论坛上大家把设计模式讲的头头是道,挺嗨的,关键是用户遇到问题的时候没见嗨的人则么积极去实际解决使能啊!!!有点颠覆我的三观,开发是使能客户,技术支持同样是使能客户,大客户是客户,小客户也是客户,我觉得这也没啥丢人低级的。你们中间某些人既然自诩开发那可以去问问你们的HR你们工作到底是个啥性质,问清楚啦去转到真正的开发岗好吗,别高不成低不就。

因为常识里开发的功底普遍要比技术支持高得多,那我就以曾经作为技术支持的人聊两句偏现实的,看看某些自诩开发人员的肚子里真实功底到底可以高到哪个层面,就看你们想不想改了。就直接聊聊你们的开源代码,开源仓库呗。咱们从img2bin.py  https://gitee.com/ascend/tools/blob/master/img2bin/img2bin.py

开始吧,本人逐行拜读了 @chen68 大神的大作 img2bin.py 说句实话啊感慨蛮深的,发现了不少的问题,逻辑组织上的矛盾点,究竟是雀雀实实,还是我蓄意抹黑?且看我下面的条理论证。接下来我就用最通俗的语言配合代码一一举例说明问题出在哪里:

convert_img 函数

https://gitee.com/ascend/tools/blob/master/img2bin/img2bin.py#L157

157行的cv.cvtColor(input_img, cv.COLOR_BGR2YUV_I420)

如果用户要求输出的图像数据为YUV格式,cv.imread读取图像BGR数据,然后在此行通过cv.cvtColor的第二个参数cv.COLOR_BGR2YUV_I420转化为YUVI420格式,也即YU12格式。YUVI420(YU12)格式的图像数据内存排布如下图所示(关于这张图描述的正确性欢迎大家随意验证哈)

YUVI420 的 各类型像素排布方式可知:

  1.    Y像素排布完毕之后,再排布U像素,最后排布V像素
  2.     420指得是(BGR/RGB -> U和V)像素的转换采样规则,那三个数字凭啥就可以描述采样规则呢?其实就是以一个采样块的采样规律来看待全图。第一个4指的是采样块的像素宽度为4个点,后面俩数字一个2,一个0,这儿有俩数字所以表示有两行。据此就先明确了采样块的形状是宽度为4高度为2总共8个像素点的一个像素块。数字2和0本身的含义是第一行取俩像素点最为代表点,第二行取零个像素点最为代表点。代表点是干嘛的?就是取这些位置点的RGB/BGR三个数据各自乘个系数,加到一起,位移一下,再加减一个数,得到的那个结果就是U或V的值。
  3.   结合上图就是取Y1 Y3 Y9 Y11的位置的BGR/RGB像素来计算出U和V的值,所以一对U V被4个位置的像素共用。举例说明:
    Y1 Y2 Y5 Y6位置的像素选出左上角的Y1位置的像素的BGR数值来算出 U1和V1的值;Y11 Y12 Y15 Y16位置的像素选出左上角的Y11位置的像素的BGR数值来算出 U4和V4的值。如果w指代BGR图片的宽,h指代BGR图片的高,那么420采样规则的U和V所占的像素点个数就是w/2 * h/2  = w*h/4。因为在opencv和python数组中要先排满一行再排下一行,所以U和V各自的高度就是 w*h/4/w = h/4 那么U和V总共的高度就是h/4*2 = h/2,也就是U V像素总共的高度为图片真实高度的1/2,单论U或是V像素各自的高度,只是图片真实高度的1/4。因此U 和 V 像素的所占行数只与图片的高度有关,与图片的宽度无关。
    那照这样看来,貌似210就可以描述清UV采样规律啊,为啥非得叫420呢?可能是存在411这种冷门采样规律吧,为了兼容才叫420,同样411为啥不干脆就叫41呢?可能是相互的为了兼容210才叫411把,由此看来真正对高度有偶数限制的应该也就420这种采样规律的,422都能看成21,对高度没限制
  4.  说完了U和V,再说下Y。Y没有采样规则,如果非得说的话那就是一一对应可以叫11 或111或444,只不过是一个点的RGB三个数对应到Y这一个数而已,至于对应规则也是线性的乘加,位移,整体加减,只不过具体每个操作数不同罢了,具体的操作数该怎么选合理,自然有数学家们给出,我们一会再举例说公式。
    这就是YUV I420格式图像数据Y U V内存排布的规律,之所以搞清规律是为了后续正确的遍历Y U V各类型像素的存放地址,正确的在Y U V格式的图像数据上进行相应像素类型的减均值和乘系数操作。

扯淡啦这么多全是为后面做铺垫,要不然后面解释起来太突兀,我就担心这samples仓和tools仓里某些人不理解我。可是一旦真正搞清楚内存排布后,代码中矛盾点就显而易见,接踵而来啦!!!!

mean 减均值函数中:

当分支走到else 就是当输出图像格式为YUV时,


逗号之前为划分图像数据的高度这一维度,联系上下文可知,mean函数的调用在convert_img resize_img 之后, 也就是说input_img这个传参的图像数据在不考虑每一个像素的具体数据类型的情况下大小已经满足了模型要求的输入大小。

上述这些话看似是废话,但举实例说明,你们就明白我说的意思啦哈,假如用户传参要求的输出图片数据高度为400宽度为902且格式为YUV(虽然YUV格式很多,但只要采样规则是420)时,经过convert_img函数的格式转换之后在python解释器中键入 input_img.shape 返回值必然是 [600902].

这个600指的是Y像素占的400U V 共占的200, 为 Y高度的1/2。分三份取前两份(32等价于除1.5)也就是找到Y像素的数据。但这个被除数选的太搞笑,太愚蠢了,竟然是args.width难不成还能是902除以1.5 ? 关键是根本除不尽啊!!!那为什么numpy数组不报错呢??? 原来是通过int()强转为了整形,这是双刃剑,索引要求整形,即便小数位是0float也不行,但正确的情况应该是小数位是0float数被转为了int型。你现在的情况就是小数位有数的float被转成了int, 这TMD不是摆明了造假嘛!!!我就不说作者划分像素界限是否正确了,更严重的是按照仓里代码现在的写法,当要求输出的图片宽度的2/3大于图片高度的1.5倍时,岂不是会有数组越界的风险???我们加一些打印语句实地看一下哈,如下图所示:

运行如下图所示的命令,读取任意一张形状的图片,只要指明输出图片的宽度的2/3大于输出图片高度的1.5倍时,就必定会越界,事实证明果真如此。

可是那就奇怪啦呀!!!为什么没有报错也没有报警告呢???? 我们手动构造下numpy数组做下验证,见下图,可见python numpy数组越界后对于越界的部分操作无效,正是这种连警告都不报的防呆机制,埋下了暗坑,导致了Y像素的越界操作和UV像素的无效操作。

正确的做法应该是

dst_h = int(input_img.shape[0] / 1.5)

input_img[: dst_h, :] -= args.mean[0]

到这一步就完成了给Y像素遍历减均值的操作,那么接下来就是给U V 像素进行减均值的操作。img2bin.py中关于U像素的减均值是这样写的,简直就是不负责任的乱写一气

首先逗号之前的取高度2/3处作为分界点被除数args.width选错是第一点;其次逗号右面的取宽度 :: 2 是指根据逗号左边所选定的每一行数据都从下标0开始间隔俩像素点进行选定,然后每个选定点减去U像素应该减的均值。这种像素点选定方法不是乱搞吗????因为每一个U都是紧挨排列的,间隔为2进行选定明显矛盾啊!!!!不急我们先不给出正确答案,再看下下一行中关于V像素的减均值是怎么写的。

首先,同样的逗号之前的取高度2/3处作为分界点被除数args.width选错是第一点;其次取高度2/3处作为分界点是YU的分界点不是UV的分界点这是错误的第二点。再来看逗号右边的表达式就离谱到家啦!!! 1: 2 表达的是指根据逗号左边所选定的每一行数据都选定各自下标为1的数据。也就是说作者认为,V像素会排列在某些行的第二列数据上,与上面数据排布图对照来看简直就是驴唇不对马嘴!!!!这是错误的第三点。

代码到这里其实就已经彻彻底底得混乱不堪啦!!!!我不禁要想为什么代码会乱到这种程度啦????为什么????,理性的思索一下啊,本人感觉有两种情况: 第一种就是真的,作者他自己在乱写一气,就图个花架子,应付个需求,糊弄个任务。 第二种看他按照这种方法来给 UV像素进行采样减均值,貌似是按照NV12的方式来搞得。如果真的是这样的话,那可是就糗大了呀!!!为什么则么讲呢? NV12是这样的

UV交替排列,你要是对V数据进行操作,就算那堆行选错了,可是每行里的V数据也能选错?大家看下面这个图里的红框,你交替取值也应该写成 1::2 呀,1:21::2是完全不同的意思!不知道作者是真的笔误,还是说就是对python的基本列表切片的表达方式在理解上存在什么误区。

我就权当你是笔误啦,你就是想着这个YUV他就是NV12或是NV21的。可以的,那就算你像素位置索引错啦,你的cvtColor 的转换参数也选错啦? 在你看来是不是 cv.COLOR_BGR2YUV_I420 就是把 BGR数据转换成NV12或是NV21的呢?那咱们就验证下你选的这个参数到底是否正确,我们把数据在不经过缩放减均值乘系数时,当成NV12或是NV21转换回去,然后写成图片看看到底能花到什么程度,脏到什么程度

我们在如下图所示中加如下代码:

结果见下:

那这样看来I420并不是等价于NV12或是NV21嘛,那这个I420是真的I420吗,咱们按I420转回去看看还花不花?

还真不花啦,卧槽,那看来I420这个转换参数跟NV12/NV21 就没有半毛钱关系啊!!!那么 I420的格式的YUV图像数据减均值的时候到底应该咋写?其实就是正确地找到UV的位置。先分两种情况,第一种是UV各自只占整数行,第二种是有一行是UV共占的,他们各自半行。但考虑到python列表切片的语法表达,第二种情况再分两种方便表达,一种是只有一行有UV,且这两个像素各占半行,另一种就是UV各自都有相同个数的整数行,但是也有一行是共用的,这两个像素各占半行。

这就是正确的I420格式YUV各通道减均值的写法,至于乘系数-=换成*=就完了。

但是我不明白作者为什么会像将YUV格式指定为I420,是有哪一个适配310芯片的深度学习模型要求读入的图片数据格式会是YUVI420???那这个模型也太奇葩啦吧,从来就没有见过啊。哦,我突然明白了,你是想适配固化有aipp功能的om模型是吧???那你自己去aipp的色域转换配置里看看 https://support.huaweicloud.com/atctool-cann503alpha2infer/atlasatc_16_0020.html

根本就不支持YUVI420这种格式的输入,aippYUV的支持就两种YUV420spNV12/NV21默认NV12),YUV400。哦,我突然就明白了呀,因为采样规律都是420,只是采样后UV像素具体的排布不同,所以从BGR/RGB转成YUV时,YUVI420的数据大小是等于YUV420sp的,你们就是这样鱼目混珠的?就是这样不负责任的变相抹黑aipp?你知不知道cv.cvtColor压根就没有参数支持直接从BGR转成那个NV12或是NV21的。你想转成NV12/NV21配合msame去推理固化有aippom模型,且aipp参数input_format : YUV420SP_U8 。那真正送给原始模型去推理的数据就彻底乱套了,你竟然还用Faster R-CNN 模型来举例说明,请问你验证过使用这个模型配合aippinput_format : YUV420SP_U8img2bin.py msame

推理出正确的数据?如果推理出了正确的数据?你的msame推理出的数据从哪个开始到哪个数据结束表示的是一个目标框的信息?如果msame 压根就不在乎推理数据的正确性,而只是简单打通一个流程,甚至强调构造所谓的全0 数据,只看单次推理速度,那么在这种限制的使用范围下,还有什么必要加那么多的功能,难道只是简单堆砌,验证编译运行无误?那结果推理的正确性呢?加载一次循环推理多次的正确性呢?如果你要为你的img2bin.py配合msameaipp 参数为input_format : YUV420SP_U8 时的推理验证做辩解,我劝你最好录一段视频放到论坛,看看img2bin.py以及msame的可用性,价值到底在什么地方,好不好???你就用你举例的Faster R-CNN模型记得固化aipp input_format : YUV420SP_U8,推理出数据后,你说下有效数据在什么位置???我就不信这种垃圾搭配能行得通,单从语法方面就直接崩盘了,锦玉其外败絮其中,让你们自检,还视若罔闻,你难道要让用户去踩坑,我就不相信你在写的时候内心就通透无比?,哪里来的自信把这种垃圾组合放出来,破绽是不是太大,太离谱,太明显了?就你这种水平,这种负责任的态度,还给别人 /lgtm /approve 我真的要怀疑你们整体水平到底是啥啦?摆烂吗?

你是不会写BGR->YUV420sp(NV12/NV21)的转换吗?你们组里不是有人知道C++版本的吗?为啥不去请教?你就是这样对待自己交付的作品的?除啦摆烂我TMD也没法用别的词语去形容你了,就你这种水平给人上代码你自己不觉得有点匪夷所思?,你TMD能不能先把自己摘干净啦再说,网上的这种代码泛滥的到处都是,就懒得去扣过来测一下能不能用是吧?是没去试还是没有试验成功,又或是嫌弃for循环太多,某人看着觉得土,到底是看着土还是压根看不懂别人写的???

 

那咱就给你好好说说到底该咋做,TMD如何才能手动把cv读进来的BGR转成YUV420sp(NV12/NV21)?思路就两步:1. 就是根据采样规则找代表点 2. 再就是套线性公式操作每一个代表点的数据了。两步没啥固定的先后顺序,只不过先对每个点都套公式,一个矩阵乘公式就行了,写法上简略点,只不过多算了。先找代表点,要用两次矩阵乘,但不用多算。咱TMD都给你们试一遍

 

先搜一下转换公式: https://www.cnblogs.com/luoyinjie/p/7219319.html

因为imread直接读进BGR uint8的数据,为了方便直接处理,就选这个了

正如https://support.huaweicloud.com/atctool-cann503alpha2infer/atlasatc_16_0020.html 中描述的

你不想用for循环,就用矩阵乘不就完了,先找点后套公式如下所示:

这不就是把420采样,加套那组公式用进来就行啦?咱们先验证NV12的,转回BGR,写入本地看看咋样?

查看图片,如下没问题,试验BGRNV12成功。

那咱们转NV21呢?换换UV顺序不就完了?

那要是先套公式矩阵乘,再选代表点呢?

这不就完啦?

YUV是事咱说完了,你再看看你其他的地方,你对入参的-i -t 做强制要求,为啥TM的不对-w -h做强制要求?你知不知道,不强制要求,你的target_size 就是俩个NoneType

还有你的process函数

TMif else判断呢?我确定的告诉你补齐的全零padding边绝不会因为转RGB/GRAY,而改变,全都是resize完就convert就行了,还分情况调整顺序?你在哗众取宠吗?你自己不会列表切片看看啊?擦

还有change_type 你竟然全然不顾输出图像的格式,随便转?我实话告诉你,我TM就没停过YUV单个数据还有float32的?不能因为numpyastype不报错,你就乱来呀?啊?你转成非UINT8的数据,别减均值乘系数直接tofilebin文件,用YUV VIEWER看看画不画,操,获知用cv. cvtColor YUV回转乘BGRTMD就直接根据数据类型报错啦?该加if else判断的不加,不该加的乱加,我TM真的是无语啦!!!

除此以外 你读取文件,cv.imread 你不做后缀校验,cv.imread是不会报错的,但返回的数据是NoneType,结果到你 

resize_img 里 读shape的时候就TM直接挂啦!!!! 纯摆烂的东西,还有脸放在makesd的前面,不知道是谁的眼睛瞎了。

巨大无比的暗坑.docx 5.19 MB,下载次数:4

数据结构

举报
分享

分享文章到朋友圈

分享文章到微博

采纳成功

您已采纳当前回复为最佳回复

cjl68

发帖: 30粉丝: 21

级别 : 版主

发消息 + 关注

发表于2021年09月15日 11:51:47
直达本楼层的链接
5#
显示全部楼层

非常感谢你花了这么多时间来确认img2bin的问题,img2bin这个脚本确实有问题。
img2bin是为了使用msame准备数据的,由于msame的定位是快速评估模型是否能够正常推理(不考虑精度);
当前masme已经支持不带输入直接跑推理,它会自动创建全0的数据作为输入,所以当前img2bin中隐藏的这个问题到现在还没有人发现;
幸亏有你才发现了这个问题,深表感谢;同时能看出来你对技术的专业以及精益求精,非常值得我们学习。

img2bin的问题已经在改进,等我们测试完毕后上库。

点赞 评论 引用 举报

游客

您需要登录后才可以回帖 登录 | 立即注册

邀请回答
您可以邀请3位专家

结贴

您对问题的回复是否满意?
满意度
非常满意 满意 一般 不满意
我要反馈
0/200