How do I draw a matrix round in python? - python

I have a matrix filled with 0 and 1. I would like to draw it round instead of square. That is, divide the circle into sectors and color them according to the matrix as in this picture:
Each value in this array corresponds to the color that should be filled in the image area. I painted the area pink for clarity:
I managed to create pie slices that I can shade, which works for the sections in circle b for example, but not for the other two:
from PIL import Image, ImageDraw
x_center = 400 // 2
y_center = 400 //2
img = Image.new('RGBA', (400, 400), 'white') Here's what happened
idraw = ImageDraw.Draw(img)
idraw.pieslice([x_center-100, x_center-100,
y_center + 106, y_center + 106], 225, 315, fill='blue')
Here's what happened:
Do you know how to do it in matplotlib or plotly? Theoretically, I understand how to do it, practically-no... Can you help me please??

Related

How do I come from a set of ordered points to a transparent picture of a polygon (Python)

I've got a number of ordered points that form a polygon and I've got an image.
Now I want to create a new image.
Every point inside the polygon should be part of the new image.
Every point outside the polygon should be transparent.
I am using PIL. Has anyone a theoretical approach or even a code example how to solve this problem?
Demo code to create a polygon image with transparent background.
from random import randint
from PIL import Image, ImageDraw
width, height = 200, 200
line_color, line_width = 'blue', 5
polygon = [(randint(0, width-1), randint(0, height-1),) for i in range(20)]
polygon.append(polygon[0])
im = Image.new("RGBA", (width, height), (255, 255, 255, 0))
draw = ImageDraw.Draw(im)
draw.line(polygon, fill=line_color, width=line_width) # join="curve"
# draw.polygon(polygon, fill=line_color) # no width option
im.show()
im.save("D:/polygon.png", format="PNG")

making grid over image starting from the middle with python matplotlib

Hey guys I am struggling with making a grid over an image of a basketball court that starts from the middle - meaning there is a middle line both at width and height of the image from where the grid then evenly spans out over the whole picture (to the left&right and bottom&top). I am using this as an example: draw grid lines over an image in matplotlib. I would greatly appreciate any help! I am very new to matplotlib and am asking the experts out there!
Thank you
This is the code I am currently working on which is not really working (in case that helps)
import matplotlib.pyplot as plt
from PIL import Image
import pylab as pl
img = Image.open('PATH_TO_IMAGE')
im = pl.imread('PATH_TO_IMAGE')
width, height = img.size
newh = height/2
neww = width/2
print(newh)
print(neww)
#dividing the new numbers by the court dimensions 60x110 both divided by two since height and width are divided by two. We want rectangles exactly 1 foot big in width and height
dx, dy = int(newh/30), int(neww/55)
print(dx)
print(dy)
grid_color = [0,0,0]
im[:,::dy,:] = grid_color
im[::dx,:,:] = grid_color
plt.figure(figsize=(6,3.2))
# Show the result
plt.imshow(im)
plt.show()
This works exactly for one image but no other ones. Here is the error message:
line 37, in
im[:,::dy,:] = grid_color
ValueError: could not broadcast input array from shape (3) into shape (1322,119,4)
I can't paste the image of the court because of copyright problems but you can just use any image of a 2D basketball court image from google like this: https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.istockphoto.com%2Fillustrations%2Fbasketball-court-overhead&psig=AOvVaw3ORchlrt0TuWGaDMHoe5zn&ust=1629496920541000&source=images&cd=vfe&ved=0CAsQjRxqFwoTCPCIk5yLvvICFQAAAAAdAAAAABAG
Ok so I found a solution for grid
since it is a RGBA value it needs 4 values. Red, green, blue and alpha. For the example of orange it would be:
grid_color = (255, 165, 0, 255)
im[:, ::dy, :] = grid_color
im[::dx, :, :] = grid_color

Draw Ellipse in Python PIL with line thickness

