Processing GenArt | How to save Shape as GIF - python

Goal: export this output as a GIF.
This is working code, using Processing and Python.
This actually runs forever, how do I stop it after a while so as I can save as GIF?
import random
radius = 0
def setup():
global displayWidth, displayHeight, radius
size(displayWidth, displayHeight)
background(0)
noFill()
stroke(255, 25)
radius = height / 2
def draw():
global radius
center_x = width / 2
center_y = height / 2
beginShape()
for i in range(360):
_noise = noise(i * 0.02, float(frameCount) / 50)
x = center_x + radius * cos(radians(i)) * _noise
y = center_y + radius * sin(radians(i)) * _noise
curveVertex(x, y)
if radius == 0:
stroke(225, 0, 0, 10)
if radius == 100:
stroke(0, 225, 0, 25)
if radius == 200:
stroke (0, 0, 225, 25)
endShape(CLOSE)
radius -= 1
Please let me know if there is anything else I should add to post.

You can't. GIFs are not supported in processing. However you can use saveFrame() to saves a numbered sequence of images. Just call saveFrame() at the end of draw. There are numerous tools that can create a GIF from a list of images.

Related

Creating randomly rotated and placed ellipses with background noise in python

I am trying to generate an image with a randomly placed and rotated ellipse. Everything else is working as it should, however the ellipse is not rotating.
from PIL import ImageDraw, Image, ImageFilter
import math
import numpy as np
import random
#define build area
x_bound = int(input("X Resolution? (Pixel) "))
y_bound = int(input("Y resolution? (Pixel) "))
#define number of outputs
repetitions = int(input("How many output images would you like? "))
count = 0
#choose amount of bubbles
distortion = int(input("how many distorting circles would you like "))
while count != repetitions:
img = Image.new("RGB", (x_bound, y_bound), color="White")
draw = ImageDraw.Draw(img)
#initialize randomness based on clock
random.seed()
# Generate a basic random colour, random RGB values 10-245
R, G, B = random.randint(10, 245), random.randint(10, 245), random.randint(10, 245),
for _ in range(0, distortion):
# Choose RGB values for this circle
r = R + random.randint(-10, 10)
g = G + random.randint(-10, 10)
b = B + random.randint(-10, 10)
diam = random.randint(30, 90)
x, y = random.randint(0, x_bound), random.randint(0, y_bound)
draw.ellipse([x, y, x + diam, y + diam], fill=(r, g, b))
# Blur the background a bit
res = img.filter(ImageFilter.BoxBlur(5))
#img.show(res)
# define shape bounds.
# I don't want to have a 0 value for size, always moving in the positive direction
x1 = random.randint(0, x_bound) y1 = random.randint(0, y_bound)
x2 = random.randint(x1, x_bound)
y2 = random.randint(y1, y_bound)
#commented line allows you to check coordinates, point of error check
print(x1, y1, x2, y2)
shape = [(x1, y1), (x2, y2)]
# create ellipse image
img1 = ImageDraw.Draw(img)
img1.ellipse(shape, fill=None, outline="black")
# rotate the ellipse image
rotation_value = random.randint(0, 180)
rotate = img.rotate(rotation_value)
#img.show(rotate)
# finding bounds of rotated figure
angle = rotation_value * math.pi / 180
# rotated coordinates of each of the four bounded corners
x_prime_1 = -y1 * math.sin(angle) + x1 * math.cos(angle)
y_prime_1 = y1 * math.cos(angle) + x1 * math.sin(angle)
x_prime_2 = -y2 * math.sin(angle) + x2 * math.cos(angle)
y_prime_2 = y2 * math.cos(angle) + x2 * math.sin(angle)
# commented code line is to check coordinates of rotated shape for validity
print(x_prime_1, y_prime_1, x_prime_2, y_prime_2)
# start a counter, ensure that x coordinates fall within defined bounds
x_count = 0
if x_prime_1 < x_bound:
x_count += 1
if x_prime_1 > 0:
x_count += 1
if x_prime_2 < x_bound:
x_count += 1
if x_prime_2 > 0:
x_count += 1
# start a counter, ensure that y coordinates fall within defined bounds
y_count = 0
if y_prime_1 < y_bound:
y_count += 1
if y_prime_1 > 0:
y_count += 1
if y_prime_2 < y_bound:
y_count += 1
if y_prime_2 > 0:
y_count += 1
print(x_count), print(y_count)
# ensure that both x and y coordinates fall within the defined area. Only then will it produce an
image.
if y_count == 4:
if x_count == 4:
img.show()
count += 1

Filling a circle produced by Midpoint Algorithm

