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






Thursday, February 27, 2025

Can you create animation with Python? Part 1

It is possible to create simple animation with Python easily. This post shows how easy to create simple animation such as a GIF.

As the first step we create a wheel with a single spoke. We will then extend it to create a wheel with 5 spokes. 

The code for creating a circle with one spoke is as shown:

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

from PIL import Image, ImageDraw

import numpy as np


def create_one_spoke_image(filename="one_spoke.png"):

    img_size = 500

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

    radius = img_size // 4


    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 ONE spoke (at 0 degrees for simplicity)

    x1 = center[0]

    y1 = center[1]

    x2 = center[0] + radius  # Spoke extends to the right

    y2 = center[1]

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


    img.save(filename)

    print(f"Saved: {filename}")

    img.show()


if __name__ == "__main__":

    create_one_spoke_image()

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

Here is the complete explanation of the code:


from PIL import Image, ImageDraw

import numpy as np

from PIL import Image, ImageDraw:

This line imports the Image and ImageDraw classes from the Python Imaging Library (PIL), also known as Pillow.

Image is used to create and manipulate image objects.

ImageDraw is used to draw shapes and lines on those image objects.

import numpy as np:

While numpy is imported, in this specific code provided, it is not actually utilized. If future modifications were to be made to the code, and array manipulation was needed, numpy would then be used.

2. Creating a Blank Image:

img_size = 500

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

img_size = 500:

This sets the size of the image to 500 pixels by 500 pixels.

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

This creates a new image object.

"RGB" specifies that the image will be in RGB color mode (red, green, blue).

(img_size, img_size) sets the dimensions of the image.

"white" sets the initial background color of the image to white.

3. Creating a Draw Object:

draw = ImageDraw.Draw(img)

draw = ImageDraw.Draw(img):

This creates a Draw object associated with the img image.

The Draw object provides methods for drawing shapes, lines, and text onto the image.

4. Drawing a Circle:

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

radius = img_size // 4

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

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

This calculates the center coordinates of the image.

radius = img_size // 4:

This calculates the radius of the circle, which is one-quarter of the image size.

draw.ellipse(...):

This draws an ellipse (which will be a circle in this case, due to the equal width and height).

The coordinates (center[0] - radius, center[1] - radius, center[0] + radius, center[1] + radius) define the bounding box of the ellipse.

fill="black" sets the fill color of the circle to black.

5. Drawing a Spoke:

x1 = center[0]

y1 = center[1]

x2 = center[0] + radius  # Spoke extends to the right

y2 = center[1]

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

x1 = center[0], y1 = center[1]:

These set the starting coordinates of the line (the spoke) to the center of the image.

x2 = center[0] + radius, y2 = center[1]:

These set the ending coordinates of the line. The spoke extends horizontally to the right, to the edge of the circle.

draw.line(...):

This draws a line between the starting and ending coordinates.

fill="red" sets the color of the line to red.

width=3 sets the thickness of the line to 3 pixels.

6. Saving the Image:

img.save(filename)

print(f"Saved: {filename}")

img.show()

img.save(filename):

This saves the created image to a file with the specified filename.

print(f"Saved: {filename}"):

This prints a confirmation message to the console.

img.show(): This line displays the image on a related printer as shown.

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

When you run this code you will see the following:

C:\Users\hoden\AppData\Local\Programs\Python\Python312\python.exe C:\Users\hoden\PycharmProjects\exploreImage\Images\CircleOneSpoke.py 
Saved: one_spoke.png
Process finished with exit code 0

The following image is displayed:








Wednesday, January 29, 2025

Does DeepSeek create the image from text specification?

 Conversing with DeepSeek, I was given to understand that it is not supporting creation of images. At present, it is only text.

However, it offered to create an image from text using Python and PIL. As I have been using these libraries, I gave it a try.

