Pillow-SIMD: A Powerful Image Processing Library

Pillow-SIMD: A Powerful Image Processing Library

Hello everyone! Today I want to introduce you to an amazing image processing library – Pillow-SIMD. As a Python developer who often deals with images, I can’t get enough of this library. It is the SIMD-accelerated version of Pillow, like installing a “rocket booster” on regular Pillow, making the processing speed astonishingly fast! Whether it’s simple image resizing, cropping, or complex filter effects and image enhancement, Pillow-SIMD can achieve it with outstanding performance. Let’s explore this powerful image processing tool together!

1. Basic Installation and Usage

First, install Pillow-SIMD (make sure to uninstall regular Pillow first):

pip uninstall Pillow
pip install pillow-simd

Basic image operations:

from PIL import Image
import numpy as np
import time

def compare_performance():
    """Compare performance improvement"""
    # Load a large image
    image = Image.open('large_image.jpg')
    
    # Test resizing operation
    start_time = time.time()
    for _ in range(100):
        resized = image.resize((800, 600))
    end_time = time.time()
    
    print(f"Processing 100 resize operations took: {end_time - start_time:.2f} seconds")
    
    # Save test results
    resized.save('resized_image.jpg')

compare_performance()

Tip: Pillow-SIMD is usually 4-8 times faster than regular Pillow, especially on CPUs that support AVX2/AVX512!

2. Image Enhancement

Implement various image enhancement effects:

from PIL import Image, ImageEnhance, ImageFilter
import numpy as np

class ImageProcessor:
    def __init__(self, image_path):
        self.image = Image.open(image_path)
    
    def enhance_image(self, brightness=1.2, contrast=1.2, 
                     sharpness=1.5, color=1.2):
        """Enhance image quality"""
        # Increase brightness
        enhancer = ImageEnhance.Brightness(self.image)
        img = enhancer.enhance(brightness)
        
        # Increase contrast
        enhancer = ImageEnhance.Contrast(img)
        img = enhancer.enhance(contrast)
        
        # Sharpen
        enhancer = ImageEnhance.Sharpness(img)
        img = enhancer.enhance(sharpness)
        
        # Adjust color
        enhancer = ImageEnhance.Color(img)
        img = enhancer.enhance(color)
        
        return img
    
    def apply_filters(self):
        """Apply filter effects"""
        # Gaussian blur
        blurred = self.image.filter(ImageFilter.GaussianBlur(radius=2))
        
        # Edge enhancement
        edge_enhanced = self.image.filter(ImageFilter.EDGE_ENHANCE)
        
        # Emboss effect
        embossed = self.image.filter(ImageFilter.EMBOSS)
        
        return {
            'blur': blurred,
            'edge': edge_enhanced,
            'emboss': embossed
        }

# Usage example
processor = ImageProcessor('test_image.jpg')
henhanced = processor.enhance_image()
henhanced.save('enhanced.jpg')

filters = processor.apply_filters()
for name, img in filters.items():
    img.save(f'{name}_effect.jpg')

3. Batch Processing and Optimization

Efficiently process a large number of images:

import os
from PIL import Image
from concurrent.futures import ThreadPoolExecutor
from functools import partial

