2013-02-28 32 views
3

我想寫一個函數,它會在這張圖片的天空中創建一個隨機數(在m和n之間,包括m和n)(http://tinypic.com/r/34il9hu/6)。我想要星星應該隨機組成一個單一的白色像素,或一個4個相鄰的白色像素的正方形。我也不想在樹枝,月亮或鳥上放置一顆'星'(1像素)雖然改變圖片中的隨機像素,python

我該如何在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) 

我不知道我在做什麼:(

+0

這東西,有在其他照片的效果? Gimp可能是你最好的選擇;-)。 – Hoopdady 2013-02-28 20:34:50

+0

@Hopopady:爲什麼?他想要做的每件事都很容易在'PIL','ImageMagick'包裝器,'scipy'等等中完成。 – abarnert 2013-02-28 20:38:01

+0

@abarnert爲何選擇哪一部分?我想知道它是否需要在其他圖片上工作,因爲它不會覆蓋鳥,月亮或樹木,而是要針對這一個。爲什麼使用gimp?因爲它的超級快速隨機點擊鋼筆工具,並在天空中放置一些1x1或4x4的白點。 – Hoopdady 2013-02-28 20:41:22

回答

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之間(含)),你需要這個作爲你的循環,而不是遍歷所有像素:現在

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

我要天上的星星應該隨機組成d爲單個白色像素或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 

(這些數字顯然只是無中生有的,但有點試驗和錯誤應該給你可用值。)

當然,如果你在做這個學習練習,你可能想要學習正確的色彩空間數學,甚至可以編寫一個邊緣檢測算法,而不是依賴這個圖像是如此簡單的解析。

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估計給定位置的圖像顏色的一些條件。

+0

我很抱歉,我真的不明白,科斯 – Oliver 2013-02-28 21:23:49

4

這看起來像一個很好的例子,試用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') 

Superpixels

現在我們有了超級像素,我們可以做的分類更容易一點,做它每超像素。你可以在這裏用一些奇特的分類,但這個例子很簡單,藍天,讓我們手工完成。

# 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) 

stars in the sky