【问题标题】:Changing random pixels in a picture, python改变图片中的随机像素,python
【发布时间】:2013-02-28 20:28:33
【问题描述】:

我想编写一个函数,它会在这张照片的天空中创建一个随机数(m 和 n 之间,包括 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)

我不知道我在做什么:(

【问题讨论】:

  • 这是必须在其他图片上工作的东西吗? Gimp 可能是你最好的选择;-)。
  • @Hoopdady:为什么?他尝试做的所有事情在PILImageMagick 包装器、scipy 等任何一个中都很容易做到。
  • @abarnert 为什么到哪一部分?我想知道它是否需要在其他图片上工作,因为让它不覆盖鸟、月亮或树会专门针对这张图片。为什么要使用 gimp?因为它非常快地随机点击钢笔工具并在天空中放置一些 1x1 或 4x4 的白点。
  • 原始图像位于oi46.tinypic.com/34il9hu.jpg
  • @Hoopdady:啊,你是在建议他手动做,而不是编写程序来做,而不是他在 gimp-fu 中使用 Python。

标签: python image random pixels


【解决方案1】:

这看起来像是一个很好的例子来尝试superpixels,由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)

【讨论】:

    【解决方案2】:

    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,例如 tkinterPySide);它将文件保存到临时目录并运行特定于平台的程序(如 Preview 或 xv)来显示它。

    我假设您还想保存文件。这也很简单:

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

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


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

    我想写一个函数,它会在这张图片的天空中创建一个随机数(m 和 n 之间,包括 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
    

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

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

    【讨论】:

      【解决方案3】:

      尝试以下方法:

      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 估计给定位置图像颜色的一些条件。

      【讨论】:

      • 很抱歉,我不太明白,科斯
      猜你喜欢
      • 2017-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-01
      • 2021-10-05
      • 1970-01-01
      • 2012-09-07
      • 2021-01-18
      相关资源
      最近更新 更多