Sunday, March 30, 2025

I am a Microsoft 365 family user, how much Microsoft AI can I access?

 AI credits is a measure of your AI usage via Copilot in the Edge browser. Every time a question is asked 1 AI Credit is used up.


How many AI credits do you get?


This is best answered by Microsoft as :


  • Users of the free Designer app (non-subscribers) receive 15 credits per month.

  • Microsoft 365 Personal and Family subscribers get 60 AI credits per month, which can be used across various applications, including Word, Excel, PowerPoint, Outlook, Microsoft Forms, OneNote, Designer​​​​​​​, Notepad, Photos, and Paint.


  • Copilot Pro subscribers can use AI features in Word, Excel, PowerPoint, Outlook, Microsoft Forms, OneNote, Designer​​​​​​​, Notepad, Photos, and Paint without worrying about credit limits. 


Note: AI benefits are only available to the subscription owner and cannot be shared with additional Microsoft 365 Family members. 

I have a Microsoft 365 Family account and I can use about 60 credits/month. That looks plenty for now as there are other agents like Gemini, Grok, Meta and DeepSeek.


Sunday, March 9, 2025

Can you create animation with Python? Part 3

In this post, we shall use the image created in the previous post and create a series of images one slightly rotated with respect to the previous. We then use these frames to create the GIF file which provides the animation.

Here is the code for creating the GIF file using the image created in the previous post:

==================

WheelRotator.py

from PIL import Image, ImageDraw
import os

def rotate_image_around_center(image_path, output_path, rotation_angle):
"""Rotates an image around its center without expanding the canvas."""
try:
original_image = Image.open(image_path).convert("RGBA")
#important to convert to RGBA
except FileNotFoundError:
print(f"Error: Image not found at {image_path}")
return None

rotated_image = original_image.rotate(rotation_angle, resample=Image.BICUBIC,\
 expand=False) #expand=False

# Create a mask to keep the original image's shape.
mask = Image.new("L", rotated_image.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0, rotated_image.width, rotated_image.height), fill=255)
#create a circle mask

# Create a new transparent image and paste the rotated image using the mask.
final_image = Image.new("RGBA", rotated_image.size, (0, 0, 0, 0))
#transparent image
final_image.paste(rotated_image, mask=mask)

final_image.save(output_path)
return final_image

def create_rotated_frames_from_image(image_path, output_folder="rotated_frames", \
num_frames=9, rotation_step=25):
"""Creates a series of rotated frames from an existing image."""
if not os.path.exists(output_folder):
os.makedirs(output_folder)

for i in range(num_frames):
output_path = os.path.join(output_folder, f"frame_{i:03d}.png")
rotated_image = rotate_image_around_center(image_path, output_path, \
i * rotation_step)
if rotated_image:
print(f"Created frame: {output_path}")

def create_gif_from_frames(image_folder, output_gif_path="rotated_image.gif"):
"""Creates a GIF from a series of images in a folder."""
images = []
filenames = sorted([f for f in os.listdir(image_folder) if f.endswith(".png")])

for filename in filenames:
filepath = os.path.join(image_folder, filename)
try:
images.append(Image.open(filepath))
except FileNotFoundError:
print(f"Error: Image not found at {filepath}")
return

if images:
images[0].save(output_gif_path, save_all=True, append_images=images[1:], \
duration=100, loop=0)
print(f"GIF created: {output_gif_path}")
else:
print(f"No images found in {image_folder}")

# Example usage:
image_file_path = r"C:\Users\hoden\PycharmProjects\exploreImage\Images\
five_spokes.png" 
# Replace with your image path.
create_rotated_frames_from_image(image_file_path)
create_gif_from_frames("rotated_frames")

Here are some notes:

The expand=False argument in original_image.rotate() ensures that the canvas size remains the same, preventing the white background from being added.

original_image = Image.open(image_path).convert("RGBA") converts the image to RGBA (Red, Green, Blue, Alpha). This is crucial for handling transparency

A mask image (mask) is created with the same size as the rotated image.

ImageDraw.Draw(mask) is used to draw an ellipse (circle) on the mask, filling it with white (255). This creates a circular mask that will be used to cut out the rotated image.

final_image = Image.new("RGBA", rotated_image.size, (0, 0, 0, 0)) creates a new transparent image with the same size as the rotated image.