In python, I have written some code that generates a circle using Bresenham's Midpoint Algorithm:
from PIL import Image, ImageDraw
radius = 100 #radius of circle
xpts = [] #array to hold x pts
ypts = [] #array to hold y pts
img = Image.new('RGB', (1000, 1000))
draw = ImageDraw.Draw(img) #to use draw.line()
pixels = img.load()
d = (5/4) - radius
x = 0
y = radius
xpts.append(x) #initial x value
ypts.append(y) #initial y value
while x < y:
if d < 0:
d += (2*x + 3)
x += 1
xpts.append(x + 500) #translate points to center by 500px
ypts.append(y - 500)
else:
d += (2 * (x - y) + 5)
x += 1
y -= 1
xpts.append(x + 500) #translate points to center by 500px
ypts.append(y - 500)
for i in range(len(xpts)): #draw initial and reflected octant points
pixels[xpts[i] ,ypts[i]] = (255,255,0) #initial octant
pixels[xpts[i],-ypts[i]] = (255,255,0)
pixels[-xpts[i],ypts[i]] = (255,255,0)
pixels[-xpts[i],-ypts[i]] = (255,255,0)
pixels[ypts[i],xpts[i]] = (255,255,0)
pixels[-ypts[i],xpts[i]] = (255,255,0)
pixels[ypts[i],-xpts[i]] = (255,255,0)
pixels[-ypts[i],-xpts[i]] = (255,255,0)
img.show()
To fill it, I had planned to use ImageDraw to draw a line horizontally within the circle from each point that is generated from the initial octant using draw.line(). I have the x and y coordinates stored in arrays. However, I am stuck interpreting each point and its reflection point to draw the horizontal line using draw.line(). Could someone clarify this?
Instead of drawing individual pixels, you would just add a line that connects the pixels corresponding to each other (either -x and +x or -y and +y). For each Bresenham step, you draw four lines (each connecting two octants).
Here is your adapted sample code. I dropped the points array and instead drew the lines directly. I also added the cx and cy variables that define the circle center. In your code, you sometimes used negative indices. This only works by coincidence because the circle is in the center:
from PIL import Image, ImageDraw
radius = 100 # radius of circle
xpts = [] # array to hold x pts
ypts = [] # array to hold y pts
img = Image.new('RGB', (1000, 1000))
draw = ImageDraw.Draw(img) # to use draw.line()
pixels = img.load()
d = (5 / 4) - radius
x = 0
y = radius
cx = 500
cy = 500
def draw_scanlines(x, y):
color = (255, 255, 0)
draw.line((cx - x, cy + y, cx + x, cy + y), fill=color)
draw.line((cx - x, cy - y, cx + x, cy - y), fill=color)
draw.line((cx - y, cy + x, cx + y, cy + x), fill=color)
draw.line((cx - y, cy - x, cx + y, cy - x), fill=color)
draw_scanlines(x, y)
while x < y:
if d < 0:
d += (2 * x + 3)
x += 1
else:
d += (2 * (x - y) + 5)
x += 1
y -= 1
draw_scanlines(x, y)
img.show()
Instead of drawing lines, you can fill all points inside a circle with radius radius in O(n^2) using:
# Your code here
for x in range(radius):
for y in range(radius):
if x**2 + y**2 < radius**2:
pixels[ x + 500 , y-500] = (255,255,0)
pixels[ x + 500 , -y-500] = (255,255,0)
pixels[ -x + 500 , y-500] = (255,255,0)
pixels[ -x + 500 , -y-500] = (255,255,0)
img.show()

Calculation speed with property into class

