2013-01-22 30 views
10

के साथ प्रदर्शन के लिए 16-बिट छवि डेटा को कुशलतापूर्वक परिवर्तित करने के लिए numpy का उपयोग करके, मैं अक्सर 16-बिट ग्रेस्केल छवि डेटा को प्रदर्शित करने के लिए 8-बिट छवि डेटा में परिवर्तित करता हूं। छवि के 'दिलचस्प' हिस्सों को हाइलाइट करने के लिए न्यूनतम और अधिकतम प्रदर्शन तीव्रता समायोजित करने के लिए लगभग हमेशा उपयोगी होता है।तीव्रता स्केलिंग

नीचे दिया गया कोड लगभग वही है जो मैं चाहता हूं, लेकिन यह बदसूरत और अक्षम है, और छवि डेटा की कई मध्यवर्ती प्रतियां बनाता है। मैं न्यूनतम मेमोरी पदचिह्न और प्रसंस्करण समय के साथ एक ही परिणाम कैसे प्राप्त कर सकता हूं?

import numpy 

image_data = numpy.random.randint(#Realistic images would be much larger 
    low=100, high=14000, size=(1, 5, 5)).astype(numpy.uint16) 

display_min = 1000 
display_max = 10000.0 

print(image_data) 
threshold_image = ((image_data.astype(float) - display_min) * 
        (image_data > display_min)) 
print(threshold_image) 
scaled_image = (threshold_image * (255./(display_max - display_min))) 
scaled_image[scaled_image > 255] = 255 
print(scaled_image) 
display_this_image = scaled_image.astype(numpy.uint8) 
print(display_this_image) 

उत्तर

13

आप क्या कर रहे हैं halftoning आपकी छवि है।

दूसरों द्वारा प्रस्तावित विधियां बहुत बढ़िया काम करती हैं, लेकिन वे बार-बार बहुत सारी महंगी गणनाएं दोहरा रही हैं। चूंकि uint16 में सबसे अधिक 65,536 अलग-अलग मान हैं, एक लुक-अप तालिका (LUT) का उपयोग करके चीजों को व्यवस्थित कर सकते हैं। और चूंकि एलयूटी छोटा है, इसलिए आपको चीजों को करने के बारे में ज्यादा चिंता करने की ज़रूरत नहीं है, या बूलियन सरणी नहीं बना रही है। निम्नलिखित कोड द्वि रिको के समारोह पुनः उपयोग कर लेता LUT बनाने के लिए:

import numpy as np 
import timeit 

rows, cols = 768, 1024 
image = np.random.randint(100, 14000, 
          size=(1, rows, cols)).astype(np.uint16) 
display_min = 1000 
display_max = 10000 

def display(image, display_min, display_max): # copied from Bi Rico 
    # Here I set copy=True in order to ensure the original image is not 
    # modified. If you don't mind modifying the original image, you can 
    # set copy=False or skip this step. 
    image = np.array(image, copy=True) 
    image.clip(display_min, display_max, out=image) 
    image -= display_min 
    np.floor_divide(image, (display_max - display_min + 1)/256, 
        out=image, casting='unsafe') 
    return image.astype(np.uint8) 

def lut_display(image, display_min, display_max) : 
    lut = np.arange(2**16, dtype='uint16') 
    lut = display(lut, display_min, display_max) 
    return np.take(lut, image) 


>>> np.all(display(image, display_min, display_max) == 
      lut_display(image, display_min, display_max)) 
True 
>>> timeit.timeit('display(image, display_min, display_max)', 
        'from __main__ import display, image, display_min, display_max', 
        number=10) 
0.304813282062 
>>> timeit.timeit('lut_display(image, display_min, display_max)', 
        'from __main__ import lut_display, image, display_min, display_max', 
        number=10) 
0.0591987428298 

तो वहाँ एक x5 गति-अप है, जो एक बुरी बात, मुझे लगता है नहीं है ...

+1

बहुत अच्छा! यह ऐसी चीज है जो मैं अपने साथ नहीं आती थी। – Andrew

+0

सुंदर और सुरुचिपूर्ण समाधान! – RockJake28

2

स्मृति के उपयोग को कम करने, यथा-स्थान कतरन करते हैं और बूलियन सरणियों बनाने से बचने के लिए।

dataf = image_data.astype(float) 
numpy.clip(dataf, display_min, display_max, out=dataf) 
dataf -= display_min 
datab = ((255./(display_max - display_min)) * dataf).astype(numpy.uint8) 

यदि आप पूर्णांक मूल्यों के रूप में अपने कतरन सीमाओं का ध्यान रखें, आप बारी-बारी से कर सकते हैं:

numpy.clip(image_data, display_min, display_max, out=image_data) 
image_data-= display_min 
datab = numpy.empty_like(image_data) 
numpy.multiply(255./(display_max - display_min), image_data, out=datab) 

नोट: कि एक अस्थायी नाव सरणी अभी भी अंतिम पंक्ति में बनाया जाएगा से पहले uint8 सरणी है बनाया था।

+0

अच्छा! मुझे 'क्लिप' के बारे में पता नहीं था। – Andrew

+0

मुझे आश्चर्य है कि 'numpy.multiply' का उपयोग' out' तर्क के साथ image_data पर सेट समान रूप से काम करता है? मुझे पता है कि यह एक uint16 सरणी में फ्लोट डेटा लिखने की कोशिश कर रहा है, लेकिन हो सकता है कि हम वही हो जो हम चाहते हैं? – Andrew

+0

विचार, फ़्लोट सरणी को खत्म करने के लिए। – Andrew

2

मैं छवि कास्टिंग फ्लोट करने से बच जाएंगे, तो आप कुछ कर सकते हैं की तरह:

import numpy as np 

def display(image, display_min, display_max): 
    # Here I set copy=True in order to ensure the original image is not 
    # modified. If you don't mind modifying the original image, you can 
    # set copy=False or skip this step. 
    image = np.array(image, copy=True) 

    image.clip(display_min, display_max, out=image) 
    image -= display_min 
    image //= (display_min - display_max + 1)/256. 
    image = image.astype(np.uint8) 
    # Display image 

यहाँ छवि के एक वैकल्पिक कॉपी में यह देशी डेटा प्रकार है बना है और एक 8 बिट प्रति पिछले पर बना है लाइन।