如何在 Python 中删除部分 PNG 图像以使其不透明

How to remove part of a PNG image in Python to make it Opaque

我有一个在 PNG 图像上创建遮挡的脚本。来自https://arxiv.org/pdf/2001.04086.pdf.

的数据增强遮挡技术

脚本运行非常适合创建遮挡,但它们在 PNG 上绘制为黑色矩形。

我希望他们做的是从 PNG 中剪切出这些矩形,并使它们成为 PNG 的 alpha 层的一部分,这样当粘贴到背景之上时,背景会透过矩形显示出来。基本上使黑色矩形透明。

当前的执行输出如下所示:

下面是完整的脚本,但需要在此处工作的区域:

    # Draw each box onto the image
    for index, row in boxes.iterrows():
        shape = [(row['topleftcornerxpx'], row['topleftcornerypx']), (row['topleftcornerxpx'] + row['sizepx'], row['topleftcornerypx'] + row['sizepx'])]
        img1 = ImageDraw.Draw(img)
        img1.rectangle(shape, fill = "black")

已尝试添加 alpha 蒙版,但这会从背景中删除 alpha 通道并使矩形保持黑色。

    # Draw each box onto the image
    for index, row in boxes.iterrows():
        shape = [(row['topleftcornerxpx'], row['topleftcornerypx']), (row['topleftcornerxpx'] + row['sizepx'], row['topleftcornerypx'] + row['sizepx'])]
        mask = Image.new('L', img.size, color = 255)
        draw=ImageDraw.Draw(mask)
        img1 = ImageDraw.Draw(img)
        img1.rectangle(shape, fill=0)
        img.putalpha(mask)

完整脚本(有人可能会喜欢):

import os
from pandas import DataFrame
from PIL import Image, ImageDraw
import numpy as np

#set directories
directory = str("C:/GIT/Temp/Test/test/")
target_directory = str("C:/GIT/Temp/Test/test/occluded/")
occlusion_scales = [.20, .125, .08] #Percent of image the occlusions will cover. Add or remove as many as required.  
image_padding = int(5)

existing_files = os.listdir(target_directory)
#print(existing_files)

#Get files
for filename in os.listdir(directory):
  if filename.endswith('.png'):
      # Process for each occlusion scale in the list. 
      for scales in occlusion_scales:
        img = Image.open(directory + filename)
        # Get image dimensions
        imgwidth, imgheight = img.size
        # Get smallest value out of x & y to scale box size by. 
        box1sizepx = round(min(imgwidth,imgheight) * scales)
        print(filename)
        
        #Dont process files already processed, can comment out for replace. 
        if (filename.replace('.png','') + '_occluded_' + str(scales)+'.png') not in existing_files: 
            #print(filename + ' not in list')
            
            # Calculate number of boxes accross and down required
            boxesaccross = round((imgwidth/2) / box1sizepx)
            boxesdown = round((imgheight/2) / box1sizepx)

            # Create dataframe for boxes 
            boxes = DataFrame(columns=['sizepx','topleftcornerxpx','topleftcornerypx'])
            # Set row counter for loop.
            boxrow = 0

            #Draw a box for each row and within that each column
            while boxesdown >= 1:
                boxesdown = boxesdown -1
                boxcolumn = 0

                while boxesaccross >= 1: 
                    boxesaccross = boxesaccross -1
                    new_box = {'sizepx':box1sizepx,'topleftcornerxpx':round(box1sizepx*.8) + (box1sizepx * boxcolumn),'topleftcornerypx':round(box1sizepx*.8) + (box1sizepx * boxrow)}
                    boxes = boxes.append(new_box, ignore_index=True)
                    boxcolumn = boxcolumn + 2

                boxrow = boxrow + 2
                boxesaccross = round((imgwidth/2) / box1sizepx)

            # Draw each box onto the image
            for index, row in boxes.iterrows():
                shape = [(row['topleftcornerxpx'], row['topleftcornerypx']), (row['topleftcornerxpx'] + row['sizepx'], row['topleftcornerypx'] + row['sizepx'])]
                img1 = ImageDraw.Draw(img)
                img1.rectangle(shape, fill = "black")

            #Save the image 
            print(target_directory + filename.replace('.png','') + '_occluded_' + str(scales)+'.png')

            #Crop the image with some padding
            cropped_object = img.crop(((0 - image_padding), (0 - image_padding), (imgwidth + image_padding), (imgheight + image_padding)))
            cropped_object.save(target_directory + filename.replace('.png','') + '_occluded_' + str(scales)+'.png')

解决了,感谢@furas,将填充设置为 0 而不是“黑色”。如果有人需要,请更新脚本。

import os
from pandas import DataFrame
from PIL import Image, ImageDraw
import numpy as np

#set directories
directory = str("C:/GIT/Temp/Test/test/")
target_directory = str("C:/GIT/Temp/Test/test/occluded/")
occlusion_scales = [.20, .125, .08] #Percent of image the occlusions will cover. Add or remove as many as required.  
image_padding = int(5)

existing_files = os.listdir(target_directory)
#print(existing_files)

#Get files
for filename in os.listdir(directory):
  if filename.endswith('.png'):
      # Process for each occlusion scale in the list. 
      #pixdata = filename.load()
      #print(pixdata)
      for scales in occlusion_scales:
        img = Image.open(directory + filename)
        # Get image dimensions
        imgwidth, imgheight = img.size
        # Get smallest value out of x & y to scale box size by. 
        box1sizepx = round(min(imgwidth,imgheight) * scales)
        print(filename)
        
        #Dont process files already processed, can comment out for replace. 
        if (filename.replace('.png','') + '_occluded_' + str(scales)+'.png') not in existing_files: 
            #print(filename + ' not in list')
            
            # Calculate number of boxes accross and down required
            boxesaccross = round((imgwidth/2) / box1sizepx)
            boxesdown = round((imgheight/2) / box1sizepx)

            # Create dataframe for boxes 
            boxes = DataFrame(columns=['sizepx','topleftcornerxpx','topleftcornerypx'])
            # Set row counter for loop.
            boxrow = 0

            #Draw a box for each row and within that each column
            while boxesdown >= 1:
                boxesdown = boxesdown -1
                boxcolumn = 0

                while boxesaccross >= 1: 
                    boxesaccross = boxesaccross -1
                    new_box = {'sizepx':box1sizepx,'topleftcornerxpx':round(box1sizepx*.8) + (box1sizepx * boxcolumn),'topleftcornerypx':round(box1sizepx*.8) + (box1sizepx * boxrow)}
                    boxes = boxes.append(new_box, ignore_index=True)
                    boxcolumn = boxcolumn + 2

                boxrow = boxrow + 2
                boxesaccross = round((imgwidth/2) / box1sizepx)

            # Draw each box onto the image
            for index, row in boxes.iterrows():
                shape = [(row['topleftcornerxpx'], row['topleftcornerypx']), (row['topleftcornerxpx'] + row['sizepx'], row['topleftcornerypx'] + row['sizepx'])]
                img1 = ImageDraw.Draw(img)
                img1.rectangle(shape, fill = 0)

            #Save the image 
            print(target_directory + filename.replace('.png','') + '_occluded_' + str(scales)+'.png')

            #Crop the image with some padding
            cropped_object = img.crop(((0 - image_padding), (0 - image_padding), (imgwidth + image_padding), (imgheight + image_padding)))
            cropped_object.save(target_directory + filename.replace('.png','') + '_occluded_' + str(scales)+'.png')