Python ve OpenCV ile Floyd–Steinberg Dithering İşlemi Algoritması

0 802

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.

Python ve OpenCV ile Floyd–Steinberg Dithering İşlemi Algoritması 1
Orjinal Resim
Floyd–Steinberg dithering işlemi
Renklerin Azaltılmış Resim
Floyd–Steinberg dithering işlemi
Floyd–Steinberg dithering işlemi uygulanmış resim

Ü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ı

python opencv elastik resim elde etme
orjinal resim
Dithering İşlemi Uygulanmış Resim dithering_gray Fonksiyonu Uygulanmış Resim
Dithering İşlemi Uygulanmış Resim dithering_color Fonksiyonu Uygulanmış Resim

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.

Cevap bırakın

E-posta hesabınız yayımlanmayacak.

Bu web sitesi deneyiminizi geliştirmek için çerezleri kullanır. Bununla iyi olduğunuzu varsayacağız, ancak isterseniz vazgeçebilirsiniz. Kabul etmek Mesajları Oku