-1

I want to divide a picture in equally big squares and measure the average gray scale level and replace it with a blob, aka halftoning. This code gives me a picture but it doesn't look right. Any ideas what could be wrong?

im = scipy.misc.imread("uggla.tif")

def halftoning(im):
    im = im.astype('float64')
    width,height = im.shape
    halftone_pic = np.zeros((width, height))
    for x in range(width):
        for y in range(height):
            floating_matrix = im[x:x + 1, y:y + 1]
            sum = np.sum(floating_matrix)
            mean = np.mean(sum)
            round = (mean > 128) * 255
            halftone_pic[x,y] = round
    fig, ax = plt.subplots(1,2)
    ax[0].imshow(im, cmap="gray")
    ax[1].imshow(halftone_pic, cmap="gray")
    plt.show()
martineau
  • 119,623
  • 25
  • 170
  • 301
Emiki
  • 11
  • 3
  • 1
    You asked the very same question yesterday. It was put on hold for a reason. Why don't you work on your question instead of posting it again? https://stackoverflow.com/questions/47821117/how-to-convert-a-grayscale-image-into-a-halftoned-one – Mr. T Dec 15 '17 at 09:46
  • Oh, I see, @martineau suggested to ask the question again. – Mr. T Dec 15 '17 at 09:48
  • 1
    @Piinthesky. I'm pretty sure this is not what he had in mind – Mad Physicist Dec 15 '17 at 13:42
  • 1
    OP, if you want help, you need to learn how to ask properly. A code dump with "fix this" is not a proper question. Provide samples of the inputs and the outputs. Explain why the outputs differ from what you want. Explain what you did to solve the problem even if it didn't work. Show effort. A good question should generally provide enough information for someone to reproduce your problem locally with just copy and paste from this page. – Mad Physicist Dec 15 '17 at 13:46
  • I am trying the best I can @MadPhysicist, if you don't know how to help me then please don't visit my questions. – Emiki Dec 15 '17 at 14:16
  • 2
    @Emiki. I *am* helping you. I have given you clear instructions on how to post a question that will not get shut down in minutes. If you put a little more work into this, you can turn it into a very decent question. I am visiting your question because I think that the subject is interesting and the question has potential. – Mad Physicist Dec 15 '17 at 14:26
  • 1
    What is your quantification of "doesn't look right"? – Jongware Dec 15 '17 at 14:37
  • @MadPhysicist: I told the OP to ask a new question even though they had edited their original enough to reopen it IMO (but I doubted that was likely going to occur). – martineau Dec 15 '17 at 14:49
  • 1
    @martineau. Very nice answer. I still think OP needs to learn how to ask a good question though. – Mad Physicist Dec 15 '17 at 14:53
  • @MadPhysicist: Thanks for going along with the re-opening ploy. I totally agree that the OP needs to greatly improve their stackoverflow question-asking skills. – martineau Dec 15 '17 at 15:00

1 Answers1

3

Here's something that does what you want. It's essentially a simplification of the code in the accepted answer to the related question How to create CMYK halftone Images from a color image?:

from PIL import Image, ImageDraw, ImageStat

# Adaption of answer https://stackoverflow.com/a/10575940/355230
def halftone(img, sample, scale, angle=45):
    ''' Returns a halftone image created from the given input image `img`.
    `sample` (in pixels), determines the sample box size from the original
    image. The maximum output dot diameter is given by `sample` * `scale`
    (which is also the number of possible dot sizes). So `sample` == 1 will
    preserve the original image resolution, but `scale` must be > 1 to allow
    variations in dot size.
    '''
    img_grey = img.convert('L')  # Convert to greyscale.
    channel = img_grey.split()[0]  # Get grey pixels.
    channel = channel.rotate(angle, expand=1)
    size = channel.size[0]*scale, channel.size[1]*scale

    bitmap = Image.new('1', size)
    draw = ImageDraw.Draw(bitmap)

    for x in range(0, channel.size[0], sample):
        for y in range(0, channel.size[1], sample):
            box = channel.crop((x, y, x+sample, y+sample))
            mean = ImageStat.Stat(box).mean[0]
            diameter = (mean/255) ** 0.5
            edge = 0.5 * (1-diameter)
            x_pos, y_pos = (x+edge) * scale, (y+edge) * scale
            box_edge = sample * diameter * scale
            draw.ellipse((x_pos, y_pos, x_pos+box_edge, y_pos+box_edge),
                         fill=255)

    bitmap = bitmap.rotate(-angle, expand=1)
    width_half, height_half = bitmap.size
    xx = (width_half - img.size[0]*scale) / 2
    yy = (height_half - img.size[1]*scale) / 2
    bitmap = bitmap.crop((xx, yy, xx + img.size[0]*scale,
                                  yy + img.size[1]*scale))
    return Image.merge('1', [bitmap])

# Sample usage

img = Image.open('uggla.tif')
img_ht = halftone(img, 8, 1)
img_ht.show()

Here's the results from using this as the input image:

input image

Halftoned result produced:

Halftoned result

martineau
  • 119,623
  • 25
  • 170
  • 301
  • @MadPhysicist: Nice of you to say so. The effect is even better on higher resolution images—I just used a relatively low-res one for testing and development (and uploading here) purposes. – martineau Dec 15 '17 at 14:57