I'm french so pardon my language error.
I try to make a little pygame-zero game with ball physic.
So I want to control precisely a ball object in time.
I created a Ball's class, which implement built-in Rect object (to use default collision in case).
import pygame
WIDTH = 300
HEIGHT = 300
class Color:
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
class Ball(pygame.Rect):
def __init__(self, cx, cy, radius, color: Color = Color.WHITE):
position = (cx - radius, cy - radius)
size = (radius * 2, radius * 2)
super(Ball, self).__init__(position, size)
self.radius = radius
self.color = color
#property
def cx(self):
return self.x + self.radius
#cx.setter
def cx(self, cx):
self.x = cx - self.radius
#property
def cy(self):
return self.y + self.radius
#cy.setter
def cy(self, cy):
self.y = cy - self.radius
def draw(self):
position = (self.cx, self.cy)
screen.draw.filled_circle(position, self.radius, self.color);
# screen.draw.rect(self, Color.RED) # draw hitbox
I instance a ball object and want make it go at x position 0 to 300. (the width of the window).
I use the default delta time (it's the time in millisecond elapsed between each frame 1/60) in update's function.
With a speed of 100 pixel * delta time, the ball will traverse the screen at 3 seconds (logical).
But it's not ... after some manipulation I created a second ball (I switch ball's name) and when I use variable instead all works fine.
cl = 0 # get time elpased at launch
ball = Ball(0, 10, 10, Color.RED)
x = ball.cx
ball2 = Ball(0, 30, 10, Color.BLUE)
speed = 100
def draw():
screen.clear()
ball.draw()
ball2.draw()
screen.draw.text(f"{cl:7.2f}", (0, 150))
def update(dt):
global cl, x
if ball.cx <= WIDTH:
cl += dt
# the ball make 3 seconds exactly
x += speed * dt
ball.cx = x
ball2.cx += speed * dt # don't make 3 seconds WHY ?
My question ... why ?
Create a custom property, it's much slower than classic variable definition ?
If you want to ensure time precise calculations, then you've to do all the calculations with floating point values. Only convert the coordinates to integral data types when drawing the objects on is integer pixel position.
The .cx property has an integral data type. Every time when the position is incremented, then the fraction part of the number which is added is lost. This causes an increasing inaccuracy. The object appears to be slower than expected.
Note, if the frame rate would be higher, then the object will even stand still, if the step per frame is smaller than 1.0. The integer part of a value < 1.0 is 0.
Note
ball2.cx += speed * dt
does the same as
ball2.cx += int(speed * dt)
The x variable is a floating point value. It is incremented with full accuracy. The exact value is cast to int when it is assigned to the .cx property, but the inaccuracy is always smaller than 1.0 and thus almost negligible.
x += speed * dt
ball.cx = x
does the same as
x += speed * dt
ball.cx = int(x)

How can I find new coordinates of boundary box of rotated image to modify its xml file for Tensorflow data augmentation?

I'm trying to make more dataset to train my model in Tensorflow for data augmantaion. I added the labels of boundary boxes to original image. I want to rotate image 45 degree and modify the xml file for the new exact boundary box(rectangle) to label new created image. It's resizing and fetching to window to not to loose anything on image.
Let me show you how I try:
def rotateImage(mat, angle):
height, width = mat.shape[:2]
image_center = (width / 2, height / 2)
rotation_mat = cv2.getRotationMatrix2D(image_center, angle, 1)
radians = math.radians(angle)
sin = math.sin(radians)
cos = math.cos(radians)
bound_w = int((height * abs(sin)) + (width * abs(cos)))
bound_h = int((height * abs(cos)) + (width * abs(sin)))
rotation_mat[0, 2] += ((bound_w / 2) - image_center[0])
rotation_mat[1, 2] += ((bound_h / 2) - image_center[1])
rotated_mat = cv2.warpAffine(mat, rotation_mat, (bound_w, bound_h))
return rotated_mat
image = cv2.imread("test.jpg")
angle = 45
rotated_45_image = image.copy()
rotated_45_image = rotateImage(rotated_45_image, angle=45)
tree_for_45_rotated = ET.parse(file_name + ".xml")
root = tree_for_xml.getroot()
for object in root.iter("object"):
xmin = object.find("bndbox").find("xmin")
ymin = object.find("bndbox").find("ymin")
xmax = object.find("bndbox").find("xmax")
ymax = object.find("bndbox").find("ymax")
print(xmin.text, ymin.text, xmax.text, ymax.text)
print("new")
new_xmin = math.cos(angle) * int(xmin.text) - math.sin(angle) * int(ymin.text)
new_xmax = math.cos(angle) * int(xmax.text) - math.sin(angle) * int(ymin.text)
new_ymin = math.sin(angle) * int(xmin.text) + math.cos(angle) * int(ymin.text)
new_ymax = math.sin(angle) * int(xmin.text) + math.cos(angle) * int(ymax.text)
print(new_xmin, new_ymin, new_xmax, new_ymax)
After rotation the image is like this:
By the way, I'm using Python and OpenCV. I can't calculate the exact new coordinates to label the image.
Thanks
I cannot add a comment in the post above, so sorry for the post. All you need is print after rotation values from corners
img = cv2.imread("test.jpg")
rotated, corners = rotateImage(img, 30)
print(corners)
and if you want a specific value just use
print(corners[0])
print(corners[1])
print(corners[2])
print(corners[3])

Collisions in Zelle graphics.py

