Pixel-szintű módosítás és LUT

Lényege

Minden pixelen a program végrehajt egy műveletet, és közben nem veszi figyelembe egyik szomszédos pixel értékét sem. Egyszerűbb módosításokra alkalmas, gyorsan lefut, de komplexebb műveletekre, mint például a zajszűrés, elmosás vagy élesítés már alkalmatlan, mivel ezekhez ismerni kell a környező képpontokat.

Fényerő, Kontraszt

Ha egy kép minden pixeljének értékét növeljük egy konstans értékkel, akkor nő a fényereje, ezáltal a konstans érték kivonásával a fényerő csökken. A kontraszt a kép legsötétebb és legvilágosabb pontjainak különbsége, szorzás művelettel módosítható. A képlet kivonást is tartalmaz, kompenzálni kell a fényerő változtatását.

Grayscale átalakítás

Színes képek szürkeárnyalatossá alakítására több módszer létezik, például a három színcsatorna értékének átlagolása. Általában azonban adott számokkal szorozzák minden csatorna értékét. Minden új pixel az eredeti képpont, mint vektor és egy másik, szabvány által meghatározott vektor skaláris szorzatából keletkezik.

A Rec.709 szabvány szerint:

$ 0.2126 ⋅ R + 0.7152 ⋅ G + 0.0722 ⋅ B $

Lookup Table (LUT)

Nagyon gyors módja a pixel-szintű módosításoknak a Lookup Table, röviden LUT alkalmazása. Ekkor egy listát kell készíteni, amelyben az összes lehetséges érték fel van sorolva adott bitmélységen. Ezek mindegyikéhez az új érték is felkerül a listára, így a számítógépnek nem kell számításokat végezni, csupán kikeresni az új értékét az adott pixelnek. Széles körben használják filmek fényelésekor, szinusz értékek tárolására, stb.

Segédlet

Boglárka fénykép: Letöltés

Forráskód: Fényerő, Kontraszt

        
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

# Open the image using PIL
image = Image.open("path-to-resources/boglarka.jpg")

# Convert image to a NumPy array
data = np.array(image, dtype=np.uint8)
print(data.shape)  # (height, width, channels)

# Set brightness and contrast
brightness = 25  # [-127;127] where 0 means unchanged
contrast = 75    # [-127;127] where 0 means unchanged

# Extend data type to potential negative values (will be converted back later)
data = np.int16(data) # 16 bit integer
# Perform the modification
data = data * (contrast / 127 + 1) - contrast + brightness
# Clip values between 0 and 255 (<= 0 to 0 and >= 255 to 255)
data = np.clip(data, 0, 255)
# Convert back to 8 bit unsigned integer
final_image = np.uint8(data)

# Display the image
plt.imshow(final_image)
plt.axis('off')
plt.show()
          
        

Forráskód: Szürkeárnyalat

        
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

# Open the image using PIL and ensure the correct (RGB) color mode
image = Image.open("path-to-resources/boglarka.jpg").convert("RGB")

# Convert image to a NumPy array
data = np.array(image, dtype=np.uint8)
print(data.shape)  # (height, width, channels)

# RGB array for the conversion (Rec.709 standard)
conv_arr = [0.2126, 0.7152, 0.0722] # R, G, B

# Perform the conversion
final_image = np.dot(data, conv_arr).astype(np.uint8)

# Display the image
plt.imshow(final_image, cmap="gray")
plt.axis('off')
plt.show()
          
        

Forráskód: LUT

        
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from timeit import default_timer as timer

# Open the image using PIL and convert to grayscale
image = Image.open("path-to-resources/boglarka.jpg").convert("L")

# Convert image to a NumPy array
data = np.array(image, dtype=np.uint8)
print(data.shape)  # (height, width, channels)

# Set brightness and contrast
brightness = 25  # [-127;127] where 0 means unchanged
contrast = 75    # [-127;127] where 0 means unchanged

# Build a grayscale LUT
myLUT = np.zeros(256, dtype = np.uint8)
for li in range(255):
    myLUT[li]= np.clip(li * (contrast / 127 + 1) - contrast + brightness, 0, 255)

# Measure execution time of applying the LUT
start1 = timer()
# Apply the LUT
final_image1 = myLUT[data]
# End timer
end1 = timer()

# Measure execution time of basic processing
start2 = timer()
# Change brigtness and contrast with the usual method
final_image2 = np.clip(data * (contrast / 127 + 1) - contrast + brightness, 0, 255)
final_image2 = np.uint8(final_image2)
# End timer
end2 = timer()

print(f"Basic method: {round((end2 - start2) * 1000, 3)}ms")
print(f"Using a LUT: {round((end1 - start1) * 1000, 3)}ms")

# Display images
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].imshow(final_image1, cmap="gray")
ax[0].set_title("LUT-applied Image")
ax[0].axis("off")
ax[1].imshow(final_image2, cmap="gray")
ax[1].set_title("Basic Processing Image")
ax[1].axis("off")
plt.show()