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.
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.