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.


Sunday, December 22, 2024

You have seen a GIF, have you created one?

  You have seen a GIF image and enjoyed it. But have you created one.? There are software programs to create GIFs and perhaps many online sites help creating GIFs.  Here is one for example, https://www.canva.com/create/gif-maker/. Animation akin to GIFS can also be created using javascript although there may not be resulting image with a .gif extension.

GIFs are like very small duration video clips but they are really a composite of many small images flipped rapidly, in-situ to create the illusion of motion. They are made to impress you by their motion.

Why GIFS?

Imagine bringing life to a still photo of a sunset by animating the clouds. An image may be worth a thousand words, but a GIF is worth a thousand images. It adds dynamic movement to static images, unleashing your creativity. If you're active on social media, GIFs are an invaluable tool for self-expression, offering endless possibilities. They bring humor, emotion, and laughter to any page, transforming a collection of static images into a vibrant and engaging experience. With GIFs, you can elevate your storytelling to new heights!"

Here is a simple GIF image copied from a web site  (display gif on web browser - Search):


Ins and outs of using Python to create GIFs:

GIF images have the .gif extension which stands for Graphics Interchange Format. 

In this post, I show you how to create from scratch a GIF using Python. Python uses a image library such as PIL to get the images into the program such as PyCharm. Once they are in the program, you need to use another library to do the flipping action. This library is called imageio, image input/output program. For GIFs this program takes in the images (a number of them) and then it customizes the duration each image is shown; whether the gif repeats itself and how many times it does, etc. Note: if you are new to PyCharm, read up my other Python/Image related posts in this blog, http://hodentekhelp.blogpost.com.

The program presented here also goes through the indexing of the images (as there are many images) which necessitate calling yet another useful library called NumPy. The imageio program cannot accept a image list, but a Numpy list and hence the use of the NumPy library.

In order to create a gif file in a python program, you need the following:

1. A set of images. 

2. Importing libraries PIL, ImageIO and Numpy.

Here is are some five image files I am using in the program:






These are not the best, but enough for the purpose.

Here is the python program that creates a GIF image taking in the images shown here:

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

BirdsGIF.py

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

# Import libraries used to create a GIF image

import imageio

import numpy as np

from PIL import Image

from PIL.ImageFile import ImageFile

# Load images

image1: ImageFile = Image.open(r'C:\Users\hoden\PycharmProjects\exploreImage\Images_3\Bird1.jpg')

image2 = Image.open(r'C:\Users\hoden\PycharmProjects\exploreImage\Images_3\Bird2.jpg')

image3 = Image.open(r'C:\Users\hoden\PycharmProjects\exploreImage\Images_3\Bird3.jpg')

image4 = Image.open(r'C:\Users\hoden\PycharmProjects\exploreImage\Images_3\Bird4.jpg')

image5 = Image.open(r'C:\Users\hoden\PycharmProjects\exploreImage\Images_3\Bird5.jpg')

# Resize images (optional)

image1 = image1.resize((200, 200))

image2 = image2.resize((200, 200))

image3 = image3.resize((200,200))

image4 = image4.resize((200,200))

image5 = image5.resize((200,200))

# Create list of images

images = [image1, image2, image3, image4, image5]

# Convert PIL image  list to NumPy arrays

images = [np.array(img) for img in images]

# Create the GIF using the image list

imageio.mimsave('my_animation.gif', images, duration=2000.0, loop=5)

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

The above program creates a image file with .gif extension and images show for 2000 milliseconds and the GIF image runs five times in succession. If you have time elapsed stills of any event you can easily turn it into an amazingly dynamic image.

That is all there is to creating a GIF. If your images are made with care and are of good quality you can indeed create a good GIF.

The GIf file created, my_animation.gif can be seen in Photo app on your windows computer device, however you can just drag and drop the image on a browser should also work.


Mahalo for staying with me. 

p.s: For these holidays, you can create your greeting card with a GIF. Try it!






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.







Sunday, December 15, 2024

Have you considered image augmentation in image data generation - Part 1?

 Python has emerged as a programming language of choice when it comes to generating images through image augmentation techniques. Image augmentation techniques can provide a rich diversity of the training dataset and turbocharge the image recognition models. 

