使用 PIL 排列二进制掩码中的像素
Permuting Pixels Within a Binary Mask with PIL
我完全被这个问题困住了 - 我需要随机排列 2D 图像上圆圈内的像素。我需要这个用于我正在设计的实验,其中搜索这个小的乱序圆圈将作为任务的低级感知部分。重要的是像素来自图像本身而不是随机值,以保持修改和未修改图像之间的图像强度均匀。
我不太了解 Python 所以到目前为止我的代码很乱 - 我首先打开图像,并确保它是 RGB。然后我做了一个深拷贝(因为我将用蒙版修改原件,但我仍然需要实际的原始像素值)。然后我画了一个亮红色的圆圈(255,0,0),然后把pix_mask定义为红色为255的地方(我们的刺激是自然场景和物体,所以应该没有其他地方图像与此)。然后我使用 pix_mask
创建一个新的蒙版图像,并将蒙版乘以复制的图像数据以获得圆圈内的数据。听起来很乱,但结果如下:
这是我用来执行此操作的代码:
def create_pixel_mask_images(image_fname: str):
# Open the image which requires a scrambled dot. Add an alpha channel and make a copy of the data
image: JpegImage = Image.open(image_fname)
image = image.convert("RGB")
image_copy = image.copy()
# Create the drawer and draw a filled red circle on the original image (255, 0, 0)
image_draw = ImageDraw.Draw(image)
image_draw.ellipse((150, 150, 250, 250), fill = "red")
image.save("TEST_DOT.png")
# Read the data from the copy and the now-modified original image into arrays
image_arr: NumpyArray = numpy.array(image)
image_copy_arr: NumpyArray = numpy.array(image_copy)
# Create a binary mask by testing for the red circle we drew on the original image (255 red)
pix_mask: NumpyArray = image_arr[:, :, 0] == 255
# Invert the mask (i.e., everything outside of the dot is now white, and the dot black)
# Write them out to file to error-check
mask_image: PILImage = Image.fromarray((pix_mask * 255).astype(numpy.uint8))
image.convert("RGB")
mask_image_inverse: PILImage = ImageOps.invert(mask_image)
image.convert("RGB")
pix_mask_inverse: NumpyArray = numpy.array(mask_image_inverse)
# Read the inverted pixel mask as a numpy array. Multiply the unmodified image by both masks
# in order to get the data both inside and outside of the mask
inner_data = image_copy_arr * pix_mask[..., None]
outer_data = image_copy_arr * pix_mask_inverse[..., None]
# Create new images from the masked data
inner_image: PILImage = Image.fromarray(inner_data.astype(numpy.uint8))
outer_image: PILImage = Image.fromarray(outer_data.astype(numpy.uint8))
outer_image = ImageOps.invert(outer_image)
# AS A CHECK multiply the inner- and outer-masked images together. We should get the original image back
image_data = image.load()
for y in range(image.size[1]):
for x in range(image.size[0]):
if image_data[x, y] == (255, 0, 0):
image_data[x, y] = (255, 255, 255)
recombined_image = ImageChops.multiply(inner_image, outer_image)
inner_image.save('INNER_DATA.png')
mask_image.save('MASK.jpg')
mask_image_inverse.save('MASK_INVERSE.jpg')
recombined_image.save('RECOMBINATION_TEST.jpg')
你可以在底部看到我通过将 inner_image
(圆掩码内的数据)与 outer_image
(其余部分)相乘来创建 recombined_image
圆掩码外的数据一起;然而,我最终得到了与这里第二张图片相同的图像(只是圆圈内的数据)。
我在这里使用嵌套的 for
-loop 将原始图像中的任何红色像素设置为白色,就好像我将该区域保留为黑色一样我会丢失那里的数据(检查文档 ImageChops.multiply()
- Docs)。我还尝试了 ImageChops.overlay()
函数,结果相同 - 除了之前被屏蔽的部分外全黑。
所以现在,我有了蒙版图像,太棒了;但是,我似乎无法将这个蒙版区域与原始区域重新组合。首先,在执行此操作之前,无论如何我都需要能够置换屏蔽区域内的数据。
到目前为止,我的解决方案看起来一团糟,我确信必须有更多 straightforward/elegant 的方法来实现我的需要。有人可以帮忙吗?
好的,这对我有用。我的测试图像大约是 2k x 1500,所以我选择了一个靠近中心的圆圈。我只是在那个圈子内随机选择 75,000 对并交换它们。当然,结果看起来像静态的。
from PIL import Image
import numpy as np
import math
import random
img = Image.open('Melody1.jpg')
img = np.asarray(img.getdata()).reshape(img.size[1],img.size[0],3)
print(img.shape)
center = (1000, 800)
radius = 150
for i in range(75000):
r1 = radius * math.sqrt(random.random())
t1 = random.random() * 2 * math.pi
r2 = radius * math.sqrt(random.random())
t2 = random.random() * 2 * math.pi
x1 = int(center[0] + r1 * math.cos(t1))
y1 = int(center[1] + r1 * math.sin(t1))
x2 = int(center[0] + r2 * math.cos(t2))
y2 = int(center[1] + r2 * math.sin(t2))
img[x1,y1,:], img[x2,y2,:] = img[x2,y2,:], img[x1,y1,:]
print(img.shape)
outimg = Image.fromarray(img.astype(np.uint8))
outimg.save( 'other.jpg' )
这是生成的图像。你会想要做更多的交换以使其无法识别。
我完全被这个问题困住了 - 我需要随机排列 2D 图像上圆圈内的像素。我需要这个用于我正在设计的实验,其中搜索这个小的乱序圆圈将作为任务的低级感知部分。重要的是像素来自图像本身而不是随机值,以保持修改和未修改图像之间的图像强度均匀。
我不太了解 Python 所以到目前为止我的代码很乱 - 我首先打开图像,并确保它是 RGB。然后我做了一个深拷贝(因为我将用蒙版修改原件,但我仍然需要实际的原始像素值)。然后我画了一个亮红色的圆圈(255,0,0),然后把pix_mask定义为红色为255的地方(我们的刺激是自然场景和物体,所以应该没有其他地方图像与此)。然后我使用 pix_mask
创建一个新的蒙版图像,并将蒙版乘以复制的图像数据以获得圆圈内的数据。听起来很乱,但结果如下:
这是我用来执行此操作的代码:
def create_pixel_mask_images(image_fname: str):
# Open the image which requires a scrambled dot. Add an alpha channel and make a copy of the data
image: JpegImage = Image.open(image_fname)
image = image.convert("RGB")
image_copy = image.copy()
# Create the drawer and draw a filled red circle on the original image (255, 0, 0)
image_draw = ImageDraw.Draw(image)
image_draw.ellipse((150, 150, 250, 250), fill = "red")
image.save("TEST_DOT.png")
# Read the data from the copy and the now-modified original image into arrays
image_arr: NumpyArray = numpy.array(image)
image_copy_arr: NumpyArray = numpy.array(image_copy)
# Create a binary mask by testing for the red circle we drew on the original image (255 red)
pix_mask: NumpyArray = image_arr[:, :, 0] == 255
# Invert the mask (i.e., everything outside of the dot is now white, and the dot black)
# Write them out to file to error-check
mask_image: PILImage = Image.fromarray((pix_mask * 255).astype(numpy.uint8))
image.convert("RGB")
mask_image_inverse: PILImage = ImageOps.invert(mask_image)
image.convert("RGB")
pix_mask_inverse: NumpyArray = numpy.array(mask_image_inverse)
# Read the inverted pixel mask as a numpy array. Multiply the unmodified image by both masks
# in order to get the data both inside and outside of the mask
inner_data = image_copy_arr * pix_mask[..., None]
outer_data = image_copy_arr * pix_mask_inverse[..., None]
# Create new images from the masked data
inner_image: PILImage = Image.fromarray(inner_data.astype(numpy.uint8))
outer_image: PILImage = Image.fromarray(outer_data.astype(numpy.uint8))
outer_image = ImageOps.invert(outer_image)
# AS A CHECK multiply the inner- and outer-masked images together. We should get the original image back
image_data = image.load()
for y in range(image.size[1]):
for x in range(image.size[0]):
if image_data[x, y] == (255, 0, 0):
image_data[x, y] = (255, 255, 255)
recombined_image = ImageChops.multiply(inner_image, outer_image)
inner_image.save('INNER_DATA.png')
mask_image.save('MASK.jpg')
mask_image_inverse.save('MASK_INVERSE.jpg')
recombined_image.save('RECOMBINATION_TEST.jpg')
你可以在底部看到我通过将 inner_image
(圆掩码内的数据)与 outer_image
(其余部分)相乘来创建 recombined_image
圆掩码外的数据一起;然而,我最终得到了与这里第二张图片相同的图像(只是圆圈内的数据)。
我在这里使用嵌套的 for
-loop 将原始图像中的任何红色像素设置为白色,就好像我将该区域保留为黑色一样我会丢失那里的数据(检查文档 ImageChops.multiply()
- Docs)。我还尝试了 ImageChops.overlay()
函数,结果相同 - 除了之前被屏蔽的部分外全黑。
所以现在,我有了蒙版图像,太棒了;但是,我似乎无法将这个蒙版区域与原始区域重新组合。首先,在执行此操作之前,无论如何我都需要能够置换屏蔽区域内的数据。
到目前为止,我的解决方案看起来一团糟,我确信必须有更多 straightforward/elegant 的方法来实现我的需要。有人可以帮忙吗?
好的,这对我有用。我的测试图像大约是 2k x 1500,所以我选择了一个靠近中心的圆圈。我只是在那个圈子内随机选择 75,000 对并交换它们。当然,结果看起来像静态的。
from PIL import Image
import numpy as np
import math
import random
img = Image.open('Melody1.jpg')
img = np.asarray(img.getdata()).reshape(img.size[1],img.size[0],3)
print(img.shape)
center = (1000, 800)
radius = 150
for i in range(75000):
r1 = radius * math.sqrt(random.random())
t1 = random.random() * 2 * math.pi
r2 = radius * math.sqrt(random.random())
t2 = random.random() * 2 * math.pi
x1 = int(center[0] + r1 * math.cos(t1))
y1 = int(center[1] + r1 * math.sin(t1))
x2 = int(center[0] + r2 * math.cos(t2))
y2 = int(center[1] + r2 * math.sin(t2))
img[x1,y1,:], img[x2,y2,:] = img[x2,y2,:], img[x1,y1,:]
print(img.shape)
outimg = Image.fromarray(img.astype(np.uint8))
outimg.save( 'other.jpg' )
这是生成的图像。你会想要做更多的交换以使其无法识别。