You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python和Pillow自定义权重将彩色图转灰度图

Great question! I’ve dealt with exactly this when simulating film photography filters in PIL—here’s how you can implement custom RGB weightings to get those classic black-and-white filter effects.

First, a quick recap: PIL’s built-in convert('L') uses the standard ITU-R 601-2 formula:

L = R * 299/1000 + G * 587/1000 + B * 114/1000

But this doesn’t let you tweak weights for artistic filters. Instead, we can manually compute the grayscale values using our own custom weights.

Method 1: Using ImageMath.eval (Simple & PIL-Native)

This approach keeps everything within PIL’s ecosystem, no extra libraries needed. We’ll split the image into RGB channels, apply our weight formula, and merge back into a grayscale image.

from PIL import Image, ImageMath

def custom_filter_grayscale(image, r_weight, g_weight, b_weight):
    # Split the input image into its red, green, blue channels
    r_channel, g_channel, b_channel = image.split()
    
    # Calculate custom luminance using our weights
    custom_gray = ImageMath.eval(
        "r * rw + g * gw + b * bw",
        r=r_channel, g=g_channel, b=b_channel,
        rw=r_weight, gw=g_weight, bw=b_weight
    )
    
    # Convert the math result back to a PIL grayscale image (mode "L")
    return Image.merge("L", [custom_gray])

# Example 1: Red filter (only red contributes to brightness)
original_img = Image.open("your_photo.jpg")
red_filter_result = custom_filter_grayscale(original_img, 1.0, 0.0, 0.0)
red_filter_result.save("red_filter_bw.jpg")

# Example 2: Orange filter (mix red and green equally)
orange_filter_result = custom_filter_grayscale(original_img, 0.5, 0.5, 0.0)
orange_filter_result.save("orange_filter_bw.jpg")

Method 2: Using NumPy (Flexible for Larger Images/Complex Logic)

If you’re working with larger images or want to add extra processing (like contrast adjustments), using NumPy gives you more flexibility. It converts the image to an array, applies the weight formula, and converts back to a PIL image.

from PIL import Image
import numpy as np

def custom_filter_grayscale_np(image, r_weight, g_weight, b_weight):
    # Convert PIL image to a NumPy array (shape: [height, width, 3] for RGB)
    img_array = np.array(image)
    
    # Apply our custom weighting formula across all pixels
    gray_array = (
        img_array[..., 0] * r_weight +  # Red channel
        img_array[..., 1] * g_weight +  # Green channel
        img_array[..., 2] * b_weight    # Blue channel
    )
    
    # Ensure pixel values stay within the valid 0-255 range and convert to 8-bit integers
    gray_array = np.clip(gray_array, 0, 255).astype(np.uint8)
    
    # Convert back to a PIL grayscale image
    return Image.fromarray(gray_array, mode="L")

# Usage is identical to the PIL-native method
original_img = Image.open("your_photo.jpg")
orange_filter_result = custom_filter_grayscale_np(original_img, 0.5, 0.5, 0.0)
orange_filter_result.save("orange_filter_bw_np.jpg")

Quick Notes:

  • Weight Sums: You don’t have to make your weights add up to 1, but if their sum exceeds 1, use np.clip (or manually clamp values in ImageMath) to avoid over-bright pixels that get clipped unexpectedly.
  • Filter Accuracy: These methods mimic real glass filters perfectly—red filters will make red objects appear brighter and blue objects darker, just like shooting with a red filter on film.

内容的提问来源于stack exchange,提问作者Touko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:46:15