Ausgabe
Ich versuche gerade, einen Weg zu finden, farbige Farbfelder zu zählen. Sie sind alle regelmäßig, gleich groß, in einem Schachbrettmuster angeordnet, Farben variieren. Die Anzahl der Muster variiert von einigen Hundert bis zu etwa 90.000.
In diesem Beispiel mit nur drei Farben brauche ich es, um die Anzahl der hellgrünen Quadrate = 8 zu zählen
In Photoshop kann ich ein Muster von jedem Farbfeld nehmen, wobei x, y die Mitte des Farbfelds sind und colArr ein Array aller RGB-Werte dieser Farbfelder ist.
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();
}
Wenn die Farbe mit einer in einem zuvor festgelegten Array übereinstimmt, wird sie gezählt.
Es klappt! Es ist ziemlich augenblicklich für kleine Proben. Bei einem Bild von über 3000 Proben dauert es jedoch etwa 25 Sekunden. Während ich zufrieden bin zu wissen, dass das Bild verarbeitet wurde, bin ich neugierig, ob es schneller geht.
Meine Frage lautet: Könnte dies beschleunigt werden, indem beispielsweise Python verwendet wird, aber wie?
Lösung
Die Details dessen, was Sie fragen, sind mir noch nicht ganz klar – ob die Quadrate in jedem Bild immer gleich groß sind, ob Sie im Voraus wissen, wie viele in einem bestimmten Bild sind, ob sie immer quadratisch sind (Sie beschreiben sie als “normal” ) und ob Sie tatsächlich mehr als eine Farbe in jedem Bild zählen möchten – Ihr Beispiel ist “hellgrün” , aber Sie scheinen ein Array “zuvor festgelegte Farben” zu haben, sodass es nicht klar ist, ob Sie es wissen möchten wie viele Pixel von jeder Farbe in diesem Array sind.
Wie auch immer, lassen Sie uns einen ersten Versuch unternehmen, eine Antwort zu finden, indem wir OpenCV und grundlegende Numpy-Indizierung verwenden, um die Zentren zu erhalten.
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]
Das gibt uns dieses Array der Größe [4,6,3], weil Numpy-Arrays [Höhe, Breite, Kanäle] sind und wir 4 Swatch-Zentren vertikal, 6 Swatch-Zentren horizontal haben und jedes 3 Farben hat.
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)
Falls Sie mit der Numpy-Indizierung nicht vertraut sind, ist es im Grunde genommen:
array[start:end:stride]
Im obigen Code beginne ich also mit einer halben Farbfeldbreite im Array (um zur Mitte des ersten Farbfelds zu gelangen) und verwende dann einen Schritt, der der Farbfeldbreite entspricht, um zur nächsten Mitte zu gelangen.
Wenn Sie jetzt die Anzahl der Farbfeldzentren mit Farbe [141,244,159] zählen möchten, können Sie Folgendes tun:
tally = np.sum(np.all(centres==[141,244,159], axis=-1))
was das Ergebnis liefert 8
.
Beachten Sie, dass Sie dies alles mit Python Imaging Library PIL/Pillow tun können, wenn dies eine einfachere Installation für Sie ist, indem Sie Folgendes ersetzen:
import cv2
im = cv2.imread(...)
mit:
from PIL import Image
# Open PIL Image and make into Numpy array
im = np.array(Image.open(...).convert('RGB'))
und bedenken Sie, dass OpenCV die BGR-Reihenfolge verwendet, während PIL RGB verwendet, sodass die gesuchten Farbtripletts umgekehrt werden.
Ich habe ein Beispielbild mit 90.000 Farbfeldern von 10 x 10 Pixeln mit 1.000 einzigartigen Farben wie folgt erstellt:
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)
Ich habe es dann zeitlich festgelegt und 1,9 ms bekommen und es hat 83 Farbfelder mit Farbe [0, 78, 156] gefunden, was Sie bei 90.000 Farbfeldern mit 1.000 Farben erwarten würden:
%%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)
Beantwortet von – Mark Setchell
Antwort geprüft von – Dawn Plyler (FixError Volunteer)