4

我想编写一个函数,它将在这张照片的天空中创建一个随机数(在 m 和 n 之间,包括在内)的星星(http://tinypic.com/r/34il9hu/6)。我希望星星应该由单个白色像素或 4 个相邻白色像素组成的正方形随机组成。我也不想在树枝、月亮或鸟上放置一个“星星”(1 个像素)尽管

我将如何在 python 中执行此操作?任何人都可以帮忙吗?谢谢!

到目前为止我有这个:

到目前为止,我已经开始并提出了这个问题,我不知道其中任何一个是否正确,或者即使我走在正确的轨道上:

def randomStars(small, large):
   import random
   file = pickAFile()
   pic = makePicture(myPic)
   #x = random.randrange(getWidth(pic))
   #y = random.randrange(getHeight(pic))
   for pixel in pic.getAllPixels():
      if random.random() < 0.25:
         pixel.red = random.randint(256)
         pixel.green = random.randint(256)
         pixel.blue = random.randint(256) 
   show(pic)

我不知道我在做什么:(

4

3 回答 3

5

这看起来像是一个尝试超像素的好例子,由skimage实现。您可能可以以更简单的方式解决您的问题。

import urllib
import random
import io
import matplotlib.pyplot as plt
import skimage.segmentation
import pandas

# Read the image
f = io.BytesIO(urllib.urlopen('http://oi46.tinypic.com/34il9hu.jpg').read())
img = plt.imread(f, format='jpg')

# Prefer to keep pixels together based on location
# But not too much, so we still get some branches.
superpixel = skimage.segmentation.slic(img, n_segments=200, ratio=20)
plt.imshow(superpixel%7, cmap='Set2')

超像素

现在我们有了超像素,我们可以通过对每个超像素进行分类来更容易地进行分类。你可以在这里使用一些花哨的分类,但是这个例子很简单,天空是蓝色的,让我们手动做。

# Create a data frame with the relative blueish of every super pixel

# Convert image to hsv 
hsv = matplotlib.colors.rgb_to_hsv(img.astype('float32')/255)
# Define blueish as the percentage of pixels in the blueish range of the hue space
df =pandas.DataFrame({'superpixel':superpixel.ravel(), 
    'blue':((hsv[:,:,0] > 0.4) & (hsv[:,:,0]<0.8)).astype('float32').ravel(), 
    'value':hsv[:,:,2].ravel()})    
grouped = df.groupby('superpixel').mean()    
# Lookup the superpixels with the least blue
blue = grouped.sort('blue', ascending=True).head(100)
# Lookup the darkest pixels
light = grouped.sort('value', ascending=True).head(50)

# If superpixels are too dark or too blue, get rid of them
mask = (np.in1d(superpixel, light.index ).reshape(superpixel.shape) | 
    np.in1d(superpixel, blue.index ).reshape(superpixel.shape))

# Now we can put the stars on the blueish, not too darkish areas
def randomstar(img, mask):
    """random located star"""
    x,y = random.randint(1,img.shape[0]-1), random.randint(1,img.shape[1]-1)
    if not mask[x-1:x+1, y-1:y+1].any():
        # color not so random
        img[x,y,:] = 255
        img[x-1,y,:] = 255
        img[x+1,y,:] = 255
        img[x,y-1,:] = 255
        img[x,y+1,:] = 255

for i in range(100):
    randomstar(img, mask)
plt.imshow(img)

天空中的星星

于 2013-02-28T22:25:35.853 回答
3

Python 的标准库没有附带任何功能强大的图像处理代码,但有一些易于安装和使用的替代方案。我将展示如何使用PIL做到这一点。

from PIL import Image

def randomStars(small, large):
    import random
    filename = pickAFile()
    pic = Image.open(filename)
    max_x, max_y = pic.size
    pixels = im.load()
    x = random.randrange(max_x)
    y = random.randrange(max_y)
    for i in range(max_x):
        for j in range(max_y):
            if random.random() < 0.25:
                red = random.randint(256)
                green = random.randint(256)
                blue = random.randint(256) 
                pixels[i, j] = (red, green, blue, 1)
    im.show()

show函数不会在您的应用程序中显示图像(为此,您需要某种带有事件循环的 GUI,例如tkinteror PySide);它将文件保存到临时目录并运行特定于平台的程序(如 Preview 或 xv)来显示它。

我假设您还想保存文件。这也很容易:

    name, ext = os.path.splitext(filename)
    outfilename = '{}-with-stars.{}'.format(name, ext)
    im.save(outfilename)

这会将其保存回具有默认 JPEG 设置的 .jpg,依赖于 PIL 从文件名中猜测您想要的内容。(这意味着,是的,您可以使用 . 将其保存为 PNG '{}-with-stars.png'.format(name)。)如果您想要更多控制,PIL 也可以这样做,指定明确的格式和特定​​于格式的选项。


到目前为止,这只是如何将您现有的代码变成可以工作的东西,您可以使用它并开始调试;它实际上并没有回答原来的问题。

我想编写一个函数,它将在这张照片的天空中创建一个随机数(在 m 和 n 之间,包括在内)的星星

所以首先,你需要这个作为你的循环,而不是所有像素的循环:

for _ in random.randint(m, n):

现在:

我希望星星应该由单个白色像素或由 4 个相邻白色像素组成的正方形随机组成。

    x, y = random.randrange(max_x), random.randrange(max_y)
    if random.random() < .5:
        # draw white pixel at [x, y]
        pixels[x, y] = (1, 1, 1, 1)
    else:
        # draw square at [x, y], making sure to handle edges

我也不想在树枝、月亮或鸟上放置一个“星星”(1 像素)

您需要定义如何知道树枝、月亮或鸟的一部分。你能用像素颜色来定义吗?

乍一看,您似乎可以做到。月亮的像素比其他任何东西都更亮、更饱和、更偏红等(除了角落的AP标志,它更亮)。鸟和树枝比其他任何东西都更黑。事实上,它们是如此不同,以至于您甚至不必担心进行正确的色彩空间数学;它可能像这样简单:

r, g, b, a = pixels[x, y]
fake_brightness = r+g+b+a
if fake_brightness < 0.2:
    # Tree or bird, pick a new random position
elif 1.2 < fake_brightness < 2.8:
    # Moon, pick a new random position
else:
    # Sky or API logo, scribble away

(这些数字显然只是凭空捏造的,但经过一些试验和错误,应该可以为您提供可用的值。)

当然,如果您将此作为学习练习,您可能想学习正确的色彩空间数学,甚至可能编写一个边缘检测算法,而不是依赖于该图像如此简单可解析。

于 2013-02-28T20:34:21.963 回答
1

尝试以下方法:

for n in xrange(number_of_stars):
    # Find a good position
    while True:
        x, y = random_coords_in_image()
        if is_sky(image, x, y):
            break

    # paint a star there
    c = star_colour()

    if large_star():
        image.put(x, y, c)
        image.put(x, y+1, c)
        image.put(x+1, y+1, c)
        image.put(x+1, y, c)
    else:
        image.put(x, y, c)

我使用的功能非常不言自明;您可以实现is_sky在给定位置估计图像颜色的一些条件。

于 2013-02-28T20:37:04.413 回答