PIL实现“幻影坦克”图片特效

实现一种特定的图片特效“幻影坦克”,以下是一个实现这一效果的示例代码。

1. 设置环境

首先,确保你已安装 Pillow

pip install Pillow

2. 原理说明

在计算机视觉和数字图像处理中,RGB和RGBA图像是常见的图像表示形式。RGB颜色模式 有三个通道,分别是红Red、绿Green和蓝Blue。这种颜色模型通过将红、绿、蓝三原色的色光以不同的比例相加,以合成产生各种色彩光。RGBA颜色模式 则包含四个通道:红Red、绿Green、蓝Blue和透明度Alpha

灰度值:表征单色的亮暗程度。数值在0-255之间,数值大小表示允许通过色彩多少,越大,相应色彩越深。
透明度:数值在0-255之间,0完全透明,255完全不透明。

RGB图像中的R、G、B三通道灰度值相等时,图片也会是黑白色的,即为灰度图。

三通道图可以是灰度图,单通道图只能是灰度图。

RGBA图像中,若R、G、B三通道的值相等,图像将呈现为带透明度的灰色。如果Alpha值为255,则图像显示为相应的灰色;如果Alpha值小于255,则图像的显示效果会有背景色的影响,可能呈现出灰色与背景色的混合效果。

在这里插入图片描述
RGBA (4x8-bit pixels, true color with transparency)图像模式及其参数:

  • 扩展RGB模式,增加一个8位的透明度通道。
  • 适合需要透明效果的彩色图像。
  • R: 红色通道,值范围为 0 - 255。
  • G: 绿,0 - 255。
  • B: 蓝,0 - 255。
  • A: 透明度通道,0 - 255(0完全透明)。

逻辑:在保持/降低底层(interior.png)灰度影响的同时,提高上层图像(exterior.png)亮度,利用上层图像的亮度来调整整体的透明度。在合成图像时,我们用当前层图像的灰度值和透明度来决定最终的灰度值。如果 α \alpha α 较小(透明度越低),表示在合成中需要“放大”当前层的亮度,以确保合成后的效果能体现出底层和上层的真实关系。值得注意的是,实际情况下这可能需要更多的归一化处理,以确保输出值灰度值在有效的范围内(0 - 255)。

把RGBA图像视为由三张带有透明度的R、G、B通道图组成。

混合透明度 { α 1 = 255 − R 1 + R 2 α 2 = 255 − G 1 + G 2 α 3 = 255 − B 1 + B 2 混合透明度\begin{cases} \alpha_{1} = 255 - R_1 + R_2\\ \alpha_{2} = 255 - G_1 + G_2\\ \alpha_{3} = 255 - B_1 + B_2 \end{cases} 混合透明度 α1=255R1+R2α2=255G1+G2α3=255B1+B2

将三者拉到近似相等的水平,提高视觉一致性和色彩的自然性,这对于图像的质量、表现以及后续的操作都是至关重要的。
α = 255 − R 1 + R 2 \alpha = 255 - R_1 + R_2 α=255R1+R2

灰度值 { R = R 2 / α G = G 2 / α B = B 2 / α 灰度值\begin{cases} R ={R_2} /{\alpha}\\ G = {G_2}/{\alpha}\\ B = {B_2} /{\alpha} \end{cases} 灰度值 R=R2/αG=G2/αB=B2/α

3. 代码实现

准备两张大小一样的图,一张作为上层图像exterior.png,另一张作为底层图像interior.png。

  1. 加载图片:使用 PIL 库打开图像,并将其转换为 RGBA 模式。
  2. 创建图像:新建一个大小一样的空白图像。
  3. 合成图像:遍历每一个像素点,计算出R、G、B、A后填充到空白图片。
  4. 保存结果:将生成的图像保存到指定路径。
from PIL import Image

# Load two footage images and convert them to RGBA images
img1 = Image.open('exterior.png').convert('RGBA')
img2 = Image.open('interior.png').convert('RGBA')

# Adjust the brightness of the picture
img1 = img1.point(lambda p: int((p + 255) / 2)) # Lighten
img2 = img2.point(lambda p: int(p / 2)) # Darken

def create_phantom_tank_effect():
    img = Image.new('RGBA', img1.size) # New a blank picture
    # Go through each pixel, calculate the transparency and R, G, B value
    # Then fill in the blank picture
    for x in range(img.width):
        for y in range(img.height):
            # alpha = 255 - R1 + R2
            alpha = 255 - img1.getpixel((x, y))[0] + img2.getpixel((x, y))[0]
            # R = R2 / alpha
            R_value = int(img2.getpixel((x, y))[0] * 255 / alpha) if alpha else 127
            # G = G2 / alpha
            G_value = int(img2.getpixel((x, y))[1] * 255 / alpha) if alpha else 127
            # B = B2 / alpha
            B_value = int(img2.getpixel((x, y))[2] * 255 / alpha) if alpha else 127
            img.putpixel((x, y), (R_value, G_value, B_value, alpha))
    img.save('result.png')# Save it

# Example use
create_phantom_tank_effect()

4. 运行结果

替换 "exterior.png"interior.png以你的输入图像路径,并指定合适的输出路径 "result.png"。eg:

在这里插入图片描述在这里插入图片描述
exterior.pnginterior.png

运行代码后,查看输出的效果图像result.png。

浅色模式下深色模式下
在这里插入图片描述在这里插入图片描述

5. 批量处理

import os
from PIL import Image

# input folder path
input_folder = './input'

# get files
files = os.listdir(input_folder)

# Create a list to store matching files
img1_files = sorted([f for f in files if f.startswith('exterior') and f.endswith('.png')])
img2_files = sorted([f for f in files if f.startswith('interior') and f.endswith('.png')])

# Ensure that both lists have the same length
num_images = min(len(img1_files), len(img2_files))

def create_phantom_tank_effect_batch():
    for i in range(num_images):
        img1_path = os.path.join(input_folder, img1_files[i])
        img2_path = os.path.join(input_folder, img2_files[i])

        # Load two footage images and convert them to RGBA images
        img1 = Image.open(img1_path).convert('RGBA')
        img2 = Image.open(img2_path).convert('RGBA')

        img1 = img1.point(lambda p: int((p + 255) / 2))  # Lighten
        img2 = img2.point(lambda p: int(p / 2))  # Darken

        # New a blank picture
        img = Image.new('RGBA', img1.size)

        for x in range(img.width):
            for y in range(img.height):
                # alpha = 255 - R1 + R2
                alpha = 255 - img1.getpixel((x, y))[0] + img2.getpixel((x, y))[0]
                # R = R2 / alpha
                R_value = int(img2.getpixel((x, y))[0] * 255 / alpha) if alpha else 127
                # G = G2 / alpha
                G_value = int(img2.getpixel((x, y))[1] * 255 / alpha) if alpha else 127
                # B = B2 / alpha
                B_value = int(img2.getpixel((x, y))[2] * 255 / alpha) if alpha else 127
                img.putpixel((x, y), (R_value, G_value, B_value, alpha))
        # Save
        # output_folder = f'D:/coding/untitled/phantom_tank/output/result{i + 1}.png'
        output_folder = f'../output/result{i + 1}.png'
        result_path = os.path.join(input_folder, output_folder)
        img.save(result_path)
        print(f'Saved: {result_path}')

create_phantom_tank_effect_batch()
  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

镜花照无眠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值