I am trying to draw a circle on an image, using Python. I tried this using PIL but I would like to specify a linewidth. Currently, PIL draws a circle but the border is too thin.
Here is what I have done.
For a test image: I created a 1632 X 1200 image in MS Paint and filled it green. I called it test_1.jpg. Here is the input file:
from PIL import Image, ImageDraw
im = Image.open('test_1.jpg')
width, height = im.size
eX, eY = 816,816 #Size of Bounding Box for ellipse
bbox = (width/2 - eX/2, height/2 - eY/2, width/2 + eX/2, height/2 + eY/2)
draw = ImageDraw.Draw(im)
bbox_L = []
for j in range(0,5):
bbox_L.append([element+j for element in bbox])
draw.ellipse(tuple(bbox_L[j]), outline ='white')
im.show()
Basically, I tried to draw multiple circles that would be centered at the same spot but with a different radius. My thinking was that this would create the effect of a thicker line.
However, this is producing the output shown in the attached file below:
Problem: As you can see, the bottom-left and top-right are too thin. Also, there are gaps between the various circles (see top left and bottom right).
The circle has a varying thickness. I am looking a circle with a uniform thickness.
Question:
Is there a way to do draw a circle in Python, on an image like test_1.jpg, using PIL, NumPy, etc. and to specify line thickness?
I had the same problem, and decided to write a helper function, similar to yours. This function draws two concentric ellipses in black and white on a mask layer, and the intended outline colour is stamped onto the original image through the mask. To get smoother results (antialias), the ellipses and mask is drawn in higher resolution.
Output with and without antialias
The white ellipse is 20 pixels wide, and the black ellipse is 0.5 pixels wide.
Code
from PIL import Image, ImageDraw
def draw_ellipse(image, bounds, width=1, outline='white', antialias=4):
"""Improved ellipse drawing function, based on PIL.ImageDraw."""
# Use a single channel image (mode='L') as mask.
# The size of the mask can be increased relative to the imput image
# to get smoother looking results.
mask = Image.new(
size=[int(dim * antialias) for dim in image.size],
mode='L', color='black')
draw = ImageDraw.Draw(mask)
# draw outer shape in white (color) and inner shape in black (transparent)
for offset, fill in (width/-2.0, 'white'), (width/2.0, 'black'):
left, top = [(value + offset) * antialias for value in bounds[:2]]
right, bottom = [(value - offset) * antialias for value in bounds[2:]]
draw.ellipse([left, top, right, bottom], fill=fill)
# downsample the mask using PIL.Image.LANCZOS
# (a high-quality downsampling filter).
mask = mask.resize(image.size, Image.LANCZOS)
# paste outline color to input image through the mask
image.paste(outline, mask=mask)
# green background image
image = Image.new(mode='RGB', size=(700, 300), color='green')
ellipse_box = [50, 50, 300, 250]
# draw a thick white ellipse and a thin black ellipse
draw_ellipse(image, ellipse_box, width=20)
# draw a thin black line, using higher antialias to preserve finer detail
draw_ellipse(image, ellipse_box, outline='black', width=.5, antialias=8)
# Lets try without antialiasing
ellipse_box[0] += 350
ellipse_box[2] += 350
draw_ellipse(image, ellipse_box, width=20, antialias=1)
draw_ellipse(image, ellipse_box, outline='black', width=1, antialias=1)
image.show()
I've only tested this code in python 3.4, but I think it should work with 2.7 without major modification.
Simple (but not nice) solution is to draw two circles (the smaller one with color of background):
outline = 10 # line thickness
draw.ellipse((x1-outline, y1-outline, x2+outline, y2+outline), fill=outline_color)
draw.ellipse((x1, y1, x2, y2), fill=background_color)
From version 5.3.0 onwards, released on 18 Oct 2018, Pillow has supported width for ImageDraw.ellipse. I doubt many people are using PIL nowadays.
I don't think there's a way to specify ellipse thickness, but you probably can draw lines at each pixel where ellipse pass, with the argument width=...
NB: I'm foreign, so sorry if my english is wrong.
You can use the Image.core.draw method like this:
zero_array = np.zeros((224,224))
im = Image.fromarray(np.uint8(zero_array))
draw = ImageDraw.Draw(im)
dr_im = Image.core.draw(im.getdata(), 0)
dr_im.draw_rectangle((22,33, 150,100),220,2)
dr_im.draw_rectangle((22,33, 150,100),125,0)
#draw.rectangle((22,33, 150,100), fill=220,outline = 125)
print(np.array(im)[33][23])
im.show()

Python reflect image along each sides of the triangle

I have created a triangle positioned in the centre of the screen.
from PIL import Image, ImageDraw
GRAY = (190, 190, 190)
im = Image.new('RGBA', (400, 400), WHITE)
points = (250, 250), (100, 250), (250, 100)
draw = ImageDraw.Draw(im)
draw.polygon(points, GRAY)
How do I duplicate this image and reflect it along each sides of the triangle at different random points. For example...
Plan: First find a random point on the edge of the big triangle where to put a smaller one, and then rotate it so it fits properly on the edge.
Suppose we can access the points of the triangle with something like this
triangle.edges[0].x,
triangle.edges[0].y,
triangle.edges[1].x,
etc
We can then find an arbitrary point by first selecting an edge, and "walk a random distance to the next edge":
r = randInt(3) # random integer between 0 and 2
first_edge = triangle.edges[r]
second_edge = r == 2 ? triangle.edges[0] : triangle.edges[r + 1]
## The next lines is kind of pseudo-code
r = randFloat(1)
random_point = (second_edge - first_edge)*r + first_edge
Our next problem is how to rotate a triangle. If you have done some algebra you might recognise this:
def rotatePointAroundOrigin(point, angle):
new_point = Point()
new_point.x = cos(angle)*point.x - sin(angle)*point.y
new_point.y = sin(angle).point.x + cos(angle)*point.y
return new_point
(see https://en.wikipedia.org/wiki/Rotation_matrix)
In addition to this you need to determine just how much to rotate the triangle, and then apply the function above to all of the points.

python draw pie shapes with colour filled

I am trying to draw a pie shape with filled colour. I've tried to do this in different ways. Here's the code:
ball = pygame.draw.circle(self.screen, self.pink, self.pos, self.r, 0)
pygame.gfxdraw.pie(self.screen, 60,60, 40, 0, 90,(0,255,0))
pygame.gfxdraw.arc(self.screen, 60,60, 40, 180, 270,(0,255,255))
pygame.draw.arc(self.screen, (255,0,255),ball,0, math.pi/4, ball.width/2)
The output image is like:
I want the pie shapes filled with colour, as the magenta coloured shape does. I used the arc function and set the line with = the radius to achieve this (4th line in the code). However, the colour isn't evenly filled. I also tried to draw a pie shape (2nd line in the code) However, I cannot find a way to fill the colour...
Thank you very much for your help!
You can just draw a sufficiently fine polygon (e.g in one degree intervals):
import math
import pygame
# Center and radius of pie chart
cx, cy, r = 100, 320, 75
# Background circle
pygame.draw.circle(screen, (17, 153, 255), (cx, cy), r)
# Calculate the angle in degrees
angle = val*360/total
# Start list of polygon points
p = [(cx, cy)]
# Get points on arc
for n in range(0,angle):
x = cx + int(r*math.cos(n*math.pi/180))
y = cy+int(r*math.sin(n*math.pi/180))
p.append((x, y))
p.append((cx, cy))
# Draw pie segment
if len(p) > 2:
pygame.draw.polygon(screen, (0, 0, 0), p)

Categories

Resources