如何从饼图图片中获取数据?

-4 投票
1 回答
69 浏览
提问于 2025-04-14 17:15

我需要从一个简单的饼图图片中提取所有相关的数据,这些数据会不时变化。

这里有一个简单饼图的例子:

在这里输入图片描述

我该如何定义一个Python函数,来得到类似这样的结果:green=26grey=15red=4

提前感谢你的支持。

我对怎么做完全没有头绪。

1 个回答

2

如果你对图像处理不太熟悉,最快最简单的方法如下:

  • 先制作一个你图像中颜色的样本
  • 把你图像中的颜色重新映射到这个样本中的颜色
  • 统计每种颜色的像素数量,然后计算出它们的百分比

为了快速起见,我会先教你用ImageMagick来做,之后我们再用Python来实现。

首先,制作你的颜色样本:

magick xc:green xc:salmon xc:lightgray xc:white +append swatch.png

下面是swatch.png的放大版本:

这里输入图片描述

你可以用颜色名称来选择颜色,或者如果你喜欢,也可以使用rgb()三元组,比如:

magick xc:"rgb(108,254,32)" xc:"rgb(10,10,10)" ...

现在把你的饼图中的颜色重新映射到样本中,并且避免出现杂色:

magick pie.jpg +dither -remap swatch.png result.png

这里输入图片描述

我之所以要映射到一个已知的颜色调色板,是因为你的JPEG图像经过压缩,里面有成千上万种颜色,且每种颜色都有细微的变化,而我们希望把这些颜色统一到饼图中的颜色。

现在检查直方图:

identify -verbose result.png | more

Image:
  Filename: result.png
  Permissions: rw-r--r--
  Format: PNG (Portable Network Graphics)
  Mime type: image/png
  Class: PseudoClass
  Geometry: 408x387+0+0
  ...
  ...
  Colors: 4
  Histogram:
         52565: (0,128,0) #008000 green            <--- HERE
         31115: (211,211,211) #D3D3D3 LightGray    <--- HERE
          7168: (250,128,114) #FA8072 salmon       <--- HERE
         67048: (255,255,255) #FFFFFF white
  Colormap entries: 4
  Colormap:
    0: (255,255,255,1) #FFFFFFFF white
    1: (211,211,211,1) #D3D3D3FF LightGray
    2: (0,128,0,1) #008000FF green
    3: (250,128,114,1) #FA8072FF salmon
  Rendering intent: Perceptual
  ...
  ...

现在你可以看到,在90,848个非白色像素中,有52,565个绿色像素(52565+31115+7168),占57%。还有31,115个浅灰色像素,占34%,以及7,168个鲑鱼色像素,占8%。


如果你想用Python做同样的事情,可以使用PIL/Pillow,像这样:

#!/usr/bin/env python3
# https://stackoverflow.com/a/78132079/2836621

import numpy as np
from PIL import Image

# Define the colours to which we want to quantize
colours = [255,255,255, 0,128,0, 211,211,211, 250,128,114]

# Create a 1x1 pixel palette image and push our colours into its palette
p = Image.new('P',(1,1))
p.putpalette(colours)

# Load the image we want to quantize
im = Image.open('pie.jpg')

# Do the work, disable dithering
N = int(len(colours)/3)      # Colours have 3 RGB components
result = im.quantize(colors=N, dither=Image.Dither.NONE, palette=p)

# Print result
print(np.array(colours).reshape((-1,3)))
print(f'{result.getcolors()=}')

# Just pretty-printing...
hist = result.getcolors()
Ngreen  = hist[1][0]
Ngrey   = hist[2][0]
Nsalmon = hist[3][0]
Total = Ngreen + Ngrey + Nsalmon

print(f'Green: {Ngreen*100/Total:.1f}')
print(f'Grey: {Ngrey*100/Total:.1f}')
print(f'Salmon: {Nsalmon*100/Total:.1f}')

输出结果

[[255 255 255]     <--- Colour 0 is white
 [  0 128   0]     <--- Colour 1 is green
 [211 211 211]     <--- Colour 2 is light grey
 [250 128 114]]    <--- Colour 3 is salmon pink
result.getcolors()=[(67000, 0), (52578, 1), (31148, 2), (7170, 3)]
Green: 57.8
Grey: 34.3
Salmon: 7.9

第四行告诉你每种颜色的像素数量,比如67,000个白色像素,52,578个绿色像素,等等。

撰写回答