Как удалить часть изображения 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')