Python 使图像的对象彼此最接近
我对PIL没有太多经验,我从一堆显微镜图像细胞中编辑了这些图像,每个细胞都在一个30x30大小的掩模中。我一直在努力把这些细胞放在一个黑色的背景中,尽可能地相互靠近而不重叠 我的代码如下:Python 使图像的对象彼此最接近,python,image-processing,computer-vision,python-imaging-library,Python,Image Processing,Computer Vision,Python Imaging Library,我对PIL没有太多经验,我从一堆显微镜图像细胞中编辑了这些图像,每个细胞都在一个30x30大小的掩模中。我一直在努力把这些细胞放在一个黑色的背景中,尽可能地相互靠近而不重叠 我的代码如下: def spread_circles(circles, rad, iterations,step): radsqr = rad**2 for i in range(iterations): for ix,c in enumerate(circles):
def spread_circles(circles, rad, iterations,step):
radsqr = rad**2
for i in range(iterations):
for ix,c in enumerate(circles):
vecs = c-circles
dists = np.sum((vecs)**2,axis=1)
if len(dists)>0:
push = (vecs[dists<radsqr,:].T*dists[dists<radsqr]).T
push = np.sum(push,axis=0)
pushmag = np.sum(push*push)**0.5
if pushmag>0:
push = push/pushmag*step
circles[ix]+=push
return circles
def gen_image(sample,n_iter, height=850, width = 850, max_shape=30, num_circles=150):
circles = np.random.uniform(low=max_shape,high=height-max_shape,size=(num_circles,2))
circles = spread_circles(circles, max_shape, n_iter, 1).astype(int)
img = Image.new(mode='F',size=(height,width),color=0).convert('RGBA')
final1 = Image.new("RGBA", size=(height,width))
final1.paste(img, (0,0), img)
for n,c in enumerate(circles):
foreground = sample[n]
final1.paste(foreground, (c[0],c[1]), foreground)
return final1
def spread_圆(圆、rad、迭代、步长):
radsqr=rad**2
对于范围内的i(迭代):
对于ix,枚举中的c(圆圈):
vecs=c-圆
距离=np.和((向量)**2,轴=1)
如果len(dists)>0:
push=(vecs[dists我已经开始考虑这一点,并且已经实施了一些策略。任何其他想找点乐趣的人都欢迎借用、窃取、盗用或破解我的代码中任何他们可以使用的部分!明天我可能还会玩一些
#!/usr/bin/env python3
from PIL import Image, ImageOps
import numpy as np
from glob import glob
import math
def checkCoverage(im):
"""Determines percentage of image that is cells rather than background"""
N = np.count_nonzero(im)
return N * 100 / im.size
def loadImages():
"""Load all cell images in current directory into list of trimmed Numpy arrays"""
images = []
for filename in glob('*.png'):
# Open and convert to greyscale
im = Image.open(filename).convert('L')
# Trim to bounding box
im = im.crop(im.getbbox())
images.append(np.array(im))
return images
def Strategy1():
"""Get largest image and pad all images to that size - at least it will tesselate perfectly"""
images = loadImages()
N = len(images)
# Find height of tallest image and width of widest image
maxh = max(im.shape[0] for im in images)
maxw = max(im.shape[1] for im in images)
# Determine how many images we will pack across and down the output image - could be improved
Nx = int(math.sqrt(N))+1
Ny = int(N/Nx)+1
print(f'Padding {N} images each to height:{maxh} x width:{maxw}')
# Create output image
res = Image.new('L', (Nx*maxw,Ny*maxh), color=0)
# Pack all images from list onto regular grid
x, y = 0, 0
for im in images:
this = Image.fromarray(im)
h, w = im.shape
# Pack this image into top-left of its grid-cell, unless
# a) in first row, in which case pack to bottom
# b) in first col, in which case pack to right
thisx = x*maxw
thisy = y*maxh
if y==0:
thisy += maxh - h
if x==0:
thisx += maxw - w
res.paste(this, (thisx,thisy))
x += 1
if x==Nx:
x = 0
y += 1
# Trim extraneous black edges
res = res.crop(res.getbbox())
# Save as JPEG so we don't find it as a PNG in next strategy
res.save('strategy1.jpg')
cov = checkCoverage(np.array(res))
print(f'Strategy1 coverage: {cov}')
def Strategy2():
"""Rotate all images to portrait (tall rather than wide) and order by height so we tend to stack equal height images side-by-side"""
tmp = loadImages()
# Recreate list with all images in portrait format, i.e. tall
portrait = []
for im in tmp:
if im.shape[0] >= im.shape[1]:
# Already portrait, add as-is
portrait.append(im)
else:
# Landscape, so rotate
portrait.append(np.rot90(im))
images = sorted(portrait, key=lambda x: x.shape[0], reverse=True)
N = len(images)
maxh, maxw = 31, 31
# Determine how many images we will pack across and down the output image
Nx = int(math.sqrt(N))+1
Ny = int(N/Nx)+1
print(f'Packing images by height')
# Create output image
resw, resh = Nx*maxw, Ny*maxh
res = Image.new('L', (resw,resh), color=0)
# Pack all from list
xpos, ypos = 0, 0
# Pack first row L->R, second row R->L and alternate
packToRight = True
for im in images:
thisw, thish = im.shape
this = Image.fromarray(im)
if packToRight:
if xpos+thisw < resw:
# If it fits to the right, pack it there
res.paste(this,(xpos,ypos))
xpos += thisw
else:
# Else start a new row, pack at right end and continue packing to left
packToRight = False
res.paste(this,(resw-thisw,ypos))
ypos = res.getbbox()[3]
else:
if xpos>thisw:
# If it fits to the left, pack it there
res.paste(this,(xpos-thisw,ypos))
xpos -= thisw
else:
# Else start a new row, pack at left end and continue packing to right
ypos = res.getbbox()[3]
packToRight = True
res.paste(this,(0,ypos))
# Trim any black edges
res = res.crop(res.getbbox())
# Save as JPEG so we don't find it as a PNG in next strategy
res.save('strategy2.jpg')
cov = checkCoverage(np.array(res))
print(f'Strategy2 coverage: {cov}')
Strategy1()
Strategy2()
!/usr/bin/env python3
从PIL导入图像,图像操作
将numpy作为np导入
从全局导入全局
输入数学
def检查覆盖率(im):
“”“确定作为单元格而不是背景的图像的百分比”“”
N=np.计数非零(im)
返回N*100/im尺寸
def loadImages():
“”“将当前目录中的所有单元格图像加载到修剪过的Numpy数组列表中”“”
图像=[]
对于glob('*.png')中的文件名:
#打开并转换为灰度
im=Image.open(filename.convert('L'))
#修剪到边界框
im=im.crop(im.getbbox())
images.append(np.array(im))
返回图像
def Strategy1():
“”“获取最大的图像并将所有图像填充到该大小-至少它会完美地镶嵌”“”
images=loadImages()
N=透镜(图像)
#查找最高图像的高度和最宽图像的宽度
maxh=max(图像中im的im.shape[0])
maxw=max(图像中im的im.shape[1])
#确定我们将在输出图像上下打包多少图像-可以改进
Nx=int(数学sqrt(N))+1
Ny=int(N/Nx)+1
打印(f'填充{N}个图像,每个图像的高度:{maxh}x宽度:{maxw}')
#创建输出图像
res=Image.new('L',(Nx*maxw,Ny*maxh),color=0)
#将列表中的所有图像打包到常规网格中
x、 y=0,0
对于图像中的即时消息:
this=Image.fromarray(im)
h、 w=im.shape
#将此图像打包到其网格单元格的左上角,除非
#a)在第一排,在这种情况下,包装到底部
#b)在第一列中,在这种情况下,向右包装
thisx=x*maxw
thisy=y*maxh
如果y==0:
thisy+=maxh-h
如果x==0:
thisx+=maxw-w
res.paste(this,(thisx,thisy))
x+=1
如果x==Nx:
x=0
y+=1
#修剪无关的黑色边缘
res=res.crop(res.getbbox())
#另存为JPEG,这样我们在下一个策略中不会发现它是PNG
res.save('strategy1.jpg')
cov=检查覆盖率(np.数组(res))
打印(f'Strategy1覆盖范围:{cov}')
def Strategy2():
“”“将所有图像旋转为纵向(高而不是宽)并按高度排序,以便我们倾向于将等高图像并排堆叠”“”
tmp=loadImages()
#以纵向格式重新创建包含所有图像的列表,即
肖像=[]
对于tmp中的im:
如果im.shape[0]>=im.shape[1]:
#已绘制肖像,按原样添加
肖像。附加(im)
其他:
#风景,所以旋转
纵向附加(np.rot90(im))
图像=已排序(纵向,关键点=λx:x.shape[0],反向=真)
N=透镜(图像)
maxh,maxw=31,31
#确定我们将在输出图像上下打包多少图像
Nx=int(数学sqrt(N))+1
Ny=int(N/Nx)+1
打印(f‘按高度包装图像’)
#创建输出图像
resw,resh=Nx*maxw,Ny*maxh
res=Image.new('L',(resw,resh),color=0)
#从列表中打包所有内容
xpos,ypos=0,0
#打包第一行L->R,第二行R->L和备用
packToRight=True
对于图像中的即时消息:
thisw,thish=im.shape
this=Image.fromarray(im)
如果包装正确:
如果xpos+thiswthisw:
#如果放在左边,就放在那里
res.paste(此(xpos thisw,ypos))
xpos-=thisw
其他:
#否则,开始新的一行,在左端打包,然后继续向右打包
ypos=res.getbbox()[3]
packToRight=True
res.paste(此(0,ypos))
#修剪任何黑色边缘
res=res.crop(res.getbbox())
#另存为JPEG,这样我们在下一个策略中不会发现它是PNG
res.save('strategy2.jpg'))
cov=检查覆盖率(np.数组(res))
打印(f'Strategy2覆盖范围:{cov}')
战略1()
战略2()
战略1的覆盖率为42%:
战略2的覆盖率为64%:
问题很酷!我不清楚他们最初是如何陷入如此混乱的?你们有没有单独的图像(每个图像小于30x30)不知何故,你可以像那样分享它们..例如,Dropbox、Google drive中单独图像的Zip存档?或者我应该从你的两张图像中的第一张中剪切它们吗?另外,我最初的想法是OpenCV或skimage可能是一个更好的工具选择。请问有什么限制?我并不拒绝skimage或OpenCV的一个好方法,事实上我是从h openCv然后我努力获得图像的透明度,然后我找到了一种使用PIL的更简单的方法。下面的链接中有图像。没有主要限制,只是希望对象彼此靠近,并在黑色图像背景中,正如我用红色圆圈显示的那样。那么开始沿着这些线排列的东西怎么样?是细胞吗允许在最终图像中触摸?允许旋转它们吗?您看过吗