V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
SeaRecluse
V2EX  ›  Python

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

  •  
  •   SeaRecluse · 2019-10-16 10:47:16 +08:00 · 4200 次点击
    这是一个创建于 1877 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想把图像转成 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
    

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

    第 1 条附言  ·  2019-10-16 16:09:23 +08:00

    手写补充下

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

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

    前面猜的差不多了,要么是 8UC1 溢出,还可能 python 和 C++的 RGB 顺序不一样
    ooxxcc
        12
    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
        13
    SeaRecluse  
    OP
       2019-10-16 15:46:49 +08:00
    @lcdtyph 默认分割后就是 8UC1,py 下如果手动执行操作的话,我新建的数据是 float32 位的,所以为了对应也为了防止溢出就改为 32FC1 的。
    SeaRecluse
        14
    SeaRecluse  
    OP
       2019-10-16 15:52:47 +08:00
    @ooxxcc 这里是我没说清楚,一开始我是好奇类似 R / (R + G + B)的归一化方式是啥玩意,随便搜了下,搜到了 CIE 1931 的色域分布公式,所以就简称 CIE 了。
    因为我 py 模拟这个操作的时候,初始化为 float32 时的结果和直接操作的结果相同,而 8UC1 情况下不同,而 C++不论如何的结果都与 py 直接操作不同,所以才有疑问。
    ooxxcc
        15
    ooxxcc  
       2019-10-16 15:55:09 +08:00
    @SeaRecluse 所以,你说这么多不如贴一下代码,这里一堆大佬会帮你 debug

    不只是初始化的问题,你这个操作过程中随时都可能存在溢出(比如临时变量)
    ooxxcc
        16
    ooxxcc  
       2019-10-16 15:56:16 +08:00
    其实主要就是
    1.R + G + B 大于 255 处理了没
    2.R + G + B 等于 0 处理了没
    SeaRecluse
        17
    SeaRecluse  
    OP
       2019-10-16 16:02:37 +08:00
    @ooxxcc 这个我手动重写时都有考虑。其实这就是全部代码了额- -。C++和 py 只是初始化不太一样而已,随手找张图这样处理一下然后 Imwrite,就能发现 C++ 的结果会全部黑 [因为都小于 1 了,uchar 里会变 0] ,但是 py 的会不一样。
    ooxxcc
        18
    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
        19
    ooxxcc  
       2019-10-16 16:30:38 +08:00
    比如这一句 r = R / (R + G + B);
    里面所有变量都是 unsigned char……
    你觉得会怎么样呢,r 中元素只可能有三个值,0/1/inf (除数为 0,可能抛异常)
    SeaRecluse
        20
    SeaRecluse  
    OP
       2019-10-16 16:31:01 +08:00
    @ooxxcc emmm 这个要双持下才会知道差别也太大了- -,我尝试手动转的代码没有贴。现在可以复现 C++下的效果,但是复现不了 Py 下的效果😂
    SeaRecluse
        21
    SeaRecluse  
    OP
       2019-10-16 16:32:58 +08:00
    @ooxxcc 我明白这是合理的,所以反观 py 我就懵了额。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5741 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 03:12 · PVG 11:12 · LAX 19:12 · JFK 22:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.