I am trying to make my circle bounce off of my rectangle using Zelle graphics.py. Once the circle bounces off of the rectangle I wanted it to keep moving randomly. Here is my code so far, and it's working!
Also I know that each circle graphics technically can use the points of the smallest possible square that would fit around the circle to do the collision but I'm having trouble with doing that.
from graphics import *
import random
def delay(d):
for i in range(d):
for i in range(50):
pass
#-------------------------------------------------
def main():
win=GraphWin("Moving Circle",500,400)
win.setBackground('white')
pt= Point(100,200)
cir=Circle(pt,30)
#changes the color of the circle for each game
r = random.randrange(256)
b = random.randrange(256)
g = random.randrange(256)
color = color_rgb(r, g, b)
cir.setFill(color)
cir.draw(win)
#rectangle
rec = Rectangle(Point(450,450), Point(275, 425))
rec.draw(win)
rec.setFill('black')
#-------------------------------------------------
pt5 = Point(250,30)
instruct1=Text(pt5, "click multiple times to start(rectangle can take multiple clicks to move)")
instruct1.setTextColor('black')
instruct1.draw(win)
#-------------------------------------------------
p=cir.getCenter()
p2=win.getMouse()
dx=1
dy=1
keepGoing=True
while keepGoing:
d = 100
delay(d)
cir.move(dx,dy)
p=cir.getCenter()
p2=win.checkMouse()
instruct1.setText("")
#rectanlge
isClicked= win.checkMouse()
if isClicked:
rp = isClicked
rc = rec.getCenter()
rdx = rp.getX() - rc.getX()
rdy = rp.getY() - rc.getY()
rec.move(rdx,rdy)
#circle
if((p.getX()-30)<=0.0) or ((p.getX()+30)>=500):
dx= -dx
if((p.getY()-30)<=0.0) or ((p.getY()+30)>=400):
dy=-dy
p3=win.checkMouse()
main()
I know that each circle graphics technically can use the points of the
smallest possible square that would fir around the circle to do the
collision
I'm playing with an alternate idea -- we could consider a circle around the rectangle instead of a square around the circle. The issue for me is that we not only need to detect collision, but come out with a sense of which way to move away from the other object. It's not just True and False but rather a (dx, dy) type of result.
Obviously, a circle around the rectangle is too crude, but suppose it were lots of smaller circles making up the rectangle and we measure circle center to center distance to detect a hit:
A hit on just a central (green) rectangle circle means reverse the vertical direction of the big circle. A hit on just the end (red) circle means reverse the horizontal direction of the big circle. And we can detect both kinds of hits and reverse the big circle completely.
Here's my rework of your code with the above in mind -- I also fixed your multiple clicking issue and made lots of style changes:
from random import randrange
from graphics import *
WIDTH, HEIGHT = 500, 400
RADIUS = 30
def delay(d):
for _ in range(d):
for _ in range(50):
pass
def distance(p1, p2):
return ((p2.getX() - p1.getX()) ** 2 + (p2.getY() - p1.getY()) ** 2) ** 0.5
def intersects(circle, rectangle):
dx, dy = 1, 1 # no change
center = circle.getCenter()
rectangle_radius = (rectangle.p2.getY() - rectangle.p1.getY()) / 2
rectangle_width = rectangle.p2.getX() - rectangle.p1.getX()
y = rectangle.getCenter().getY()
for x in range(int(rectangle_radius * 2), int(rectangle_width - rectangle_radius * 2) + 1, int(rectangle_radius)):
if distance(center, Point(rectangle.p1.getX() + x, y)) <= rectangle_radius + RADIUS:
dy = -dy # reverse vertical
break
if distance(center, Point(rectangle.p1.getX() + rectangle_radius, y)) <= rectangle_radius + RADIUS:
dx = -dx # reverse horizontal
elif distance(center, Point(rectangle.p2.getX() - rectangle_radius, y)) <= rectangle_radius + RADIUS:
dx = -dx # reverse horizontal
return (dx, dy)
def main():
win = GraphWin("Moving Circle", WIDTH, HEIGHT)
circle = Circle(Point(WIDTH / 5, HEIGHT / 2), RADIUS)
# change the color of the circle for each game
color = color_rgb(randrange(256), randrange(256), randrange(256))
circle.setFill(color)
circle.draw(win)
# rectangle
rectangle = Rectangle(Point(275, 425), Point(450, 450)) # off screen
rectangle.setFill('black')
rectangle.draw(win)
dx, dy = 1, 1
while True:
delay(100)
circle.move(dx, dy)
# rectangle
isClicked = win.checkMouse()
if isClicked:
point = isClicked
center = rectangle.getCenter()
rectangle.move(point.getX() - center.getX(), point.getY() - center.getY())
# circle
center = circle.getCenter()
if (center.getX() - RADIUS) <= 0.0 or (center.getX() + RADIUS) >= WIDTH:
dx = -dx
if (center.getY() - RADIUS) <= 0.0 or (center.getY() + RADIUS) >= HEIGHT:
dy = -dy
# collision bounce
x, y = intersects(circle, rectangle)
dx *= x
dy *= y
main()
Not perfect, but something to play around with, possibly plugging in a better intersects() implementation.

Categories