Как удалить часть изображения PNG в Python, чтобы сделать его непрозрачным

У меня есть скрипт, который создает окклюзии на изображениях PNG. Техника окклюзии увеличения данных из https://arxiv.org/pdf/2001.04086.pdf.

Скрипт работает хорошо для создания окклюзий, но они рисуются поверх PNG в виде черных прямоугольников.

Я бы хотел, чтобы они вырезали эти прямоугольники из PNG и сделали их частью альфа-слоя PNG, чтобы при вставке поверх фона фон отображался через прямоугольники. По сути, сделайте черные прямоугольники прозрачными.

Текущие выходные данные реализации выглядят следующим образом:

Полный сценарий ниже, но здесь необходимо поработать над областью:

          # 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")

Пробовали добавить альфа-маску, но это удаляет альфа-канал с фона и оставляет прямоугольники черными.

          # 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')

1 ответ

Решено спасибо @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')
Другие вопросы по тегам