1

I use Floyd-Steinberg dithering in order to diffuse the quantization error after processing an image with KMeans from scipy. The given data is RGB file - both for grayscale and color. The problem is the visualisation - I get no dithering.

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

im = Image.open('file.png').convert('RGB')
pic = np.array(im, dtype = np.float)/255
im.close()

I would like to omit the KMeans part and focus on Floyd-Steinberg:

"""pic - as above, original array; image - processed image"""

def dither(pic, image):
    v, c, s = pic.shape
    Floyd = np.copy(image)
    for i in range(1, v-1):
        for j in range(1, c-1):
            quan = pic[i][j] - image[i][j] #Quantization error
            Floyd[i][j + 1] = quan * (np.float(7 / 16)) + Floyd[i][j + 1]
            Floyd[i + 1][j - 1] = quan * (np.float(3 / 16)) + Floyd[i + 1][j - 1]
            Floyd[i + 1][j] = quan * (np.float(5 / 16)) + Floyd[i + 1][j]
            Floyd[i + 1][j + 1] = quan * (np.float(1 / 16)) + Floyd[i + 1][j + 1]
    return Floyd

Floyd = dither(pic, image)

plt.imshow(Floyd)
plt.show()

I receive a little dithering when I replace Floyd with pic, i.e. Floyd[i + 1][j] = quan * (np.float(5 / 16)) + pic[i + 1][j]. However, this is improper code! Additionally, I have to deal with colours out of the clusters, thus I again assess the new pixels to clusters. How can I make it work? Where is THIS crucial mistake?

fgh
  • 169
  • 1
  • 3
  • 15
  • What is `image`? How did you process that? You have a fundamental misunderstanding of the process. You should have only one image: you modify the input grey-value image, setting each pixel to either 0 or 1, and spreading the difference with the original value to the next pixels still to be processed. That means that your algorithm should only read from `Floyd`, not from `image` or `pic`. And `Floyd` should be a copy of `pic`, the original image. – Cris Luengo Apr 26 '19 at 22:12
  • Thank you for your answer. I managed to improve the code and would like to post it as an aswer. However, due to some circumstances I can sit to this only on Monday. Although I had corrected the mistakes before I read your hint, I regard your comment as very useful. I wish I read about those fundamental misunderstandings three days ago, when I started the fight with the code... – fgh Apr 26 '19 at 22:57

1 Answers1

0
from PIL import Image
import cv2
import numpy as np

##################################################### Solution 1 ##############################################################

#PIL.Image.convert parametrs :
#https://pillow.readthedocs.io/en/4.2.x/reference/Image.html?highlight=image.convert#PIL.Image.Image.convert


#PIL.Image.convert Modes :
#https://pillow.readthedocs.io/en/4.2.x/handbook/concepts.html#concept-modes


#image convert to 1-bit pixels, black and white, stored with one pixel per byte and Dithering
imageConvert = Image.open('Image.PNG').convert(mode='1',dither=Image.FLOYDSTEINBERG)
imageConvert.save('DitheringWithPIL.png')


##################################################### Solution 2 ##############################################################


Image = cv2.imread('Image.PNG')

GrayImage = cv2.cvtColor(Image, cv2.COLOR_BGR2GRAY)
cv2.imwrite('GracyImage.PNG', GrayImage)

Height = GrayImage.shape[0]
Width = GrayImage.shape[1]

for y in range(0, Height):
    for x in range(0, Width):

        old_value = GrayImage[y, x]
        new_value = 0
        if (old_value > 128) :
            new_value = 255

        GrayImage[y, x] = new_value

        Error = old_value - new_value

        if (x<Width-1):
            NewNumber = GrayImage[y, x+1] + Error * 7 / 16
            if (NewNumber>255) : NewNumber=255
            elif (NewNumber<0) : NewNumber=0
            GrayImage[y, x+1] = NewNumber

        if (x>0 and y<Height-1):
            NewNumber = GrayImage[y+1, x-1] + Error * 3 / 16
            if (NewNumber>255) : NewNumber=255
            elif (NewNumber<0) : NewNumber=0
            GrayImage[y+1, x-1] = NewNumber

        if (y<Height-1):
            NewNumber= GrayImage[y+1, x] + Error * 5 / 16
            if (NewNumber>255) : NewNumber=255
            elif (NewNumber<0) : NewNumber=0
            GrayImage[y+1, x] = NewNumber

        if (y<Height-1 and x<Width-1):
            NewNumber = GrayImage[y+1, x+1] + Error * 1 / 16
            if (NewNumber>255) : NewNumber=255
            elif (NewNumber<0) : NewNumber=0
            GrayImage[y+1, x+1] = NewNumber

cv2.imwrite('DitheringWithAlgorithm.PNG', GrayImage)
sinasho
  • 180
  • 2
  • 6
  • 2
    Please put your answer always in context instead of just pasting code. See [here](https://stackoverflow.com/help/how-to-answer) for more details. – gehbiszumeis Nov 27 '19 at 12:15