How to draw stripes in python pillow? - python

I have made a stripes as you can see in folowing code. I was wondering is there a simplest way to do this? or some other way that you can think of, if there are, please provide code.
from PIL import Image, ImageDraw
img = Image.new('RGB', (100, 100), (255, 255, 255))
draw = ImageDraw.Draw(img)
draw.line((100, 10, 0, 10), (0, 0, 0), 10)
draw.line((100, 30, 0, 30), (0, 0, 0), 10)
draw.line((100, 50, 0, 50), (0, 0, 0), 10)
draw.line((100, 70, 0, 70), (0, 0, 0), 10)
draw.line((100, 90, 0, 90), (0, 0, 0), 10)
img.show()
Thanks in advance!

There is no simpler way but you can use for-loop to make shorter code.
for y in range(10, 91, 20):
draw.line((100, y, 0, y), (0, 0, 0), 10)

Related

How can i generate an image determining the color of each pixel in python?

I need a way to generate an image so that i can decide width, length and color for each pixel, maybe through an array. how can i do that in Python?
Here is a way using Pillow and an array
from PIL import Image
# Your image as a 3d-array using RGB color values for each pixel
imageArray = [[(0, 0, 0), (0, 0, 0), (0, 0, 0)],
[(0, 0, 0), (0, 0, 0), (0, 0, 0)],
[(0, 0, 0), (0, 0, 0), (0, 0, 0)]]
# Generate image
img = Image.new("RGB", (len(imageArray[0]), len(imageArray)), "#ffffff")
for i, row in enumerate(imageArray):
for j, pixel in enumerate(row):
img.putpixel((j, i), pixel)
img.save("output.png")

How to convert 2D matrix of RGBA tuples into PIL Image?

Suppose if I have image img with contents:
[[(255, 255, 255, 255), (0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255)],
[(0, 0, 0, 255), (255, 255, 255, 255), (0, 0, 0, 255), (0, 0, 0, 255)],
[(0, 0, 0, 255), (0, 0, 0, 255), (255, 255, 255, 255), (0, 0, 0, 255)],
[(0, 0, 0, 255), (0, 0, 0, 255), (0, 0, 0, 255), (255, 255, 255, 255)]]
Is there's any way I can make PIL Image from it?
I tried Image.fromarray(np.asarray(img)) and I got the following error:
TypeError: Cannot handle this data type: (1, 1, 4), <i4
How can I resolve it? Also is there's any solution without the usage of numpy module? Thanks in advance.
I think you want this (quite self explanatory from the doc):
from PIL import Image
arr = np.array(img)
PIL_image = Image.frombuffer('RGBA',(arr.shape[0],arr.shape[1]),np.uint8(arr.reshape(arr.shape[0]*arr.shape[1],arr.shape[2])),'raw','RGBA',0,1)
You need to explicitly set dtype of an array as np.uint8 to let the Image object generator know the format of input data. And I would also recommend to specify the mode because I don't know how PIL choose between RGBA and CMYK when there are 4 channels. The solution is here:
from PIL import Image
Image.fromarray(np.asarray(img, dtype=np.uint8), mode='RGBA')

Why must I load a file instead of a custom surface when setting an icon?

