Creating a chessboard in PIL

2019-08-03 17:36发布

Background

I have been trying to create a chessboard in the PIL module and I have got the general pattern for the first two rows, but can't figure out how to apply this to the entire board. As you can see, I have created an image:

from PIL import Image

img = Image.new("RGB", (15,15), "white") # create a new 15x15 image
pixels = img.load() # create the pixel map

My solution for the first two rows

Note - I am still learning Python so this code may seem very inefficient, but feel free to suggest improvements.

The second row:

Code:

black_2 = []
for i in range(img.size[0]):
    if i % 2 == 0:
        black_2.append(i)

This gives me all the horizontal index positions on where to put a black pixel. Therefore, for the 15x15 board I created, it returns [0, 2, 4, 6, 8, 10, 12, 14]

The first row:

Code:

I then use the second row to work out the horizontal index positions for the first row

black_1 = [i-1 for i in black_2 if i > 0]
if img.size[0] % 2 == 0: # 'that' if statement
    black_1.append(img.size[0]-1)

For the 15x15 pixel board I created, it returns [1, 3, 5, 7, 9, 11, 13]. I created that if statement because I realised that the last black pixel was not showing if the board had an even length, and that seemed to fix it.

Changing the pixels to black:

# hardcoded to check patterns
for i in black_1:
    pixels[i,0] = (0,0,0)

for k in black_2:
    pixels[k,1] = (0,0,0)

img.show()

How can I apply both patterns to the rest of the board, regardless of its size?

I would suspect a for var in range() loop is needed, but I am not sure how it would change depending on if the height(img.size[1]) of the board is odd or even.

Overall pattern so far:

Chessboard

black_1 applies to first row

black_2 applies to second row

4条回答
做自己的国王
2楼-- · 2019-08-03 18:21

This is a simple way. In case it confuses you, one pixel in the image corresponds to a whole square of the chessboard and you can scale it up at the end if you want to.

#!/usr/bin/env python3

from PIL import Image

# Create new black image of entire board
w, h = 12, 6
img = Image.new("RGB", (w,h))
pixels = img.load()

# Make pixels white where (row+col) is odd
for i in range(w):
    for j in range(h):
        if (i+j)%2:
            pixels[i,j] = (255,255,255)

img.save('result.png')

If you want it to be a larger image, just resize at the end. So, say you want each square of the board to be 15px x 15px:

img = img.resize((15*w,15*h),PIL.Image.NEAREST)

enter image description here

查看更多
淡お忘
3楼-- · 2019-08-03 18:22

Solution:

Using numpy modul, its very fast and you have only 11 loops(also not looping through every pixel, but rather through patterns). It doesnt matter how big is the chessboard. Processing should be similary fast

timing: 2400 x 2400 pixel chessboard -> 0.17s

import numpy as np
from PIL import Image
n = 50 # size of one element, row = 8*n, chessboard = 8*n x 8*n

segment_black = np.zeros(shape = [n,n])
segment_white = np.ones(shape = [n,n])*255
chessboard = np.hstack((segment_black,segment_white))
for i in range(4):
    chessboard = np.hstack((chessboard,segment_black))
    chessboard = np.hstack((chessboard,segment_white))
temp = chessboard
for i in range(7):
    chessboard = np.concatenate((np.fliplr(chessboard),temp))
img = Image.fromarray(chessboard.astype(np.uint8))
img.save('chess.jpg')
img.show()
查看更多
对你真心纯属浪费
4楼-- · 2019-08-03 18:23

You could use PIL.Image.paste to paste img on itself.

for n in range(15/2):
    img.paste(img, (0, n*2))

Using all your existing code, just add this at the bottom.

查看更多
做个烂人
5楼-- · 2019-08-03 18:27

A chess board has 64 squares instead of 256. Firstly you need (8,8) and then you can use double for loops to assign the color to all the 8 rows.

General example for any size

from PIL import Image

size = 16
img = Image.new("RGB", (size,size), "white") # create a new 15x15 image
pixels = img.load() # create the pixel map

black_2 = []
for i in range(img.size[0]):
    if i % 2 == 0:
        black_2.append(i)

black_1 = [i-1 for i in black_2 if i > 0]
if img.size[0] % 2 == 0: # 'that' if statement
    black_1.append(img.size[0]-1)


for i in black_1:
    for j in range(0, size, 2):
        pixels[i,j] = (0,0,0)

for k in black_2:
    for l in range(1, size+1, 2):
        pixels[k,l] = (0,0,0)

img.show()

enter image description here

查看更多
登录 后发表回答