Here is the text specification that I used to create an image from Gemini AI [https://hodentekhelp.blogspot.com/2025/01/how-do-you-create-image-using-gemini-ai.html].

"Create an icon with the letter H decorated in yellow, with its insides filled with a web of electronic circuits. The background should be black  23-bit color with 8-bit transparency and the format in png."

Gemini AI created the following image:


Here is the suggestion from DeepSeek:

```python
from PIL import Image, ImageDraw, ImageFont

# Create a blank image with a black background and transparency
width, height = 256, 256  # Icon size
background_color = (0, 0, 0, 0)  # Black with full transparency
image = Image.new("RGBA", (width, height), background_color)

# Initialize ImageDraw
draw = ImageDraw.Draw(image)

# Draw the letter "H"
font = ImageFont.truetype("arial.ttf", 150)  # Use a system font like Arial
letter_color = (255, 255, 0, 255)  # Yellow
draw.text((75, 50), "H", font=font, fill=letter_color)

# Draw a web of electronic circuits inside the "H"
# This is a simplified representation using lines
circuit_color = (0, 255, 0, 255)  # Green for circuits
draw.line((90, 100, 90, 200), fill=circuit_color, width=2)  # Vertical linej
draw.line((90, 150, 160, 150), fill=circuit_color, width=2)  # Horizontal line
draw.line((160, 100, 160, 200), fill=circuit_color, width=2)  # Vertical line
draw.line((100, 120, 150, 120), fill=circuit_color, width=2)  # Horizontal line
draw.line((100, 180, 150, 180), fill=circuit_color, width=2)  # Horizontal line

# Save the image as a PNG file
image.save("icon_H_circuit.png", "PNG")

print("Icon created and saved as 'icon_H_circuit.png'")
```
I ran this code in PyCharm as shown:

from PIL import Image, ImageDraw, ImageFont

# Create a blank image with a black background and transparency
width, height = 256, 256 # Icon size
background_color = (0, 0, 0, 0) # Black with full transparency
image = Image.new("RGBA", (width, height), background_color)

# Initialize ImageDraw
draw = ImageDraw.Draw(image)

# Draw the letter "H"
font = ImageFont.truetype("arial.ttf", 150) # Use a system font like Arial
letter_color = (255, 255, 0, 255) # Yellow
draw.text((75, 50), "H", font=font, fill=letter_color)

# Draw a web of electronic circuits inside the "H"
# This is a simplified representation using lines
circuit_color = (0, 255, 0, 255) # Green for circuits
draw.line((90, 100, 90, 200), fill=circuit_color, width=2) # Vertical line
draw.line((90, 150, 160, 150), fill=circuit_color, width=2) # Horizontal line
draw.line((160, 100, 160, 200), fill=circuit_color, width=2) # Vertical line
draw.line((100, 120, 150, 120), fill=circuit_color, width=2) # Horizontal line
draw.line((100, 180, 150, 180), fill=circuit_color, width=2) # Horizontal line

# Save the image as a PNG file
image.save("icon_H_circuit.png", "PNG")
image.show()

print("Icon created and saved as 'icon_H_circuit.png'")

Here is the image created by DeepSeek:

Well, given the limitations, it did create a H with a minimalist circuit (it decided the color and artwork). 

I really think, the high-end chips are needed for creating something more exotic art work or images. This said, what is the utility of imaginary sceneries with a multitude of colors, etc. 

The basic thing the AI should deliver is VALUE in the first place and in subsequent places.



Monday, January 27, 2025

DeepSeek rattles the US AI dominance. Can it continue to rattle?

 The emergence of DeepSeek AI, a powerful Chinese language model, has sent shockwaves through the US AI industry. Developed with a focus on cost-effectiveness, DeepSeek reportedly functions effectively on lower-end hardware, a stark contrast to US models heavily reliant on high-end chips like Nvidia's. This revelation triggered a significant sell-off in Nvidia stock, highlighting the potential disruption to the current AI landscape.   

https://site.financialmodelingprep.com/market-news/nasdaq-futures-plunge-amidst-concerns-over-deepseeks-impact-on-ai-chip-demand

Last night, I downloaded DeepSeek to take a peek and lo and behold, at first sight, looked as good as the Copilot, Gemini AI, and others I have come across.

Well, what does it lack?

 However, a notable limitation became apparent: DeepSeek lacks robust image generation capabilities. While it can provide code snippets (like Python with Kivy) to generate images, this approach is less user-friendly and may be hindered by the limitations of lower-end hardware in processing and rendering graphics. In contrast, US models excel in not only creating images but also seamlessly modifying them based on simple text prompts.   This is clearly beyond low-end chips.

This development necessitates a renewed focus on innovation and optimization within the US AI sector. US developers must prioritize improving model efficiency and exploring alternative hardware solutions to maintain a competitive edge. While DeepSeek presents a significant challenge, it also serves as a valuable catalyst for further advancements in AI technology.

Does Gemini AI create the image from text prompt?

 Creating an image with Gemini AI is straightforward. Simply provide a textual description of the image you need. While Gemini AI can create and display the image, it does not store it. You can download the image to the Downloads folder on a Windows computer or share it using the built-in share icon.


Here is an example of text description used to create an  image using Gemini AI on Chrome:

Create an icon with the letter H decorated in yellow, with its insides filled with a web of electronic circuits. The background should be black, 24-bit color with 8-bit transparency, and the format should be PNG. 

At first, it did not create a PNG file. Perhaps due to size constraints, it used a JPG format instead. Repeating to ask creation of a PNG file was not successful and most agents have this habit of repeating what they did neglecting to refine them according to the wishes of the user. Sometimes, they get fixated on their result across couple of future sessions. 

Other AI agents, such as Meta AI on WhatsApp and Copilot, also have the capability to create images from text. Many other AI agents offer similar functionality.

Here is the image created by Gemini AI.

The image more or less follows the description. Small refinements may sometime lead to totally different image, not an iteration on the previous. 

I wanted to check the other parts of the image description. It is possible to check the image file using PIL and Python:

from PIL import Image

def verify_image_properties(image_path):
"""
Verifies the color and transparency of an image using PIL.

Args:
image_path: Path to the image file.

Returns:
A tuple containing:
- True if the dominant color is yellow, False otherwise.
- True if the image has 24-bit color, False otherwise.
- True if the image has 8-bit transparency, False otherwise.
"""

try:
img = Image.open(path/to/your/image.png)

# Check color (simplified approximation)
dominant_color = img.getpixel((img.width // 2, img.height // 2)) # Get center pixel color
is_yellow = (dominant_color[0] > 200) and (dominant_color[1] > 200) and (dominant_color[2] < 50)

# Check color depth
is_24_bit_color = img.mode == 'RGB'

# Check transparency depth
has_8_bit_transparency = False
if img.mode == 'RGBA':
if img.info.get('dpi') is not None and len(img.info['dpi']) == 2:
has_8_bit_transparency = True

return is_yellow, is_24_bit_color, has_8_bit_transparency

except Exception as e:
print(f"Error processing image: {e}")
return False, False, False

# Example usage
image_path = "r'C:\Users\hoden\PycharmProjects\exploreImage\Images\GeminiG.jpg')" # Replace with the actual path
is_yellow, is_24_bit_color, has_8_bit_transparency = verify_image_properties(image_path)

if is_yellow:
print("Image is predominantly yellow.")
else:
print("Image is not predominantly yellow.")

if is_24_bit_color:
print("Image has 24-bit color.")
else:
print("Image does not have 24-bit color.")

if has_8_bit_transparency:
print("Image has 8-bit transparency.")
else:
print("Image does not have 8-bit transparency.")

The code returns the following:

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

Image is not predominantly yellow.

Image has 24-bit color.

Image does not have 8-bit transparency.

Process finished with exit code 0

Did the Gemini AI create an image to fit our description?

The image is not predominantly yellow is true and finding the color in the image center is perhaps the wrong approach.

Other methods may yield better result than the Center Pixel Method in the code for the visible color yellow:

Center Pixel Method: This method checks the color of the pixel at the center of the image. It's simple but may not always represent the overall dominant color.

Most Common Color: This method counts the occurrences of each color and identifies the most frequent one. It can be effective but might not capture the visually dominant color if the image has a lot of background noise

K-Means Clustering: This method groups similar colors together and identifies the most visually impactful color. It's more sophisticated and can provide a better representation of the dominant color but requires more computational resources.