final_image.paste(rotated_image, mask=mask) pastes the rotated image onto the transparent image, using the mask to define the visible area. This effectively removes the unwanted background.

Here is the rotated_jmage.gif


Without using the mask and using expand==true, the effect would have been less satisfactory:



Saturday, March 1, 2025

Can you create animation with Python? Part 2

We shall extend the code  in Part 1for five spokes using the following code. After which we rotate.

------

from PIL import Image, ImageDraw

import numpy as np


def create_five_spoke_image(filename="five_spokes.png"):

    img_size = 500

    center = (img_size // 2, img_size // 2)

    radius = img_size // 4


 2   img = Image.new("RGB", (img_size, img_size), "white")

    draw = ImageDraw.Draw(img)


    # Draw the circle

    draw.ellipse((center[0] - radius, center[1] - radius, center[0] + radius, center[1] + radius), fill="black")


    # Draw FIVE spokes

    num_spokes = 5

    for i in range(num_spokes):

        angle = (2 * np.pi * i / num_spokes)  # Calculate angle for each spoke

        x1 = center[0]

        y1 = center[1]

        x2 = center[0] + int(radius * np.cos(angle))

        y2 = center[1] + int(radius * np.sin(angle))

        draw.line((x1, y1, x2, y2), fill="red", width=3)


    img.save(filename)

    print(f"Saved: {filename}")

    img.show()


if __name__ == "__main__":

    create_five_spoke_image()

-----------------

Here is a detailed explanation of steps:


Imports:

from PIL import Image, ImageDraw: Imports the Image and ImageDraw modules from the Pillow (PIL) library. Pillow is used for image manipulation.

import numpy as np: Imports the NumPy library, which is used for numerical operations, specifically for calculating trigonometric functions.

create_five_spoke_image(filename="five_spokes.png") 

Function:

def create_five_spoke_image(filename="five_spokes.png"):

    img_size = 500

    center = (img_size // 2, img_size // 2)

    radius = img_size // 4

This function creates an image with a black circle and five red spokes radiating from the center.

img_size = 500: Sets the size of the image to 500x500 pixels.

center = (img_size // 2, img_size // 2): Calculates the center coordinates of the image.

radius = img_size // 4: Calculates the radius of the circle, which is one-fourth of the image size.

img = Image.new("RGB", (img_size, img_size), "white"): Creates a new RGB image with a white background.

draw = ImageDraw.Draw(img): Creates a Draw object, which is used to draw shapes on the image.

Drawing the Circle:

draw.ellipse((center[0] - radius, center[1] - radius, center[0] + radius, center[1] + radius), fill="black"): Draws a black ellipse (which looks like a circle because the radius is equal in both dimensions) at the center of the image. The coordinates define the bounding box of the ellipse.

Drawing the Spokes:

num_spokes = 5: Sets the number of spokes to 5.

for i in range(num_spokes):: Loops through the desired number of spokes.

angle = (2 * np.pi * i / num_spokes): Calculates the angle for each spoke. This evenly distributes the spokes around the circle. np.pi is the mathematical constant pi.

x1 = center[0], y1 = center[1]: Sets the starting coordinates of the spoke to the center of the image.

x2 = center[0] + int(radius * np.cos(angle)), y2 = center[1] + int(radius * np.sin(angle)): Calculates the ending coordinates of the spoke using trigonometric functions (cosine and sine). This places the end of each spoke on the circumference of the circle.

draw.line((x1, y1, x2, y2), fill="red", width=3): Draws a red line (the spoke) between the starting and ending coordinates with a width of 3 pixels.

Saving and Displaying the Image:

img.save(filename): Saves the image to a file with the specified filename.

print(f"Saved: {filename}"): Prints a message indicating that the image has been saved.

img.show(): Displays the image.

if __name__ == "__main__": Block:


create_five_spoke_image(): Calls the create_five_spoke_image() function when the script is executed directly. This ensures that the image is created only when the script is run, not when it's imported as a module.

When the code is run the image of a circle with five spokes apppear as shown:

C:\Users\hoden\AppData\Local\Programs\Python\Python312\python.exe C:\Users\hoden\PycharmProjects\exploreImage\Images\CircleFiveSpokes.py 

Saved: five_spokes.png

Process finished with exit code 0