python एक लेबल की गई छवि को{लेबल:[निर्देशांक]} के शब्दकोश में बदलने के लिए तेज़ तरीका




numpy image-processing (4)

कहते हैं कि मैंने एक छवि को एसिप्सी.एंडिंज़.मैपरमेंट.लैबिल के साथ लेबल किया है जैसे:

[[0, 1, 0, 0, 0, 0],
 [0, 1, 0, 0, 0, 0],
 [0, 1, 0, 0, 0, 0],
 [0, 0, 0, 0, 3, 0],
 [2, 2, 0, 0, 0, 0],
 [2, 2, 0, 0, 0, 0]]

प्रत्येक लेबल से संबंधित निर्देशांक एकत्र करने का एक तेज़ तरीका क्या है? जैसे कुछ:

{ 1: [[0, 1], [1, 1], [2, 1]],
  2: [[4, 0], [4, 1], [5, 0], [5, 1]],
  3: [[3, 4]] }

मैं उन छवियों के साथ काम कर रहा हूं जो आकार में ~ 15,000 x 5000 पिक्सल हैं, और प्रत्येक छवि के पिक्सल का लगभग आधा लेबल (यानी गैर-शून्य) है।

nditer साथ पूरी छवि के nditer , क्या प्रत्येक लेबल के लिए np.where(img == label) तरह कुछ करना तेज होगा?

संपादित करें:

कौन सा एल्गोरिदम सबसे तेज़ है, इस पर निर्भर करता है कि लेबल वाली छवि कितनी बड़ी है, इसकी तुलना में कितने लेबल हैं। वॉरेन वेकसेर और सल्वाडोर डाली / बीएचएटीआर आईआरएसएचएडी के तरीकों (जो np.nonzero और np.where np.nonzero पर आधारित हैं) सभी लेबल्स की संख्या के साथ रैखिक रूप से पैमाने पर दिखते हैं, जबकि nditer साथ प्रत्येक छवि तत्व के माध्यम से nditer स्पष्ट रूप से लेबल छवि के आकार के साथ रैखिक रूप से तराजू ।

एक छोटे से परीक्षण के परिणाम:

size: 1000 x 1000, num_labels: 10
weckesser ... 0.214357852936s 
dali ... 0.650229930878s 
nditer ... 6.53645992279s 


size: 1000 x 1000, num_labels: 100
weckesser ... 0.936990022659s 
dali ... 1.33582305908s 
nditer ... 6.81486487389s 


size: 1000 x 1000, num_labels: 1000
weckesser ... 8.43906402588s 
dali ... 9.81333303452s 
nditer ... 7.47897100449s 


size: 1000 x 1000, num_labels: 10000
weckesser ... 100.405524015s 
dali ... 118.17239809s 
nditer ... 9.14583897591s

तो सवाल अधिक विशिष्ट हो जाता है:

लेबल वाली छवियों के लिए जिसमें लेबल की संख्या sqrt(size(image)) के क्रम पर होती है sqrt(size(image)) क्या लेबल निर्देशांक इकट्ठा करने के लिए कोई एल्गोरिथ्म होता है जो प्रत्येक छवि तत्व (जैसे nditer साथ) के मुकाबले तेज गति से होता है?


यह मूल रूप से वांछित प्रारूप प्राप्त करने के लिए कुछ अतिरिक्त कार्य के साथ एक argsort संचालन है:

def sorting_based(img, nlabels):
    img_flat = img.ravel()

    label_counts = np.bincount(img_flat)
    lin_idx = np.argsort(img_flat)[label_counts[0]:]
    coor = np.column_stack(np.unravel_index(lin_idx, img.shape))

    ptr = np.cumsum(label_counts[1:-1])
    out = dict(enumerate(np.split(coor, ptr), start=1))

    return out

जैसा कि आपने पता लगाया है, प्रत्येक लेबल परिणामों के लिए np.where(img == label) को np.where(img == label) रनटाइम O(m*n) , m=n_pixels और n=n_labels । सॉर्टिंग आधारित दृष्टिकोण O(m*log(m) + n) को जटिलता कम कर देता है।

रैखिक समय में यह ऑपरेशन करना संभव है, लेकिन मुझे नहीं लगता कि नम्पी के साथ वेक्टर बनाना संभव है। आप इस उत्तर की तरह scipy.sparse.csr_matrix दुरुपयोग कर सकते हैं, लेकिन उस समय आप शायद कोड लिखने से बेहतर हैं जो वास्तव में समझ में आता है, Numba, Cython, आदि में।


इसे इस्तेमाल करे:

>>> z
array([[0, 1, 0, 0, 0, 0],
       [0, 1, 0, 0, 0, 0],
       [0, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 3, 0],
       [2, 2, 0, 0, 0, 0],
       [2, 2, 0, 0, 0, 0]])
>>> {i:zip(*np.where(z==i)) for i in np.unique(z) if i}
{1: [(0, 1), (1, 1), (2, 1)], 2: [(4, 0), (4, 1), (5, 0), (5, 1)], 3: [(3, 4)]}

यहाँ एक संभावना है:

import numpy as np

a = np.array([[0, 1, 0, 0, 0, 0],
              [0, 1, 0, 0, 0, 0],
              [0, 1, 0, 0, 0, 0],
              [0, 0, 0, 0, 3, 0],
              [2, 2, 0, 0, 0, 0],
              [2, 2, 0, 0, 0, 0]])

# If the array was computed using scipy.ndimage.measurements.label, you
# already know how many labels there are.
num_labels = 3

nz = np.nonzero(a)
coords = np.column_stack(nz)
nzvals = a[nz[0], nz[1]]
res = {k:coords[nzvals == k] for k in range(1, num_labels + 1)}

मैंने इस स्क्रिप्ट को get_label_indices.py कहा है यहां एक नमूना चलाया गया है:

In [97]: import pprint

In [98]: run get_label_indices.py

In [99]: pprint.pprint(res)
{1: array([[0, 1],
       [1, 1],
       [2, 1]]),
 2: array([[4, 0],
       [4, 1],
       [5, 0],
       [5, 1]]),
 3: array([[3, 4]])}

आप ऐसा कुछ कर सकते हैं (आईएमजी आपका मूल एनडी.रात्र है)

res = {}
for i in np.unique(img)[1:]:
  x, y = np.where(a == i)
  res[i] = zip(list(x), list(y))

जो आपको वांछित करेगा जो आपको चाहिए:

{
 1: [(0, 1), (1, 1), (2, 1)],
 2: [(4, 0), (4, 1), (5, 0), (5, 1)],
 3: [(3, 4)]
}

चाहे वह तेज़ हो - बेंचमार्क निर्धारित करने के लिए है

प्रति वॉरेन के सुझाव, मुझे अनूठे उपयोग करने की आवश्यकता नहीं है और बस ऐसा कर सकते हैं

res = {}
for i in range(1, num_labels + 1)
    x, y = np.where(a == i)
    res[i] = zip(list(x), list(y))






scipy