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
Sponsored by
LinkedIn
不坐班的神仙工作 · 去任何你想去的地方远程,赚一线城市的工资
2000 个不用出门 Social 的全球远程工作,帮助 V2EX 的小伙伴开启全新的工作方式。
Promoted by LinkedIn
zaxlct
V2EX  ›  Python

新手提问:如何用 Python 识别魔方上不同颜色块的数量?

  •  
  •   zaxlct · 2019-05-16 19:06:15 +08:00 · 5634 次点击
    这是一个创建于 1233 天前的主题,其中的信息可能已经有所发展或是发生改变。

    下图由黄,红,绿,蓝方块组成,如何获取每种颜色方块的数量? 如果用 python 来实现的话,有第三方库或思路推荐吗,谢谢 图片

    我首先想到了 openCV,如果实在没思路的话,就去 GayHub 找个 python-opencv 的库试试看,考虑到可能会绕圈子,所以在这里问问 pythoner 大佬,感想~

    第 1 条附言  ·  2019-05-16 22:39:43 +08:00
    刚开始觉得问题简单了,花时间仔细想了很久,还有以下几个点开始没考虑到:
    1. 每个图片分辨率不是固定的
    2. 每个方块周围还有白色缝隙干扰
    3. 有的图形可能不是完整的正方形方块(不完整的方块也算一个)
    比如下图,是比较复杂的场景 = =!

    ![]( http://vote-img.sutot.cn/1558017547.jpeg?imageMogr2/thumbnail/!70p)
    第 2 条附言  ·  2019-05-17 09:53:14 +08:00
    感谢大家的回复,结合大家的想法和自己的实际情况,我觉得用直方图、图片二值化、或 hsv 等提取颜色特征的方法代母实现上有点困难,然后可能精度有点不够(多一块少一块都不行),我决定用一个方块上下左右移动遍历,取每个方块的中心点颜色色值,最后统计不同颜色数量的方法来做。(@largecat )
    第 3 条附言  ·  2019-05-17 09:56:27 +08:00
    和女朋友沟通了一下,每张图都是用 PS 做出来的,所以理论上图片可以是矢量图,或者是非常高清的图。
    感觉如果搞不定这个需求的话,会被女朋友深深的鄙视👎,😭
    43 条回复    2019-05-18 15:11:40 +08:00
    AlisaDestiny
        1
    AlisaDestiny  
       2019-05-16 19:17:09 +08:00   ❤️ 1
    颜色空间直方图了解一下。
    zaxlct
        2
    zaxlct  
    OP
       2019-05-16 19:22:01 +08:00 via iPhone
    @AlisaDestiny 谢谢,我查查相关资料
    Muniesa
        3
    Muniesa  
       2019-05-16 19:53:00 +08:00
    我的思路是,按颜色设置阈值,分割之后计算每种颜色轮廓的面积,和总面积一比就可以了
    Muniesa
        4
    Muniesa  
       2019-05-16 19:55:16 +08:00
    好像跟直方图原理差不多 hhh 都是计算像素数量
    Takamine
        5
    Takamine  
       2019-05-16 22:06:52 +08:00
    不知道用一个和方块一样大小的 scanner 一路扫过去,结合 PIL 库有没有戏。
    ThirdFlame
        6
    ThirdFlame  
       2019-05-16 22:36:03 +08:00
    如果方块大小是固定和一致的,如果是的话 使用 PIL 库 隔多少像素去一个点,获得 rgb 值即可。
    no1xsyzy
        7
    no1xsyzy  
       2019-05-16 22:44:32 +08:00   ❤️ 1
    卖垫子的?

    1. 需要被统计的块是否可能本身是白色的?
    2. 是否保证存在白色缝隙?
    3. 是否对精度有绝对要求?
    zaxlct
        8
    zaxlct  
    OP
       2019-05-16 22:51:48 +08:00
    @no1xsyzy 哈哈,卖地胶的,白色的块无需统计,保证存在白色缝隙,对精度有要求。但是图片分辨率都会和上面的第一张图一样清楚。

    如果你有思路可以聊下,我可以付一些辛苦费,告诉我思路自己去实现,嘿嘿
    ThirdFlame
        9
    ThirdFlame  
       2019-05-16 23:05:24 +08:00
    有个简单粗暴的方法,直接遍历所有点的 RGB 值,然后拿同颜色的点( RGB 相近)的数量 除以 1 块的像素点数量(宽*高) 就能得到大概值了。
    不过半块的之类的会导致少算一些。
    minami
        10
    minami  
       2019-05-16 23:15:39 +08:00
    这种估计只能用图形学的区域填充算法,把每块的边界算出来,才能保证精度
    zaxlct
        11
    zaxlct  
    OP
       2019-05-16 23:20:26 +08:00
    查了很多资料,GayHub 也翻了半天没找到好的办法,我看最终的办法只能靠肉眼去数了 = =!
    no1xsyzy
        12
    no1xsyzy  
       2019-05-16 23:36:01 +08:00   ❤️ 1
    @zaxlct 这样相对简单,用白色切开后统计每个块的颜色直方图。
    精度要求我认为设计成先显示一个带覆盖层的样子然后人工检验一下比较好。
    最好能够比较方便地指出错误类型

    “与其费力地尝试完全取代人类的工作,不如想想如何让人类的工作变得更加方便”
    necomancer
        13
    necomancer  
       2019-05-17 02:37:25 +08:00   ❤️ 1
    from skimage.color import rgb2hsv, rgba2rgb
    from skimage import data, io, filters
    import numpy as np

    image = io.imread('1.png')
    hsv = rgb2hsv(rgba2rgb(image))

    h_hist, h = np.histogram(hsv[...,0].flatten(), bins=30)

    1. 把你的图转成 hsv,在 h 空间求 histogram,黑 /白色的 h 值会是 0 所以不用在意。选择合适的 bins,使峰个数和颜色个数相等。忽略小于某值的 h,因为是白色。这里如果你的图里每个颜色都是纯色,bins 原则多大都是准确的。
    2. 建议你尽量把图的 dpi 搞成一样的,也就是说每个方块大小相等,图总大小只和方块数有关。这样你只要算出一个方块有多少像素,用上述的 h_hist 值去除就可以了。因为不到一个方块按一个方块计算,所以向上取整 int(h_hist/square_size)+1 即可。
    necomancer
        14
    necomancer  
       2019-05-17 02:52:18 +08:00   ❤️ 1
    我没怎么折腾过这类问题,你最好看看 rgb2hsv 和 rgba2rgb 之类的函数,了解一下 hsv 模型。理论上说,白色的话 hsv 里 s 是 0, v 是 1,rgb2hsv 里给出的 h 也应该是 0,但近白色 h 不一定是 0,所以纯色最好。你这图不知道为啥好像不完全是纯色,所以筛选起来可能会比较麻烦,求 histogram 之前可以考虑像 hsv = hsv[np.logical_and(hsv[...,1]>0.05, hsv[...,2]<0.95)]这样按照 s, v (白色 s 值比较小接近 0,v 值比较大接近 1 )尽可能地把白色去掉,以增加准确度。

    可以看看这里:
    http://www.voidcn.com/article/p-dntnbcyb-ro.html
    有常见颜色的 HSV 范围参考。
    necomancer
        15
    necomancer  
       2019-05-17 03:10:34 +08:00
    P.S. 地胶市场咋样?这么丑的设计地胶能卖出去么……
    dangyuluo
        16
    dangyuluo  
       2019-05-17 05:53:39 +08:00   ❤️ 1
    如果要大致计算的话,就用直方图。如果要精确计算的话,就划分网格,然后一个个中心取 RGB 值。不规则形状的话,用一个 mask 来遮住空白区域
    largecat
        17
    largecat  
       2019-05-17 07:23:38 +08:00 via Android   ❤️ 1
    第一个图横竖遍历,每个方格中心点像素值取出来,最后统计像素值数量就行。

    第二个不规则图形,细节还是小方格,我觉得先把不规则图形补成规则的长方形,再横竖遍历,最后求像素个数,

    一般图形颜色不会那么整齐,考虑颜色值的一个偏移范围,
    JerryCha
        18
    JerryCha  
       2019-05-17 08:27:09 +08:00
    腐蚀好像可以消去细线和封闭区块内的点
    zaxlct
        19
    zaxlct  
    OP
       2019-05-17 08:43:30 +08:00 via iPhone
    @necomancer 这个图只是方便客户,计算需要的数量,实际不是这个样子,市场挺好的
    ytmsdy
        20
    ytmsdy  
       2019-05-17 09:19:39 +08:00   ❤️ 1
    参考图片二值化的做法,把颜色进行三值化就可以了。然后就可以直接数块状大小了。
    atz
        21
    atz  
       2019-05-17 09:32:11 +08:00   ❤️ 1
    反正你这每一个格子大小应该都是固定的,用 opencv 查询每个格子中间像素的数值就很好统计
    zaxlct
        22
    zaxlct  
    OP
       2019-05-17 09:41:07 +08:00
    @atz 每个格子的大小是固定的,图都是美工做的,「用 opencv 查询每个格子中间像素的数值」这个有点难 = =!
    littleylv
        23
    littleylv  
       2019-05-17 09:49:28 +08:00   ❤️ 1
    简单提供一个思路,不知道符不符合你的要求:
    分别针对 4 个颜色,做 cv::threshold、cv::findContours 等操作,得到各个颜色的总面积。后面就可以除以每个色块的面积得到大概的色块数量了
    zaxlct
        24
    zaxlct  
    OP
       2019-05-17 09:54:20 +08:00
    @littleylv 我试一下
    qza1212
        25
    qza1212  
       2019-05-17 15:00:28 +08:00
    直接通过颜色做阈值分割,分别拿到各种颜色的面积,然后除以单个方块的面积就行了
    moodasmood
        26
    moodasmood  
       2019-05-17 15:39:32 +08:00 via Android
    细线一定存在?都存在的话按细线切割开就行了呀
    minmini
        27
    minmini  
       2019-05-17 16:19:19 +08:00 via Android   ❤️ 1
    下午摸鱼写了一下,4 个颜色分别 181 731 14 34 个?
    zaxlct
        28
    zaxlct  
    OP
       2019-05-17 16:33:17 +08:00
    @minmini 红色我肉眼数了下 37 个
    minmini
        29
    minmini  
       2019-05-17 17:39:42 +08:00 via Android
    @zaxlct 颜色识别有点问题,晚上回去研究一下 HSV
    minmini
        30
    minmini  
       2019-05-17 21:31:06 +08:00   ❤️ 1
    @zaxlct 刚刚回家改了改各种颜色的判定范围,没问题了,红色 h 值可以在两个区间,emmmmmm
    红色:37
    蓝色:14
    黄色:178
    绿色:731
    其他?:0
    cz5424
        31
    cz5424  
       2019-05-17 22:42:31 +08:00 via iPhone
    计算一下间隙距离(从左到右遇到白色块的距离)切割图片,遍历所有小图
    zaxlct
        32
    zaxlct  
    OP
       2019-05-17 23:47:58 +08:00
    @minmini 我和同事也实现了下,有点误差。你的计算还挺准确的,能提供下思路吗?
    minmini
        33
    minmini  
       2019-05-17 23:54:47 +08:00   ❤️ 1
    @zaxlct
    先用不同的色彩通道做二值化,然后合并(bitwise_and),再简单的处理一下得到网格的 mask,然后用原图减去网格得到很多小方块。再寻找轮廓就能够得到全部小方块的轮廓,获取每个小方块的中心坐标,再拿着全部坐标到原图(转成 HSV)去取值,最后根据 @necomancer 的方法来判断颜色就好了
    zaxlct
        34
    zaxlct  
    OP
       2019-05-17 23:57:42 +08:00
    @minmini 谢谢你的回复,我去试试。另外一个不情之请,方便的话能不能提供下部分代码,作为感谢,一本 python 相关的书作为感谢~京东上可以自选,报酬很低,见谅~
    minmini
        35
    minmini  
       2019-05-18 00:05:07 +08:00
    @zaxlct 可以的,留个邮箱吧
    zaxlct
        36
    zaxlct  
    OP
       2019-05-18 00:08:52 +08:00
    @minmini
    [email protected]
    谢谢,顺便把书的京东链接、收货地址一起发送吧~
    minmini
        37
    minmini  
       2019-05-18 00:21:29 +08:00
    @zaxlct 已发,请注意查收,有问题直接回邮件就是
    vmebeh
        38
    vmebeh  
       2019-05-18 01:18:37 +08:00 via iPad
    我觉得可以写个拼图的工具
    lovestudykid
        39
    lovestudykid  
       2019-05-18 02:49:51 +08:00   ❤️ 1


    学 cv 时候的作业,先用 canny edge detector,再用 hough line detector,然后筛选一下,就可以把每个角点确定下来,然后在每个矩形中间去颜色就行了。不用颜色直方图的原因是你收拍的照片是有 projective distortion 的。
    hacunix
        40
    hacunix  
       2019-05-18 08:56:29 +08:00 via iPhone
    hsv 了解一下
    banditv2ex
        41
    banditv2ex  
       2019-05-18 10:15:33 +08:00   ❤️ 1
    直接把所有的像素转换成 rgb 编码,然后 计算所有不同 RGB 编码的数量,就是像素量,然后除以每个色块的像素量就是色块数。
    zaxlct
        42
    zaxlct  
    OP
       2019-05-18 15:10:39 +08:00
    条条大路通罗马,等我实现了把代码贴一下
    zaxlct
        43
    zaxlct  
    OP
       2019-05-18 15:11:40 +08:00
    @banditv2ex 有的方块可能是半块(不满一块按一块算)所以您的方法可能会有误差
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1961 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 50ms · UTC 02:12 · PVG 10:12 · LAX 19:12 · JFK 22:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.