Python ve OpenCV ile Floyd–Steinberg Dithering İşlemi Algoritması
Bu yazımızda Python ve OpenCV ile Floyd–Steinberg Dithering İşlemi Algoritmasına örnek bir kod paylaşıyoruz.
İçerik Tablosu
Floyd-Steinberg Dithering Algoritması Nedir?
Floyd – Steinberg titreme , ilk olarak 1976’da Robert W. Floyd ve Louis Steinberg tarafından yayınlanan bir görüntü dithering algoritmasıdır . Görüntü işleme yazılımı tarafından yaygın olarak kullanılır, örneğin bir görüntü maksimum 256 renkle sınırlandırılmış GIF formatına dönüştürüldüğünde resmin renklerinin azaltılması işleminde resmin bozulmasını engeller.



Üstteki 3 resimde de örneğini gördüğünüz gibi bu dithering algoritaması sayesinde renklerin azaltılması resmin bozulmasını en aza indiriyor.
Algoritma , hata yayılımı kullanarak renk taklidi gerçekleştirir , yani daha sonra ele alınmak üzere bir pikselin kalan nicemleme hatasını komşu piksellerine iter (ekler) . Borçları dağılımına göre (komşu piksellerin haritası olarak gösterilir) dağıtır.
Dithering bilgisayarda olmayan bir rengi 2 veya daha fazla pixeli yan yana getirerek yaratmaya çalışmaktır. Az renk kullanmak zorunda kaldığımız ekran modlarinda kaçınılmazdır.
Bu algoritmayla ilgili olarak temel konuları alttaki videodan izleyebilirsiniz.
Dithering Algoritması Videosu
Python ve OpenCV ile Dithering Algoritması
import cv2
import numpy as np
def minmax(v):
if v > 255:
v = 255
if v < 0:
v = 0
return v
def dithering_gray(inMat, samplingF):
#https://en.wikipedia.org/wiki/Floyd–Steinberg_dithering
#https://www.youtube.com/watch?v=0L2n8Tg2FwI&t=0s&list=WL&index=151
#input is supposed as color
# grab the image dimensions
h = inMat.shape[0]
w = inMat.shape[1]
# loop over the image
for y in range(0, h-1):
for x in range(1, w-1):
# threshold the pixel
old_p = inMat[y, x]
new_p = np.round(samplingF * old_p/255.0) * (255/samplingF)
inMat[y, x] = new_p
quant_error_p = old_p - new_p
# inMat[y, x+1] = minmax(inMat[y, x+1] + quant_error_p * 7 / 16.0)
# inMat[y+1, x-1] = minmax(inMat[y+1, x-1] + quant_error_p * 3 / 16.0)
# inMat[y+1, x] = minmax(inMat[y+1, x] + quant_error_p * 5 / 16.0)
# inMat[y+1, x+1] = minmax(inMat[y+1, x+1] + quant_error_p * 1 / 16.0)
inMat[y, x+1] = minmax(inMat[y, x+1] + quant_error_p * 7 / 16.0)
inMat[y+1, x-1] = minmax(inMat[y+1, x-1] + quant_error_p * 3 / 16.0)
inMat[y+1, x] = minmax(inMat[y+1, x] + quant_error_p * 5 / 16.0)
inMat[y+1, x+1] = minmax(inMat[y+1, x+1] + quant_error_p * 1 / 16.0)
# quant_error := oldpixel - newpixel
# pixel[x + 1][y ] := pixel[x + 1][y ] + quant_error * 7 / 16
# pixel[x - 1][y + 1] := pixel[x - 1][y + 1] + quant_error * 3 / 16
# pixel[x ][y + 1] := pixel[x ][y + 1] + quant_error * 5 / 16
# pixel[x + 1][y + 1] := pixel[x + 1][y + 1] + quant_error * 1 / 16
# return the thresholded image
return inMat
def dithering_color(inMat, samplingF):
#https://en.wikipedia.org/wiki/Floyd–Steinberg_dithering
#https://www.youtube.com/watch?v=0L2n8Tg2FwI&t=0s&list=WL&index=151
#input is supposed as color
# grab the image dimensions
print("buraya geldik dithering_color")
h = inMat.shape[0]
w = inMat.shape[1]
# loop over the image
for y in range(0, h-1):
for x in range(1, w-1):
# threshold the pixel
old_b = inMat[y, x, 0]
old_g = inMat[y, x, 1]
old_r = inMat[y, x, 2]
new_b = np.round(samplingF * old_b/255.0) * (255/samplingF)
new_g = np.round(samplingF * old_g/255.0) * (255/samplingF)
new_r = np.round(samplingF * old_r/255.0) * (255/samplingF)
inMat[y, x, 0] = new_b
inMat[y, x, 1] = new_g
inMat[y, x, 2] = new_r
quant_error_b = old_b - new_b
quant_error_g = old_g - new_g
quant_error_r = old_r - new_r
inMat[y, x+1, 0] = minmax(inMat[y, x+1, 0] + quant_error_b * 7 / 16.0)
inMat[y, x+1, 1] = minmax(inMat[y, x+1, 1] + quant_error_g * 7 / 16.0)
inMat[y, x+1, 2] = minmax(inMat[y, x+1, 2] + quant_error_r * 7 / 16.0)
inMat[y+1, x-1, 0] = minmax(inMat[y+1, x-1, 0] + quant_error_b * 3 / 16.0)
inMat[y+1, x-1, 1] = minmax(inMat[y+1, x-1, 1] + quant_error_g * 3 / 16.0)
inMat[y+1, x-1, 2] = minmax(inMat[y+1, x-1, 2] + quant_error_r * 3 / 16.0)
inMat[y+1, x, 0] = minmax(inMat[y+1, x, 0] + quant_error_b * 5 / 16.0)
inMat[y+1, x, 1] = minmax(inMat[y+1, x, 1] + quant_error_g * 5 / 16.0)
inMat[y+1, x, 2] = minmax(inMat[y+1, x, 2] + quant_error_r * 5 / 16.0)
inMat[y+1, x+1, 0] = minmax(inMat[y+1, x+1, 0] + quant_error_b * 1 / 16.0)
inMat[y+1, x+1, 1] = minmax(inMat[y+1, x+1, 1] + quant_error_g * 1 / 16.0)
inMat[y+1, x+1, 2] = minmax(inMat[y+1, x+1, 2] + quant_error_r * 1 / 16.0)
# quant_error := oldpixel - newpixel
# pixel[x + 1][y ] := pixel[x + 1][y ] + quant_error * 7 / 16
# pixel[x - 1][y + 1] := pixel[x - 1][y + 1] + quant_error * 3 / 16
# pixel[x ][y + 1] := pixel[x ][y + 1] + quant_error * 5 / 16
# pixel[x + 1][y + 1] := pixel[x + 1][y + 1] + quant_error * 1 / 16
# return the thresholded image
return inMat
#İmaj dosyasının okunması
inMat = cv2.imread('imp-5013967_1920.jpg') #İşlem yapacağınız imaj dosyasının adını ve yolunu buraya yazıyorsunuz.
#Eğer imaj dosyasını klasörle aynı klasöre atarsanız sadece imaj dosyasının ismini yazmanı yeterli.
#color ditering
outMat_color = dithering_color(inMat.copy(), 1)
cv2.imwrite('out_color.jpg', outMat_color)
#gray ditering
grayMat = cv2.cvtColor(inMat, cv2.COLOR_BGR2GRAY)
outMat_gray = dithering_gray(grayMat.copy(), 1)
cv2.imwrite('out_gray.jpg', outMat_gray)
İşlem sonucunda 2 farklı resim dosyası kodun bulunduğu klasörde oluşacaktır.
Kullandığınız imaj dosyasına bağlı olarak işlem oldukça uzun sürüyor. Alttaki 1920×1080 boyutlarında ki resim dosyası yaklaşık 20 dakikada dönüşümünü tamamladı.
İşlem Sonuçları



Sitemizde Python ve OpenCV kullanarak hazırladığımız yüz tanıma uygulaması örneği ve farklı OpenCV örnek kodlarını bulabilirsiniz.
Python öğrenmek isteyenler için hazırladığımız Python derslerine de göz atabilirsiniz.
Yorumlarınız ve sorularınızı bizimle paylaşın.