This post explores one of the fundamental image data augmentation techniques, random cropping. A future post discusses the random clipping.

Cropping and flipping are common image manipulation techniques that don't require explicit redefinition. They are often implemented using built-in functions or libraries like OpenCV and PIL.

Details of random cropping:

Here is the python code to randomly crop an image.

=========

def random_crop(img, crop_size):


    h, w = img.shape[:2]

    x = np.random.randint(0, w - crop_size[1])

    y = np.random.randint(0, h - crop_size[0])

    crop_img = img[y:y+crop_size[0], x:x+crop_size[1]]

    return crop_img

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

The random cropping shown above does not directly use the OpenCV, it uses the functionality of NumPy arrays. 

Note:  Defining h, w =img.shape[:2] correctly picks the images height and width appropriate for NumPy array. The common channels of NumPy are [height, width, and  color-channel] in that order.

Also note:

NumPy arrays use zero-based indexing. This means the first element in an array has an index of 0, the second has an index of 1, and so on.

In the random_crop function:

x = np.random.randint(0, w - crop_size[1])

This line generates a random starting x-coordinate for the crop. w is the width of the image.

crop_size[1] is the width of the cropped region.

By subtracting crop_size[1] from w, we ensure that the starting x-coordinate plus the crop width doesn't exceed the image's width.

y = np.random.randint(0, h - crop_size[0])

This line generates a random starting y-coordinate for the crop.

h is the height of the image. crop_size[0] is the height of the cropped region.

Similarly, this ensures the starting y-coordinate plus the crop height doesn't exceed the image's height.

Random cropping is the same as cropping with randomness introduced to the randomness in choosing the cropping coordinates.

The following code is just regular cropping of an image:

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

from PIL import Image

def crop_image(image_path, left, top, right, bottom):
"""
Crops an image using PIL.

Args:
image_path: Path to the image file.
left: X-coordinate of the top-left corner of the cropping region.
top: Y-coordinate of the top-left corner of the cropping region.
right: X-coordinate of the bottom-right corner of the cropping region.
bottom: Y-coordinate of the bottom-right corner of the cropping region.

Returns:
The cropped image as a PIL Image object.
"""
try:
img = Image.open(image_path)
cropped_img = img.crop((left, top, right, bottom))
return cropped_img
except Exception as e:
print(f"Error cropping image: {e}")
return None


# Example usage:
image_path = r"C:\Users\hoden\PycharmProjects\exploreImage\Images\TheKiss.jpg"
left = 100
top = 50
right = 300
bottom = 200

cropped_image = crop_image(image_path, left, top, right, bottom)

if cropped_image:
cropped_image.show()
cropped_image.save("cropped_image.jpg")

Now, Let us consider random cropping:

TBC--> TO BE CONTIUED

What are some useful built-in functions of "Random" in Python?

 Random numbers are needed in most studies in information technology such as:

  • Simulation
  • Game Development
  • Machine Learning, AI, Image recognition
  • Cryptography
  • Code testing and many more.

Random module in Python has all the functions. You need to import Random to work with random functions in Python. Using this module you can generate random numbers and sequences. However, the random number generated are pseudo-random numbers, random numbers that are deterministic. In order to generate truly random numbers one has to resort to physical systems like noise, radioactive decay or weather related phenomenon.

Here is a brief description of the functions:

1. random.random():

Generates a random floating-point number between 0.0 (inclusive) and 1.0 (exclusive).

2. random.uniform(a, b):

Generates a random floating-point number between a and b, inclusive of a but exclusive of b.

3. random.randint(a, b):

Generates a random integer between a and b, inclusive of both a and b.

4. random.randrange(start, stop[, step]):

Generates a random integer from the range [start, stop), with an optional step value.

5. random.choice(seq):

Returns a random element from the sequence seq.

6. random.shuffle(x):

Shuffles the elements of the sequence x in place.

7. random.sample(population, k):

Returns a k length list of unique elements chosen from the population sequence or set.

Sequence is a general form of data structure that stores a collection of items in a specific order. It can be of different data types. In simple terms, an ordered list of same type of data is a sequence. 

Here is a better example of a sequence and a list:

Tuples (Immutable Sequences):

  • Ordered collection of elements.
  • Elements cannot be changed after creation.

Often used to represent fixed data structures.

Lists (Mutable Sequences):

  • Ordered collection of elements.
  • Elements can be modified, added, or removed.

More flexible for dynamic data structures.

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

The random.shuffle(mylist) function modifies the list mylist in place and does not return a new list. This means that you need to have an existing list that you want to shuffle. The function directly changes the order of elements in the original list.

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

Here is an example of the usage of the randum() function in PyCharm, Randoms.py. If you want use the code to run, remove space between each function shown below.

import random

# Generate a random float between 0 and 1
random_float = random.random()
print("Random Float: ", random_float)

# Generate a random integer between 1 and 10 (inclusive)
random_integer = random.randint(1, 25)
print("Random Integer: ", random_integer)

random_number_with_step = random.randrange(5, 67, 3)
# Generates a random integer from the range [start, stop), with an optional step value
print("Random Number with step: ", random_number_with_step)

random_choice_seq = random.choice([1, 200, 300, 412, 516])
# Returns a random element from the sequence (list as argument)seq.
print("Random Choice Sequence (list): ", random_choice_seq)

random_choice_seq=random.choice('A thing of beauty is a joy forever')
# Returns a random letter from the sequence (string as argument)seq
print("Random Choice Sequence (string): ", random_choice_seq)

random_shuffle_of_the_list=random.shuffle([1, 100, 1000, 10000])
#Shuffles the elements of the sequence x in place
print("Random Shuffle list in place: ", random_shuffle_of_the_list)


#random_Sample=random.sample(population, k)
#Returns a k length list of unique elements chosen from the population sequence or set.
# unlike random.shuffle, random.sample can accept a list variable or use list elements as argument

# Original list
my_list = [1, 100, 1000, 10000]
# Get a sample of 2 elements from the list
random_Sample_Population_k = random.sample(my_list, 2)
# Print a sampled list
print("Random_Sample_Population_k: ", random_Sample_Population_k)
------------------------------------------------------
Being random, each time you run the result will be different except the shuffle list
Random Float:  0.7630766884865164
Random Integer:  1
Random Number with step:  26
Random Choice Sequence (list):  412
Random Choice Sequence (string):  a
Random Shuffle list in place:  None
Random_Sample_Population_k:  [1, 1000]

Saturday, November 30, 2024

What are Google style docstrings?

 

If you are working with Python, sooner or later you will encounter the Google Style docstrings.

What are Google style docstrings?

Google docstrings are a special, custom format for documenting Python code based on Google's style guide for documentation. They completely and unambiguously document everything about the python code.

I will keep it simple. Let us say you need to concatenate two strings, "Hello," and " World" that you need to concatenate to produce, "Hello, World".

The python code will be:

====

str1 = "Hello,"

str2 = " World!"

result = str1 + str2

print(result)  # Output: Hello, World!

===========

This good for a simple stuff like this. Perhaps, it is unambiguous to most folks.

How does it look like?


You can appreciate as to how well it has documented. It has definition, arguments, returns neatly documented.

Now what does the Google style docstring looks like when pasted into Notepad, Surprise!

==========

str1 = "Hello"

str2 = " World!"

result = str1 + str2

print(result)  # Output: Hello World!

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

Well, Google-style docstrings are not simple text. They are a specific format used to document code in a structured way.

Notepad, as a basic text editor, cannot interpret this format. It simply displays the raw text.

While Notepad may not display the Google Style Docstring(GSD), there are other software

that can:

  • Visual Studio Code: A versatile code editor with excellent support for Python.


  • Atom: A customizable text editor with a focus on simplicity and extensibility.


  • Sublime Text: A powerful text editor with a wide range of plugins for various programming languages.


What is the use of this new rendering of the code and its documentation?

Here are some reasons why it's worth the effort:

  • Enhanced Code Clarity:

Clear and concise docstrings make it easier for others (and future you) to understand the code's intent and usage. Consistent formatting improves code readability and reduces cognitive load.

  • Improved Collaboration:

  • Sharing code with the team:

A shared style guide ensures that all team members are on the same page, leading to smoother collaboration and fewer misunderstandings.

  • Facilitated Code Review:

