计算彩色样本需要更快的方法

2024-03-29 06:39:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正试图找到一种计算彩色样本的方法。它们都是规则的,大小相同,排列成棋盘图案,颜色各异。样本数量将从几百个到大约90000个不等

swatch sample

在这个例子中,只有三种颜色,我需要它来计算浅绿色方块的数量=8

在Photoshop中,我可以对每个样例进行采样,其中x,y是样例的中心,colArr是这些样例的所有RGB值的数组

var pointSample = app.activeDocument.colorSamplers.add([x,y]);

// Obtain array of RGB values.
var rgb = [
  Math.round(pointSample.color.rgb.red,0),
  Math.round(pointSample.color.rgb.green,0),
  Math.round(pointSample.color.rgb.blue,0)
];

colArr.push(rgb);
delete_all_colour_samples();

function delete_all_colour_samples()
{
  app.activeDocument.colorSamplers.removeAll();
}

如果颜色与先前建立的数组中的颜色匹配,则会对其进行计数

它起作用了!对于小样本来说,这是相当即时的。然而,对于超过3000个样本的图像,它需要大约25秒。虽然我很高兴知道这个图像已经被处理过了,但我很好奇它是否可以做得更快

我的问题是:使用say-Python是否可以加快速度,但如何加快


Tags: app数量颜色varmathrgb数组color
2条回答

你所问的细节我还不太清楚——比如每幅图片中的正方形是否总是相同的大小,你是否事先知道给定图像中有多少个正方形,它们是否总是正方形(你将它们描述为“普通的”)以及你是否真的想在每张图像中计算一种以上的颜色-你的例子是“浅绿色”,但你似乎有一个数组“先前建立的颜色”,所以你不清楚你是否想知道该数组中每种颜色有多少像素

无论如何,让我们先尝试一下答案,使用OpenCV和基本Numpy索引来获得中心

import cv2
import numpy as np

# Load an image
im = cv2.imread('Qcza1.png')

# Assume the swatches are 64x64 pixels
sw, sh = 64, 64

# Get colours at each swatch centre, so we start 1/2 a swatch in and step by a whole swatch
centres = im[sh//2::sh, sw//2::sw]

这给了我们这个大小为[4,6,3]的数组,因为Numpy数组是[高度、宽度、通道],我们有4个垂直的样本中心,6个水平的样本中心,每个都有3种颜色

array([[[141, 244, 159],
    [ 85, 202, 105],
    [255, 255, 255],
    [ 85, 202, 105],
    [141, 244, 159],
    [ 85, 202, 105]],

   [[255, 255, 255],
    [141, 244, 159],
    [ 85, 202, 105],
    [141, 244, 159],
    [ 85, 202, 105],
    [141, 244, 159]],

   [[141, 244, 159],
    [ 85, 202, 105],
    [255, 255, 255],
    [ 85, 202, 105],
    [141, 244, 159],
    [255, 255, 255]],

   [[ 85, 202, 105],
    [141, 244, 159],
    [ 85, 202, 105],
    [255, 255, 255],
    [ 85, 202, 105],
    [255, 255, 255]]], dtype=uint8)

如果您不熟悉Numpy索引,它基本上是:

array[start:end:stride]

因此,在上面的代码中,我将从阵列的半个样本宽度开始(到达第一个样本的中心),然后使用等于样本宽度的步幅到达下一个中心

如果现在要统计具有颜色的样例中心的数量[141244159],可以执行以下操作:

tally = np.sum(np.all(centres==[141,244,159], axis=-1))

获取结果8


请注意,您可以使用Python Imaging LibraryPIL/Pillow来完成这一切,如果这对您来说更容易安装,请更换:

import cv2
im = cv2.imread(...)

与:

from PIL import Image

# Open PIL Image and make into Numpy array
im = np.array(Image.open(...).convert('RGB'))

请记住,OpenCV使用BGR排序,而PIL使用RGB,因此您要查找的三色组将被反转


我使用1000种独特的颜色生成了90000个10x10像素的样本图像,如下所示:

import cv2
import numpy as np

# Define 10 possible values for R, G and B
vals = np.arange(0,255,26)

# Make 90,000 pixel image using approx 10*10*10 = 1000 colours
h, w = 200, 450
np.random.seed(42)
im = np.random.choice(vals, (h,w,3)).astype(np.uint8)

# Scale up to make swatches 10x10
sw, sh = 10, 10
im = cv2.resize(im, (w*sw, h*sh), 0, 0, interpolation=cv2.INTER_NEAREST)

然后我计时,得到了1.9ms,它发现了83个颜色为[0,78,156]的样本,这是你期望的90000个1000种颜色的样本:

%%timeit
centres = im[sh//2::sh, sw//2::sw]
np.sum(np.all(centres==[0,78,156], axis=-1))

1.95 ms ± 30.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

要计算具有给定颜色的连续区域数,请执行以下操作:

  • 首先找出哪些像素具有该颜色
  • 然后使用连接组件分析来计算连续区域的数量

大多数图像处理库都具有轻松完成此任务所需的工具。例如,使用DIPlib(披露:我是一名作者)将是:

import diplib as dip

img = dip.ImageRead('Qcza1.png')

color = dip.Create0D([159,244,141])
squares = dip.AllTensorElements(img == color)
squares = dip.Label(squares, connectivity=1)
count = dip.Maximum(squares)[0][0]

对于OpenCV,它将是:

import cv2

img = cv2.imread('Qcza1.png')  # Uses BGR ordering!

color = (141,244,159)
squares = cv2.inRange(img, color, color)
count, squares = cv2.connectedComponents(squares, connectivity=4)
count = count - 1  # count included background label

这里有两件事可能出错:

  1. 颜色不精确(照明变化、压缩瑕疵等)。在这种情况下,您需要使用一系列颜色(dip.InRange(img, color1, color2)而不是img == colorcv2.inRange(img, color1, color2)

  2. 正方形并不像示例中那样完全分开。如果连接只发生在顶点,那么在标记之前对二进制squares图像进行一点侵蚀就可以解决这个问题。如果正方形可以并排排列,则需要一种更复杂的方法:我们将查看大小的直方图,期望看到单个正方形大小的第一个峰值,以及该大小倍数的进一步峰值。根据这个直方图,我们可以计算出有多少个正方形,方法是将2倍大小附近的箱子乘以2,3倍大小附近的箱子乘以3,等等,然后将我们的所有值相加

相关问题 更多 >