class BatchProcessor:
    def __init__(self, input_dir, output_dir):
        self.input_dir = input_dir
        self.output_dir = output_dir
        os.makedirs(output_dir, exist_ok=True)
    
    def process_image(self, filename, size=(800, 600)):
        """Process a single image"""
        input_path = os.path.join(self.input_dir, filename)
        output_path = os.path.join(self.output_dir, filename)
        
        try:
            with Image.open(input_path) as img:
                # Convert to RGB mode (for PNG and other formats)
                if img.mode != 'RGB':
                    img = img.convert('RGB')
                
                # Resize image
                img = img.resize(size, Image.LANCZOS)
                
                # Optimize save
                img.save(output_path, 
                        'JPEG',
                        quality=85, 
                        optimize=True)
            return True
        except Exception as e:
            print(f"Processing {filename} failed: {str(e)}")
            return False
    
    def batch_process(self, max_workers=4):
        """Parallel batch process images"""
        filenames = [f for f in os.listdir(self.input_dir)
                    if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
        
        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            results = list(executor.map(self.process_image, filenames))
        
        success = sum(results)
        print(f"Successfully processed {success}/{len(filenames)} images")

# Usage example
processor = BatchProcessor('input_images', 'output_images')
processor.batch_process()

4. Image Composition and Watermarking

Create complex image effects:

from PIL import Image, ImageDraw, ImageFont
import numpy as np

class ImageCompositor:
    def __init__(self, base_image_path):
        self.base_image = Image.open(base_image_path)
    
    def add_watermark(self, text, font_size=40, opacity=0.5):
        """Add a semi-transparent watermark"""
        # Create watermark layer
        watermark = Image.new('RGBA', self.base_image.size, (0,0,0,0))
        draw = ImageDraw.Draw(watermark)
        
        # Load font
        font = ImageFont.truetype('arial.ttf', font_size)
        
        # Get text size
        text_size = draw.textsize(text, font)
        
        # Calculate position (bottom right corner)
        position = (
            self.base_image.size[0] - text_size[0] - 20,
            self.base_image.size[1] - text_size[1] - 20
        )
        
        # Draw watermark
        draw.text(
            position,
            text,
            font=font,
            fill=(255,255,255,int(255*opacity))
        )
        
        # Composite image
        return Image.alpha_composite(
            self.base_image.convert('RGBA'),
            watermark
        )
    
    def create_collage(self, images, rows, cols):
        """Create an image collage"""
        # Calculate individual image size
        w = self.base_image.size[0] // cols
        h = self.base_image.size[1] // rows
        
        # Create blank canvas
        collage = Image.new('RGB', self.base_image.size)
        
        # Fill images
        for idx, img_path in enumerate(images):
            if idx >= rows * cols:
                break
                
            img = Image.open(img_path)
            img = img.resize((w, h), Image.LANCZOS)
            
            x = (idx % cols) * w
            y = (idx // cols) * h
            
            collage.paste(img, (x, y))
        
        return collage

# Usage example
compositor = ImageCompositor('background.jpg')

# Add watermark
watermarked = compositor.add_watermark('© 2023 MyPhotos')
watermarked.save('watermarked.png')

# Create collage
image_files = ['img1.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg']
collage = compositor.create_collage(image_files, 2, 2)
collage.save('collage.jpg')

5. Image Analysis and Processing

Perform image analysis and special effects processing:

from PIL import Image, ImageStat
import numpy as np

class ImageAnalyzer:
    def __init__(self, image_path):
        self.image = Image.open(image_path)
        self.array = np.array(self.image)
    
    def get_dominant_colors(self, num_colors=5):
        """Get dominant colors"""
        # Convert to RGB mode
        img = self.image.convert('RGB')
        # Resize image to speed up processing
        img = img.resize((150, 150))
        
        # Convert to numpy array and reshape
        pixels = np.float32(img).reshape(-1, 3)
        
        # Use K-means clustering
        from sklearn.cluster import KMeans
        kmeans = KMeans(n_clusters=num_colors)
        kmeans.fit(pixels)
        
        # Get colors
        colors = kmeans.cluster_centers_
        
        return [tuple(map(int, color)) for color in colors]
    
    def auto_adjust(self):
        """Automatically adjust image"""
        # Automatic contrast
        stat = ImageStat.Stat(self.image)
        r,g,b = stat.mean
        
        # Calculate brightness adjustment
        brightness = 255 / max(r,g,b)
        
        # Apply adjustment
        adjusted = Image.fromarray(
            (self.array * brightness).astype(np.uint8)
        )
        
        return adjusted
    
    def create_artistic_effect(self, effect_type='sketch'):
        """Create artistic effects"""
        if effect_type == 'sketch':
            # Create sketch effect
            gray = self.image.convert('L')
            inv = ImageOps.invert(gray)
            blur = inv.filter(ImageFilter.GaussianBlur(radius=2))
            return ImageOps.invert(blur)
        
        elif effect_type == 'oil_painting':
            # Create oil painting effect
            return self.image.filter(ImageFilter.ModeFilter(size=9))
        
        return self.image

# Usage example
analyzer = ImageAnalyzer('test_image.jpg')

# Get dominant colors
colors = analyzer.get_dominant_colors()
print("Dominant colors:", colors)

# Auto adjust
adjusted = analyzer.auto_adjust()
adjusted.save('auto_adjusted.jpg')

# Create artistic effect
sketch = analyzer.create_artistic_effect('sketch')
sketch.save('sketch_effect.jpg')

Exercises

  1. Create an image batch processing tool that supports resizing and adding watermarks
  2. Implement an image filter system that includes various artistic effects
  3. Write an image analysis tool that calculates the dominant colors and statistics of the image

Conclusion

Today we learned the core features of Pillow-SIMD:

  • Basic image processing
  • Image enhancement techniques
  • Batch processing optimization
  • Image composition and watermarking
  • Image analysis and processing

When using Pillow-SIMD, be aware of:

  1. Ensure the CPU supports SIMD instruction sets
  2. Use multithreading wisely
  3. Pay attention to memory management
  4. Choose appropriate image save parameters

Pillow-SIMD is a powerful image processing tool that makes image processing both fast and simple. I hope everyone can use this amazing tool in real projects! Remember, good image processing should not only pursue effects but also focus on performance. Let’s create a wonderful world of images with Pillow-SIMD!

Pillow-SIMD: A Powerful Image Processing Library

Leave a Comment