When running the code
pygame.display.set_icon(icon)
where icon is a custom Surface, meaning I filled parts of a surface, e.g. icon.fill((255, 128, 0), (0, 0, 20, 10))
The icon shows up as the backmost color which in my case is green, but when I save the icon to a file and load the image as the icon it works.
CODE:
Map_Surface = pygame.Surface((20, 20))
SKIN_DICT = {
'Steve': (
[(0, 255, 0), (0, 0, 20, 10)],
[(0, 0, 0), (4, 4, 4, 4)],
[(0, 0, 0), (12, 4, 4, 4)],
[(255, 255, 255), (4, 4, 2, 2)],
[(255, 255, 255), (12, 4, 2, 2)],
[(128, 128, 128), (0, 10, 20, 7)],
[(0, 0, 255), (0, 17, 20, 3)]
)
}
def skin(name):
for style in name:
Map_Surface.fill(style[0], style[1])
skin(SKIN_DICT['Steve'])
When I put Map_Surface into pygame.display.set_icon(Map_Surface) The icon gets set to a solid green square.
pygame.display.set_icon(Map_Surface)
But when I put Map_Surface into pygame.image.save(icon, 'icon.png') and then do pygame.display.set_icon(pygame.image.load('icon.png')
pygame.image.save(Map_Surface, 'icon.png')
pygame.display.set_icon(pygame.image.load('icon.png'))
You don't need to load your icon from a file. Simply call convert_alpha() on Map_Surface, as follows:
pygame.display.set_icon(Map_Surface.convert_alpha())
This sets the icon to a copy of Map_Surface with an alpha channel. Unfortunately I don't know why it fixes the problem. I originally tried to use pygame.Surface.convert(), however the icon remained as a solid green square.
See the documentation for pygame.Surface.convert_alpha:
https://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert_alpha

dumb question: Is there a way to make a color pattern repeat every X number of LEDs? Or do I have to write out the pattern for each LED in the strip?

I have a strip of 288 addressable LEDs and it is broken up into segments of 12 LEDs each. I have already written a bunch of code for colors and patterns designed for just one segment. The single colors were easy enough to adjust to fill all of the segments but I haven't quite figured out how to do the patterns without just copy/paste and correct the pixel numbers. Any insight is greatly appreciated, i'll attach a copy of a pattern to use as an example. (all of the patterns are pretty simple, basically two to three colors broken up across the segment)
I've just tried a bit of googling and using what i already know to try to come up with a way to make it work.
import board
import neopixel
import time
pixels = neopixel.NeoPixel(board.D18, 288)
pixels[0] = (25, 255, 255)
pixels[1] = (25, 255, 255)
pixels[2] = (25, 255, 255)
pixels[3] = (25, 255, 255)
pixels[4] = (155, 155, 155)
pixels[5] = (155, 155, 155)
pixels[6] = (0, 0, 255)
pixels[7] = (0, 0, 255)
pixels[8] = (0, 0, 255)
pixels[9] = (0, 0, 255)
pixels[10] = (155, 155, 155)
pixels[11] = (155, 155, 155)
I would like to get this pattern to repeat across the entire strip of 288 LEDs.
Let's first set the pattern for us to use in each of the following solutions and a helper function:
pattern = [
(25, 255, 255),
(25, 255, 255),
(25, 255, 255),
(25, 255, 255),
(155, 155, 155),
(155, 155, 155),
(0, 0, 255),
(0, 0, 255),
(0, 0, 255),
(0, 0, 255),
(155, 155, 155),
(155, 155, 155)
]
def roundup(numerator, denominator):
return (numerator + denominator - 1) // denominator
The roundup function is based on this answer which is applicable here since it's being applied to variables derived from length, which will be ints.
1) You can pack the pattern up very easily like this, which should be flexible to differing length patterns or LED strips:
len_strip = 288
len_pattern = len(pattern)
pixels = (pattern * roundup(len_strip,len_pattern))[:len_strip]
2) Here is a way you can loop over this pattern (rather than the whole array):
pixels = [0]*288
for i in range(len(pixels)//12):
pixels[12*i:12*i+12] = pixel_pattern
This packs it up so you are looping over the pattern instead of looping over each pixel.
3) If you want to pack it up to be deal with a varying length of pattern or of LED array, you could try something more flexible like this:
pixels = [0]*288
strip_len = len(pixels)
pattern_len = len(pixel_pattern )
for i in range(roundup(len(pixels),pattern_len)):
chunk_start = pattern_len*i
chunk_end = chunk_start + pattern_len
if chunk_end<strip_len:
pixels[chunk_start:chunk_end] = pixel_pattern
else:
chunk_end = strip_len
pixels[chunk_start:chunk_end] = pixel_pattern[0:chunk_end-chunk_start]
4) If you wanted to address each one while still looping over the pattern, you can also do it this way:
pixels = [0]*288
for i in range(len(pixels)//12):
pixels[12*i+0] = (25, 255, 255)
pixels[12*i+1] = (25, 255, 255)
pixels[12*i+2] = (25, 255, 255)
pixels[12*i+3] = (25, 255, 255)
pixels[12*i+4] = (155, 155, 155)
pixels[12*i+5] = (155, 155, 155)
pixels[12*i+6] = (0, 0, 255)
pixels[12*i+7] = (0, 0, 255)
pixels[12*i+8] = (0, 0, 255)
pixels[12*i+9] = (0, 0, 255)
pixels[12*i+10] = (155, 155, 155)
pixels[12*i+11] = (155, 155, 155)
Maybe something like this would work for you:
pixel_config = [
(25, 255, 255),
(25, 255, 255),
(25, 255, 255),
(25, 255, 255),
(155, 155, 155),
(155, 155, 155),
(0, 0, 255),
(0, 0, 255),
(0, 0, 255),
(0, 0, 255),
(155, 155, 155),
(155, 155, 155)
]
runningIdx = 0
endingIdx = len(pixel_config)
for i in range(288):
# Start new sequence if end is detected
runningIdx = 0 if runningIdx == endingIdx else runningIdx
pixels[i] = pixel_config[runningIdx]
runningIdx += 1
Essentially utilizes a running index to keep track of which configuration to set for a given pixel and resets as necessary when the final configuration has been set to begin setting the colors for the next sequence of pixels.

Draw circles that leave the image boundaries

This piece of code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PIL import Image, ImageDraw
imo=Image.new("RGB", (85, 64), (204, 204, 204))
pos=(10, 64)
r=8
draw=ImageDraw.Draw(imo)
draw.chord((pos[0]-r, pos[1]-r, pos[0]+r, pos[1]+r), 0, 359, (0, 0, 255), (0, 0, 0))
for pos in [(32, -1), (85, 32), (32, 64), (-1, 32), (54, 63)]:
draw.ellipse((pos[0]-r, pos[1]-r, pos[0]+r, pos[1]+r), (0, 0, 255), (0, 0, 0))
pos=(75, 65)
draw.rectangle((pos[0]-r, pos[1]-r, pos[0]+r, pos[1]+r), (0, 0, 255), (0, 0, 0))
imo.save("aa.png", "PNG")
creates this (enlarged) image:
Is there a trick to draw the circles in such a way that they are also shown fully filled at the bottom of the image?
Okay...it works fine for rectangles...but I would prefer circles.
after upgrading to python-Pillow-2.9.0-6.4.x86_64, I now get fully filled circles - even on openSUSE 13.2.

Categories