图像处理, py 和 C++下的结果不同

2019-10-16 10:47:16 +08:00
 SeaRecluse

想把图像转成 CIE 色度下的图片,执行了如下操作

#B,G,R = split(img)

/*
vector<Mat>BGR;
split(img,BGR);
B,G,R = BGR[0],BGR[1],BGR[2]
*/

r = R / (R + G + B)
g = G / (R + G + B)
b = 1 - r - g

发现两者的结果不同,有大佬来解惑么~

4018 次点击
所在节点    Python
21 条回复
Mohanson
2019-10-16 11:48:16 +08:00
检查下变量 R, G, B 是不是 float.
SeaRecluse
2019-10-16 13:41:04 +08:00
@Mohanson 有检查,然后为了避免运算符重载的问题,我还遍历了手动操作,但是结果还是不一样,难道是 py 和 C++的 imwrite 不同?
lcdtyph
2019-10-16 13:53:33 +08:00
@SeaRecluse #2
注释里的东西是实际代码吗?
如果是的话
```
B,G,R = BGR[0],BGR[1],BGR[2]
```
相当于 B, G, (R = BGR[0]), BGR[1], BGR[2]
这在 C++里是逗号表达式,并不是 unpacking
stebest
2019-10-16 14:06:31 +08:00
这个语法是 C 还是 py ?
SeaRecluse
2019-10-16 14:21:06 +08:00
@lcdtyph @stebest 伪代码
现在我自己测试的结果是 C++因为变量类型固定的缘故,会比 py 多一步%256。所以会有差别- -
capbone
2019-10-16 14:46:24 +08:00
图像颜色这种东西可视化一下不就清楚问题在哪了?而且 r = R / (R + G + B) 这种哪是 CIE 啊
Justkkk
2019-10-16 14:49:41 +08:00
opencv r,g,b 是 uchar 存储的,8 位( 0-255 ),你 r+b+g 可能会超过 255 的
hitmanx
2019-10-16 14:56:21 +08:00
一共就那么点操作,那么几行代码,还贴伪代码...变量类型让大家猜吗?
SeaRecluse
2019-10-16 15:16:42 +08:00
@Justkkk 我修改了 Mat 开始的空间类型为 32FC1,结果是一样的。py 这里不会归到 0-255 内,然后存储再读取之后的值,看不出来是怎么转换的。
lcdtyph
2019-10-16 15:37:01 +08:00
@SeaRecluse 按你的描述不是应该修改成 8UC1 吗…
ooxxcc
2019-10-16 15:42:58 +08:00
一共就这么几行,还贴伪代码,是让大家脑补还原再帮你 debug 吗?

然后出来结果怎么样得也没说,只描述了不一样,到底怎么不一样

前面猜的差不多了,要么是 8UC1 溢出,还可能 python 和 C++的 RGB 顺序不一样
ooxxcc
2019-10-16 15:46:02 +08:00
还有,opencv 自带颜色空间转换,你何苦自己写……

https://docs.opencv.org/3.4/de/d25/imgproc_color_conversions.html

另外 CIE 有 CIE XYZ/ CIE L*a*b*/CIE L*u*v*,不过我看你这个怎么好像哪个都不是……
SeaRecluse
2019-10-16 15:46:49 +08:00
@lcdtyph 默认分割后就是 8UC1,py 下如果手动执行操作的话,我新建的数据是 float32 位的,所以为了对应也为了防止溢出就改为 32FC1 的。
SeaRecluse
2019-10-16 15:52:47 +08:00
@ooxxcc 这里是我没说清楚,一开始我是好奇类似 R / (R + G + B)的归一化方式是啥玩意,随便搜了下,搜到了 CIE 1931 的色域分布公式,所以就简称 CIE 了。
因为我 py 模拟这个操作的时候,初始化为 float32 时的结果和直接操作的结果相同,而 8UC1 情况下不同,而 C++不论如何的结果都与 py 直接操作不同,所以才有疑问。
ooxxcc
2019-10-16 15:55:09 +08:00
@SeaRecluse 所以,你说这么多不如贴一下代码,这里一堆大佬会帮你 debug

不只是初始化的问题,你这个操作过程中随时都可能存在溢出(比如临时变量)
ooxxcc
2019-10-16 15:56:16 +08:00
其实主要就是
1.R + G + B 大于 255 处理了没
2.R + G + B 等于 0 处理了没
SeaRecluse
2019-10-16 16:02:37 +08:00
@ooxxcc 这个我手动重写时都有考虑。其实这就是全部代码了额- -。C++和 py 只是初始化不太一样而已,随手找张图这样处理一下然后 Imwrite,就能发现 C++ 的结果会全部黑 [因为都小于 1 了,uchar 里会变 0] ,但是 py 的会不一样。
ooxxcc
2019-10-16 16:27:51 +08:00
@SeaRecluse 没看到你转换成 double 啊……建议学习一下 Mat::copyTo 和 Mat::convertTo 的区别
假如都是 8UC1 的话,你这么除之后当然都是 1 或者 0,imwrite 之后是全黑也是正常的

你现在做的是一个 range 是[0,1]的 8UC1 Mat 保存成图片,全黑是正常表现
python-opencv 我没怎么用过,看起来大概是隐含类型转换,除的时候给你处理成浮点了,保存时候表现不一样
ooxxcc
2019-10-16 16:30:38 +08:00
比如这一句 r = R / (R + G + B);
里面所有变量都是 unsigned char……
你觉得会怎么样呢,r 中元素只可能有三个值,0/1/inf (除数为 0,可能抛异常)
SeaRecluse
2019-10-16 16:31:01 +08:00
@ooxxcc emmm 这个要双持下才会知道差别也太大了- -,我尝试手动转的代码没有贴。现在可以复现 C++下的效果,但是复现不了 Py 下的效果😂

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/609807

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX