Showing posts with label PIL. Show all posts
Showing posts with label PIL. Show all posts

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

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.



Sunday, December 29, 2024

Would you like to watermark and protect your picture?

 You might have been shocked to see one of your pictures or image on someone else's site and felt betrayed. Chances are your name or reference is not even sited, just your image lifted from the internet. Watermarking is your protection against the plagiarism that happens sometimes.

What is watermarking?

Watermarking is the placing of a recognizable form of text or semi-transparent image on your picture so that if someone copies, your marking goes with the picture.

Here is an example of watermarking an image. You can shutterstock all over the image. You can copy from the site but it will have the watermarks.


Watermarking is more, it is branding

Watermarking a picture or an image is not just for protection, it is also your branding tool. Branding is an essential step you should take to be recognized on the internet and by far the most effective. Names like, Nike, Apple, Facebook are most recognizable because of branding. 

It is essential therefore that you take steps to establish your work by copywriting and watermarking.

Tools for watermarking:

There are many tools available for watermarking that are pretty cool. Here are just a few:

Watermarkly: A free, user-friendly tool for adding watermarks to photos

Canva: A free, online tool that lets you add a logo, name, or other visuals to your photos

PicMonkey: A free, online tool for adding watermarks to your images

Fotor: A free, online tool for adding watermarks to your images

Movavi Photo Editor: A free tool for making and editing collages

PhotoMarks: A tool for batch watermarking

Arclab Watermark Studio: A tool for adding multiple watermarks to images

Watermark Software: A tool for fast processing

Format Factory: A tool for watermarking photos and videos

uMark: A tool that uses barcodes and QR codes

This post shows you how to place a watermark on an image of your choosing using Python and an image library.

Python and image libraries have tools to do this. By extending the same concept, you can also watermark videos. I will be placing this text "Hodentek 2025" on the image shown below.


Here is the code in Python that allows you to create watermarks:

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

import os
from PIL import Image, ImageDraw, ImageFont

try:
# Open the original image
image_path = r"C:\Users\hoden\PycharmProjects\JNumpy\Jay.jpg"
original_image = Image.open(image_path)

# Create a watermark text
watermark_text = "Hodentek 2025"

# Create a new image for the watermark with an alpha layer (RGBA)
watermark_image = Image.new('RGBA', original_image.size, (0, 0, 0, 0))

# Get a drawing context
draw = ImageDraw.Draw(watermark_image)

# Define the font and size (you might need to adjust the font path)
font = ImageFont.truetype('arial.ttf', 72)

# Calculate the bounding box for the watermark text
bbox = draw.textbbox((0, 0), watermark_text, font=font)
text_width, text_height = bbox[2] - bbox[0], bbox[3] - bbox[1]
# position = (original_image.size[0] - text_width - 10, original_image.size[1] \
# - text_height - 10)
# Calculate the position for the watermark (center of the image)
position = ((original_image.size[0] - text_width) / 2, \
(original_image.size[1] - text_height) / 2)
# Draw the watermark text onto the watermark image
draw.text(position, watermark_text, fill=(255, 255, 255, 128), font=font)
# White text with transparency

# Combine the original image with the watermark
watermarked_image = Image.alpha_composite(original_image.convert('RGBA'), \
                                              watermark_image)

# Save and display the result
watermarked_image.show() # To display the image
watermarked_image.save('watermarked_output.png')

print('Watermarked image saved as watermarked_output.png')

except AttributeError as e:
print(f"Error: {e}")
print("Explanation:")
print("Make sure you are using the correct method and attributes.")

except OSError as e:
print(f"Error: {e}")
print("Explanation:")
print("This error likely occurs when the specified font file \
cannot be found or opened.")
print("Please double-check the font path and ensure the font \
file exists.")

except Exception as e:
print(f"An unexpected error occurred: {e}")

Note: Line continuation characters have been used, watch out.

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

 When you run this code, you will see the image with the watermark at its center  as shown:


Removing watermarks,? yes, Possible:

You may want to know also whether it is possible to remove watermarks. The answer is yes, you can remove watermarks with Python and the watermarked image, but it is more difficult and greater care is needed. Manual editing with Adobe Photoshop or GIMP is also possible. Presently there is an AI tool, Pixnova that removes watermark from photos and it can automatically remove watermark but preserving the original details. AI tools like Fotor and Vmake can help removing watermarks from videos as well.

Dynamic watermarking:

Yes, tools are available for this as well. Oh! you can hide watermarks also.


DynmaicWatermaking.jpg

Thursday, December 26, 2024

Ever Explored an Image? Dive In Now!


If you have not, it is time you do it. Python lends itself to be the way to unveil the magic behind images. While python is the main tool you need libraries to help along.

There is a famous adage, if you want to control something you need to measure it first. In order to change or use image in a yet to unknown ways, you need to unravel an image. Image processing is all about how in myriad ways you can use images for aesthetic, scientific and medical fields. Python with a plethora of image and other supportive libraries such as PIL, OpenCV, NumPy, etc. is great for this purpose. First of all we need to understand Pixel, it is like understanding a point in geometry, the fundamental building block.

What is a pixel?

The unveiling of an image starts with the building block of images, the pixels - geometrical structures with very minute dimensions that have some color in them.

Pixels are actually square. Each pixel is a tiny square of color that, when combined with other pixels, forms the images you see on screens. This grid of square pixels is what allows digital displays to render images with precision and clarity. The concept of pixels being square is fundamental to how digital images are created and displayed. In a sense, pixels are abstract that depend on the device on which we see the image. The physical size of a pixel is device dependent. The physical size of a pixel has to be derived from a knowledge of the resolving power of the device, the dots per inch seen on the device. While in Micro LEDs they are about 50 microns they can be fraction of a millimeter in large LEDs.  

Images are a grid of pixels, each with a specific color. When viewed together, these pixels form the images we see.

What is NumPy and what is its role in image processing?

In the process of understanding images, NumPy plays a crucial role. This library helps to separate an image into three distinct parts: height, width, and color. Furthermore, it isolates the colors red, green, and blue, placing them into their respective channels. By dismantling the image with NumPy, we can access the five important components of an image. These components can be manipulated using various image libraries in Python.

Also, while NumPy can disassemble an image, it can also reconstruct an image and it is extremely versatile. NumPy depends for its speed on the core C programming constructs but implemented for a high level language like Python.

Finding the height and width of an image using NumPy in Python:

This program takes in an image and find its shape with three arguments, height, width and number of channels. You can also see the result of running this code in PyCharm.

This image Kiss.jpg has height and width of 7401 and 7376 with three colors.

Finding the height, width and colors:

The following code unravels the image (the python program is using PyCharm interface):



1. When this code is run the image dimensions (height and width) are returned.

2. It separates the 3 color channels into its constituents.

3. It gives three images and saves them to a files in the same project

In arriving at these results it has,

1. Reduced the size of image by resizing so that final image is not distorted, visible and without any display related artifacts. (When this code was run without resizing, it returned 3 very large images all in grey).

2. After resizing, I have extracted the three channel information. Remember, it is zero-based.

3. Each channel (red, green, and blue) is populated by values from the image in a two-step process. In the first step, an array with the same dimensions as the image is created, but all elements are initialized to zero for the chosen channel. In the second step, this array is filled with the values of the pertinent color from the image.

4. It creates separate images of the same image in separate colors, one each for red, green and blue and shows them.

5. It also writes to file, the images for each of these channels.

As you can see, we have the height, width and three separate images of the image looking at ony red, green and blue values in its pixels.






Here is the code, should you try to run for your image:

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

import cv2
import numpy as np

# Load the image
image = cv2.imread(r'C:\Users\hoden\PycharmProjects\exploreImage\Images\TheKiss.jpg')
# Get the dimensions of the image
height, width, channels = image.shape

# Print the dimensions
print(f'Width: {width} pixels, Height: {height} pixels')

# resizing the image to display smaller sizes on my display device
resized_image = cv2.resize(image, (200, 200))

# Extract individual color channels
blue_channel = resized_image[:, :, 0]
green_channel = resized_image[:, :, 1]
red_channel = resized_image[:, :, 2]

# Create separate images for each channel
blue_image = np.zeros_like(resized_image)
blue_image[:, :, 0] = blue_channel

green_image = np.zeros_like(resized_image)
green_image[:, :, 1] = green_channel # Assign green channel to green image

red_image = np.zeros_like(resized_image)
red_image[:, :, 2] = red_channel

# Display the extracted channels as images
cv2.imshow('Blue Channel', blue_image)
cv2.imshow('Green Channel', green_image)
cv2.imshow('Red Channel', red_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

# Save the extracted channels as images (optional)
cv2.imwrite('blue_channel.jpg', blue_image)
cv2.imwrite('green_channel.jpg', green_image)
cv2.imwrite('red_channel.jpg', red_image)



 

 





Monday, December 23, 2024

Do you want to slow down a fast GIF?

GIFs are very engaging and dynamic images and they can run at a speed set at the time of creation. Well, some GIFs may look way better when run at a slow speed. 

You can use Python code to slow down a GIF that is too fast for your liking. In the previous post, you learnt how to make a GIF from scratch using Python. In this post, you will use Python code to slow down a GIF. The post shows an example.

Here is a GIF that is somewhat fast. It is copied from a website. 

Now here is the Python code that you can use to slow it down. The code shown is copied from my PyCharm user interface. If you copy and paste make sure the indentation requirements are satisfied.

from PIL import Image, ImageSequence
# Open the original GIF gif_path = 'lawn-time-lapse.gif'
gif = Image.open(r'C:\Users\hoden\PycharmProjects\exploreImage\Images\lawn-time-lapse.gif')
# Create a list to hold the frames
frames = []
# Loop through each frame in the original GIF
for frame in ImageSequence.Iterator(gif):
# Append each frame to the list
frames.append(frame.copy())
# Save the frames as a new GIF with a slower speed
frames[0].save('slowed_down_1_gif.gif', save_all=True, append_images=frames[1:],
duration=200, loop=0)
print('Slowed down GIF saved as slowed_down_1_gif.gif')

The fast GIF is in the project folder in the path shown. The ImageSequence is the key. You get a sequence of images in the frame that you append to a list. Save the frames as a new GIF with a slower speed. Duration in PIL is absolute in milliseconds.

The code before the print saves the first frame(frames[0]) and it saves all the frames slowing down to a duration of 200 seconds and appends the rest of the frames starting from frame[1], the second frame in the sequence.

Here is the result of slowing down the original GIF.


Since we have a handle to the sequence, we can find the original frames and the original duration as well.


Thursday, December 19, 2024

How do you resize an image with a desired resolution using Python?

 

Have you ever needed to resize an image for a specific purpose, like sharing it online or printing it? While many image editing programs offer tools for this, Python provides a powerful and flexible way to resize images programmatically. However, Size and DPI are related. In this post, we'll explore how to easily resize images to your desired dimensions using Python.

You can use PIL, the Python Image Library to accomplish this task easily using the following code:------------------------------------------------------

from PIL import Image 

# Open the original image 

image_path = 'path_to_your_image.jpg' 

image = Image.open(image_path) 

# Set the desired resolution (DPI) 

dpi = (300, 300) 

# Calculate the new size based on the desired DPI 

width, height = image.size 

new_width = int((width / original_dpi) * 300) 

new_height = int((height / original_dpi) * 300) 

new_size = (new_width, new_height) 

# Resize the image 

resized_image = image.resize(new_size, Image.ANTIALIAS) 

# Save the resized image with the new DPI 

resized_image.save('resized_image.jpg', dpi=dpi) 

print(f'Resized image saved as resized_image.jpg with resolution {dpi[0]}x{dpi[1]}

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

I used this code to change the size and resolution of the image shown here:


The properties of this image are as shown here (72x72 DPI), 2565x2747 pixels. 


This is the code used to change resolution to 300x300 DPI:

from PIL import Image

# Open the original image
image_path = 'path_to_your_image.jpg'
image = Image.open(r'C:\Users\hoden\PycharmProjects\exploreImage\Images\OliverEdited.jpg')

# Set the desired resolution (DPI)
dpi = (300, 300)

# Calculate the new size based on the desired DPI
width, height = image.size
new_width = int((width / 72) * 300)
new_height = int((height / 72) * 300)
new_size = (new_width, new_height)

# Resize the image
resized_image = image.resize(new_size, Image.LANCZOS)

# Save the resized image with the new DPI
resized_image.save('resized_image.jpg', dpi=dpi)

print(f'Resized image saved as resized_image.jpg with resolution {dpi[0]}x{dpi[1]} DPI')

Note: You might have noticed the ue of Image.LANCZOS in the above. Whereas earlier in the python code it was Image.ANTIALIAS. The reason for this that depending on the version, Image.ANTIALIAS may throw an exception.

The properties of this resized image is as shown here:


The printed size of this is very large. If you happen to copy and paste these into some kind of display you may not see the size change as most display devices readjust to show the image within its visible area.  You may have to ZOOM to 100% to see on some software programs. With GIMP shown here,


You will be able to see the difference visually by using its ZOOM feature.


Resized image by the program (gimpResized.png)


Edited image (gimpEdited.png)

Printers have different designed resolutions, typically measured in dots per inch (DPI). Here are some common DPI values for various types of printers:

  1. Inkjet Printers: These are commonly used for home and office printing. They typically have resolutions ranging from 300 DPI to 1200 DPI. High-end photo inkjet printers can go up to 4800 DPI or more.

  2. Laser Printers: These are often used in offices for text and document printing. They usually have resolutions of 600 DPI to 2400 DPI.

  3. Photo Printers: Specialized photo printers can have very high resolutions, often exceeding 4800 DPI, to produce high-quality photo prints.

  4. Commercial Printers: Used for professional printing services, these printers can have resolutions of 2400 DPI or higher, depending on the type of print job and the quality required.

The DPI value indicates how many dots of ink or toner the printer can place in a one-inch line. Higher DPI values generally result in finer detail and better print quality, especially for images and photos. However, for text documents, a lower DPI (like 300 or 600 DPI) is usually sufficient.







Saturday, November 30, 2024

How are color adjustments made in Python using PIL?

 

 When you adjust color of an image, you are adjusting the color balance which has the following components:

1. White balance: Adjusting color to make it look natural under different lighting conditions. Incandescent lamp, tungsten lamp, etc.

2. Color temperature: Adjusting the warmth or coolness of the image. Higher the temperature (in Kelvin) cooler the image (blue) and cooler the temperature warmer the image (more yellow). It may appear counterintuitive as to how we feel the effects of temperature. In reference to how a black body appears at different Kelvin values, higher Kelvin around 6500K and lower Kelvin, between 2000 to 3000. It represents the hue of a light source.

3. Tint:: adjusting green-magenta balance to correct for any color casts that were not addressed by the above. Note that color casts is an artifact of camera, environment etc. and is unwanted.

Well, in Python using PIL you need to use the ImageEnhance.color() method.

This method just takes a single argument (enhance factor), a floating-point number. The color enhancement for three enhancement factors are as follows:

1.0 : returns a copy of the image

<1.0: decreases the enhancement (e.g., less color)

>1.0: increases the enhancement)e.g., more color)

The PIL library can only do the above corrections or changes but for a more granular control you may need additional libraries or custom software.

Here is an example code and some screenshots. I am again using the "TheKiss" image used earlier. The original image is very large and so I have used a smaller image, about 10% of the original using size adjusting code in the Python code ().

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

AdjustColorPIL.py

from PIL import Image, ImageEnhance
from PIL.ImageFile import ImageFile

# Open an image file
image: ImageFile = Image.open(r'C:\Users\hoden\PycharmProjects\exploreImage\Images\TheKiss.jpg')
new_width = image.width // 10
new_height = image.height // 10
image = image.resize((new_width, new_height))
# Create an enhancer object for color
color_enhancer = ImageEnhance.Color(image)
# Enhance the image color with a factor (e.g., 1.5 for 50% more color)
enhanced_image = color_enhancer.enhance(0.5)
# Save the enhanced image
enhanced_image.save("enhanced_0point5.jpg")
# display the image
enhanced_image.show()

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

The above code was run for three values of enhance factor 0.5. 1.00 and 1.5. The results are as shown here:

                                            enhance factor= 0.5

                                            enhance factor =1.0 (no enhancement, original)

                                            enhance factor =1.5

The enhancement or otherwise using the enhance factor has no upper or lower limits. But beyond certain values, the result may look weird or uninteresting.

 Here are some practical guidelines:

  • 0.0 ≤ factor < 1.0: This range will reduce color saturation. For example:

    • 0.0: Converts the image to grayscale.

    • 0.5: Significantly reduces color intensity.

  • factor > 1.0: This range will increase color saturation. For example:

    • 1.5: Moderately increases color intensity.

    • 2.0 and above: Can lead to highly saturated, unnatural-looking colors.

Here is the image for enhance factor = 1.85









Friday, November 1, 2024

What is the histogram of an image?

 Histogram is an important quantity in image processing. This post looks at white and black images and their histograms.

Histogram is the distribution of intensities or pixel values. In other words, for a grayscale image, the histogram of the image is the distribution of intensities from 0(black) to 255(white). Each bin in the histogram represents a range of pixel values and the height of the bin indicates the number of pixels that fall within that range. Hence, a uniform gray colored image has just one value for the histogram and one with a gradient has a triangular distribution, and so on.

Python can be used to calculate the histogram of an image. Python uses the libraries related to images like PIL and OpenCV. 

Calculating the histogram [calcHist()] using OpenCV:

At first, let us calculate the histogram of a grayscale image. I have a image all white and let us find its histogram.

using the PyCharm IDE,

histogram = cv2.calcHist([image], [0], None, [256], [0, 256])

[image]: This is a list (or a single image) containing the image to be analyzed. In this case, we are passing a single grayscale image.

[0]: This specifies that we want to calculate the histogram for the first channel of the image. For grayscale images, there is only one channel.

None: This parameter is used for specifying a mask. In this case, we are not using a mask, so we pass None.

[256]: This specifies the number of bins in the histogram. A value of 256 is commonly used for grayscale images, as it corresponds to the possible range of pixel values (0-255).

[0, 256]: This specifies the range of pixel values for which the histogram is calculated. In this case, we are calculating the histogram for all pixel values in the image.

 Note that histogram does not refer to the spatial distribution of the pixel values.

This is the python code for a image all white.

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

import cv2

image = cv2.imread(r'C:\Users\hoden\PycharmProjects\exploreImage\Images_3\white.png')

histogram = cv2.calcHist([image], [0], None, [256], [0, 256])

print(histogram)

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

 The result is a single array all zeros except the last one. 

[[     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

 [     0.]

.

.

.

.

[636804.]]

  • The intensity value for white pixels is 255.

  • Every pixel in the image has this intensity.

Given these facts, the histogram will show:

  • A peak at the intensity level 255.

  • All other intensity levels (0-254) will have a frequency of 0.

For a perfectly all-black image, the histogram will be,

[[636804.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
 [     0.]
.
.
.
.
.[     0.]
 [     0.]
 [     0.]]

The 636804 being the result of using a 798x798 sized picture

In essence, 

 X-axis: Represents the intensity or brightness level of pixels. In grayscale images, this ranges from 0 (black) to 255 (white).

Y-axis: Represents the number of pixels in the image that have the intensity level corresponding to the x-axis value.

These can be plotted using other image libraries such as matplotlib.

PIL can also be used for calculating the Histogram of an image. Here is the python code.
------------------------------
from PIL import Image

def calculate_histogram(image):
    """Calculates the histogram of an image.

    Args:
        image: A PIL Image object.

    Returns:
        A list containing the pixel counts for each intensity level.
    """

    histogram = image.histogram()
    return histogram

# Load the image
image = Image.open("your_image.jpg")

# Calculate the histogram
histogram = calculate_histogram(image)

# Print the histogram
print(histogram)
-----------------------------------
PIL is a simpler implementation than that of OpenCV. Both the data structure and the visualization are different.  We will look at visualization in future posts.
Histogram are very useful in image recognition related aspects:
  • Image segmentation: Identifying regions of interest within an image based on their pixel intensity distribution.
  • Image enhancement: Adjusting the contrast or brightness of an image based on the histogram.
  • Image comparison: Comparing the histograms of different images to determine their similarity or dissimilarity.

Monday, October 28, 2024

How do you install matplotlib for python?

 

We have seen earlier how to install PIL and OpenCV to visualize images. Matplotlib is yet another library for creating complex plots and graphs.

 Each of these graphic libraries have their own application area:

PIL(Pillow): Great for simple manipulations like cropping, resizing and adding filters. Easy to use but not for extensive visualizations.

OpenCV: Great for real-time computer vision tasks and image processing and lend itself to feature detection, object recognition and video analysis.

Matplotlib: Great for complex plots, graphs,  and charts. Highly customizable.


Installing Matplotlib

Herein, I consider installing matplotlib in the PyCharm IDE that was used for PIL and OpenCV. You can use either the python interpreter to install the library package or the virtual terminal.

In the PyCharm IDE locate the Packages icon highlighted in blue. You can see other packages from earlier installs like pip, pillow, etc. 


In the search box type 'matplotlib' and click Install on the right


There was an error that indicated it is being used. However, it is not installed on this machine in any other program. If this works for you you are in luck.


The virtual terminal is another way to install packages. Locate the Terminal icon in PyCharm. The command line is displayed on the right. 


Type in the following : pip install matplotlib

This should install matplotlib. The program came back saying that it is already present in the site packages. 

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

(.venv) C:\Users\hoden\OneDrive\Desktop\PyCharm\PIL>pip install matplotlib

Requirement already satisfied: matplotlib in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (3.9.2)Requirement already satisfied: contourpy>=1.0.1 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (1.3.0)Requirement already satisfied: cycler>=0.10 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (0.12.1)Requirement already satisfied: fonttools>=4.22.0 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (4.54.1)Requirement already satisfied: kiwisolver>=1.3.1 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (1.4.7)Requirement already satisfied: numpy>=1.23 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (2.1.1)Requirement already satisfied: packaging>=20.0 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (24.1)Requirement already satisfied: pillow>=8 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (10.4.0)Requirement already satisfied: pyparsing>=2.3.1 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (3.2.0)Requirement already satisfied: python-dateutil>=2.7 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from matplotlib) (2.9.0.post0)  Requirement already satisfied: six>=1.5 in c:\users\hoden\pycharmprojects\exploreimage\.venv\lib\site-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)[notice] A new release of pip is available: 23.2.1 -> 24.3.1[notice] To update, run: C:\Users\hoden\PycharmProjects\exploreImage\.venv\Scripts\python.exe -m pip install --upgrade pi

And, indeed it was. The reason for this is perhaps the project files are not in the virtual environment. 

Anyway, before you use matplotlib in your python project, you need to import the plotting routine using 

Import matplotlib.pyplot as plt

Usage of matplotlib 

Python code for displaying an image. 

We will use the same RGB.png image as in the earlier posts.

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

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

# Load the image
image = mpimg.imread(r'C:\Users\hoden\PycharmProjects\exploreImage\Images_2\RGB.png')
# Display the image
plt.imshow(image)
plt.axis('off')
# Hide axes for a cleaner look
plt.title('Displayed Image')
plt.show()

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

The following image gets displayed:


What display device matplotlib uses to display an image?

Matplotlib uses a backend to display images and plots. The backend is responsible for rendering the visualizations to the screen or saving them to a file. By default, Matplotlib selects the appropriate backend based on your environment. Some common backends are:

  • TkAgg: Uses the Tkinter library for rendering.

  • Qt5Agg: Uses the Qt5 library for rendering.

  • MacOSX: Used for rendering on macOS.

  • GTK3Agg: Uses the GTK3 library for rendering.

  • Agg: Used for rendering to files without displaying on screen.

How to check the display device used for rendering:

The following code is used to check the display device:

Import matplotlib
print(matplotlib.get_backend())

On my Windows 11 laptop, it appears to use the TkAgg library for rendering as I get a reply 'tkagg' for the above code.