Clear docstrings make it easier for reviewers to understand the code's logic and identify potential issues.

  • Automated Documentation Generation:

Tools like Sphinx can automatically generate professional-looking documentation from well-formatted docstrings.


 


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 15, 2024

How do you work with color images in Python?

 Imagine a world without colors, all gray and boring. Imagine flowers, birds, animals devoid of their vibrant hues. It would indeed be a dreary world. Color is at the heart of everyday life and every field you can think of. Consider the blue of the sky, the red of a rose, and the emotions they evoke. The color of walls, matching furniture, and designer curtains all play a crucial role in our surroundings.

The importance of color spans across various activities and applications such as visual communication, aesthetics, brand identity, cognitive impact, and data visualization.

Python libraries we’ve explored (PIL and OpenCV) are robust and user-friendly tools for understanding color in images. They are invaluable in image processing and essential in computer vision.

This post considers the OpenCV library. The python codes are tested using PyCharm. There are more articles on this blog using PyCharm that you may want to look at.


For starters we take a beautiful colored image, The KISS we used earlier and convert it into a gray image. Later on the various other conversions it can make. It just takes a few lines of code. Voila, you have a gray image.

OpenCV's cvtColor() function is very versatile and it can be used to alter the color of the image.

In PyCharm, I create a new project, ColorChanges. It has no color related libraries and you need to install it. If you don't, you will have no such library error.


Installing the OpenCV Library:

You install Opencv-python from PyCharm's Terminal node.



This installs OpenCV as well as Numpy. Opencv-python 4.10.0.84 and numpy 2.1.3 are installed.

The following python code,  UsingOpenCV-_1.py. The PyCharm IDE provides excellent syntax highlighting and color .


Here is the script n text format:

import cv2
# Load the image
image_path = 'path_to_your_image.jpg'
image = cv2.imread(r'C:\Users\hoden\PycharmProjects\exploreImage\Images\TheKiss.jpg')
# Resize the image # You can change the width and height values to #fit your display
width = 738
height = 741
image_resized = cv2.resize(image, (width, height))
# Convert the image from BGR to grayscale
image_gray = cv2.cvtColor(image_resized, cv2.COLOR_BGR2GRAY)
# Save and display the grayscale image
cv2.imwrite('grayscale_image.jpg', image_gray)
cv2.imshow('Grayscale Image', image_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()

Notice that I use an image from another project by giving its absolute path. Also, the original image is pretty big (7380x7410) and if I do not resize, the resulting image after processing will be very large. You can see that cv2.resize() function ressies the image for the new width and height.

Converting color is a breeze with a single line using the function cvtColor().

The last two lines of code are for creating image display window on a keypress event and destroy after the user decides to close all openCV windows.

Here is the result of color conversion:

This is the original image 7380 pixels x 7410 pixels


This is the image after running the python code:










Friday, November 8, 2024

How are PyCharm projects structured?

 The projects created in PyCharm all go into a folder of projects that you can choose.

A new project in PyCharm comes up with two options:

  • Pure Python
  • Django

and opens in the default, Pure Python as shown in the image 

You provide a name for your , by overwriting the default, pythonProject

The location will be the owners folder in C:\Users

Next, it shows the interpreter related information. It creates Project's Venv, the virtual environment in the root of the project and the Python version and its location in the folder structure:

The next picture shows the Python interpreter related details and the version.



The Base conda tabbed page shows the Base conda installed. Conda is another package management and environment management system. 



A brief information about Conda is in the appendix.


The Custom environment tab shows the Type (default is Virtualenv) which is project specific and the location of the python interpreter and its location.

There are options to inherit packages from the base interpreter and also choose to make available the packages to all projects. If you don't choose to make available to all projects then it will be only available for the specific projects. 

When you choose to create a New Project using the Django option you display the following:

To use this option you must upgrade to PyCharm Professional. You also get support for Django templates with many more useful features like syntax and error highlighting, code completion, etc.

The next picture shows the HelloWorld project, a default project that PyCharm is shipped with. The .venv folder has all the packages and the libraries. 

It also has the scripts used in the project as shown:

In order to work with projects, knowing the IDE is very crucial.