2011-11-30 71 views
2

我希望對某些人來說這是一個有趣的問題。根據底層圖像的亮度設置隨機位置上的像素

我想在圖像上的隨機位置上創建一些像素,但隨機化應該取決於亮度,所以創建像素的可能性應該在圖像的明亮部分較高,在較暗部分較低(但仍有可能)。

讓我們這個形象的比方:

Clouds

我想創建一個功能SetRandomizedPixel這將讓該位圖,它設置在一個隨機位置的像素。在位置1上創建像素的可能性應該很高,在位置2中等和位置3低。

Clouds with numbers

我與C#和位圖/圖形的工作,但是這不應該的問題。

我唯一需要的是一個建議如何開始,因爲我找不出一個好的方法來存檔這個。

也許讀取所有圖像像素的亮度和位置,並按亮度對列表進行排序 - 但是,如何隨機選擇哪個更喜歡亮區?


UPDATE:在圖像上答案工作

下面的代碼的結果是這樣的:

Randomized image

但是,如果我們仔細看的也有很多像素的左側:

Randomized image zoomed

這是代碼(C#/ MVC3):

public ActionResult RandomTest() 
{ 

    const int points = 500; 

    Bitmap bitmap = new Bitmap(Server.MapPath("~/Files/random-test.jpg")); 
    Random random = new Random(); 

    int imageWidth = bitmap.Width; 
    int imageHeight = bitmap.Height; 

    float[][] weightedPixels = ConvertImageToGrayScale(bitmap); 
    float totalValue = weightedPixels.Sum(i => i.Sum()); 

    for (var y = 0; y < imageHeight - 1; y++) 
    { 
     for (var x = 0; x < imageWidth - 1; x++) 
     { 
      weightedPixels[y][x] /= totalValue; 
     } 
    } 

    for (var i = 0; i < points; i++) 
    { 
     double randomNumber = random.NextDouble(); 
     double currentSum = 0; 
     for (var y = 0; y < imageHeight - 1; y++) 
     { 
      for (var x = 0; x < imageWidth - 1; x++)      
      { 
       currentSum += weightedPixels[y][x]; 
       if (currentSum >= randomNumber) 
       { 
        bitmap.SetPixel(x, y, Color.Red); 
        break; 
       } 
      } 
     } 
    } 

    // output 
    var stream = new MemoryStream(); 
    bitmap.Save(stream, ImageFormat.Png); 
    return File(stream.ToArray(), "image/png"); 
} 


public float[][] ConvertImageToGrayScale(Bitmap bm) 
{ 
    var b = new Bitmap(bm); 
    var data = new List<float[]>(); 
    for (var i = 0; i < b.Width; i++) 
    { 
     var row = new List<float>(); 
     for (int x = 0; x < b.Height; x++) 
     { 
      var oc = b.GetPixel(i, x); 
      var grayScale = (int)((oc.R * 0.3) + (oc.G * 0.59) + (oc.B * 0.11)); 
      row.Add(grayScale); 
     } 
     data.Add(row.ToArray()); 
    } 
    return data.ToArray(); 
} 

回答

4

你可以拍攝照片的灰度圖像,然後總結的像素的總數的值。然後,如果你通過這個總數來劃分每個像素,你會得到一個權重。然後你選擇一個介於0和1之間的數字,並從第一個加權像素開始,並保持加起來,直到你到達第一個像素,使總和大於你的隨機數。然後在原始圖像上對該像素着色,但是您需要。

編輯:的僞代碼

int imageWidth = ... 
int imageHeight = ... 
int[][] grayScale = ConvertImageToGrayScale(yourImage); 
int totalValue = grayScale.Sum(); 

float[][] weightedPixels = grayScale.AsType(float[][]); 
for (int y in 0...imageHeight-1) 
    for (int x in 0...imageWidth-1) 
     weightedPixels[y][x] /= totalValue; 

float randomNumber = RandomReal(); 
float currentSum = 0; 
for (int y in 0...imageHeight-1) 
    for (int x in 0...imageWidth-1) 
     currentSum += weightedPixels[y][x]; 
     if (currentSum >= randomNumber) 
      break 2; // Here is your random pixel at (x, y) 

編輯:理論

這背後的理論是,我們希望將圖像轉換成基於每個像素的亮度的概率分佈。通過這種方式,更亮的像素比更暗的像素更有可能被選中。轉換爲灰度有助於我們生成PDF或weightedMatrix,方法是將每個像素減少爲單個數字而不是RGB三元組。我們用灰度矩陣的總和來得到創建加權矩陣所需的總值。加權矩陣用灰度矩陣初始化,但每個元素除以總權重。這意味着加權矩陣的總和爲1,這是它表示PDF的要求。現在我們可以選擇一個介於0和1之間的隨機概率。使用這個概率,我們通過沿加權矩陣求和來選擇一個像素,直到總和剛好大於我們的概率。發生這種情況的像素是我們隨機選取的像素。這是從列表中隨機選擇一個項目的標準方法,其中每個項目都有相關的概率。

編輯:固定左側線

的OP長大問題具有與從循環中Y,X掃描線的陣列上boundry條件。如果將代碼重新編制爲使用線性數組,然後將索引轉換爲X,Y對,則左側的實線將被刪除。如果主要方法的中間塊更改爲以下,則其按​​預期工作:

float[] weightedPixels = ConvertImageToGrayScale(bitmap).SelectMany(r => r).ToArray(); 
float totalValue = weightedPixels.Sum(); 

for (int i = 0; i < weightedPixels.Length; i++) { 
     weightedPixels[i] /= totalValue; 
} 

for (int pIdx = 0; pIdx < points; pIdx++) 
{ 
    double randomNumber = random.NextDouble(); 
    double currentSum = 0; 
    for (int i = 0; i < weightedPixels.Length; i++) 
    { 
     currentSum += weightedPixels[i]; 
     if (currentSum >= randomNumber) 
     { 
      int y = i/imageWidth; 
      int x = i % imageWidth; 
      bitmap.SetPixel(x, y, Color.Red); 
      break; 
     } 
    } 
} 
+0

+1,但是你應該處理明顯的除零以得到完全黑色的圖像 – Niki

+0

是真的。雖然如果在這種情況下真正的意圖是仍然有一些像素選擇,那麼最好的辦法是實際增加一個小的偏移量到灰度矩陣,以確保沒有零元素。這樣每個像素都有被挑選的機會。這將是對代碼的小調整。 – troutinator

+0

非常感謝你,我在C#中構建了你的代碼,它工作正常,但有一點問題仍然存在。你能看看我更新的答案嗎? – Marc

1

您正在尋找加權隨機選擇。

回答這個問題應該讓你開始在低層次的編程: Weighted random numbers

這是它的外觀在Mathematica中,使用內置的功能RandomChoice

{w, h} = [email protected]; 
brightness = [email protected][img, "Grayscale"]; 

(* number of pixels to change *) 
npix = 150; 
(* new value for changed pixels *) 
newrgb = {1, 1, 1}; 

Image[ ReplacePart[ 
    [email protected], 
    RandomChoice[ 
     [email protected] -> Tuples[{Range[1, h], Range[1, w]}], 
     npix] -> newrgb]] 

enter image description here

+0

非常感謝,我確定你的代碼可以工作,但troutinator的答案對於我來說更容易將其加入到我的代碼中。 Mathematica的意思是[this](http://en.wikipedia.org/wiki/Mathematica)嗎? – Marc

+0

是的,這是我在示例中使用的軟件。 –

1

我喜歡troutinator和Matthias Odisio的加權隨機數解,但我認爲對於大圖像這可能是CPU密集型的。特別是如果必須拾取幾個像素。我寧願採用Monte Carlo simulation的方法。下面是一些僞代碼:

Normalize(I)    //in [0,1] range, with 1=bright 
n=0 
While n < number_of_pixels_to_pick 
    x = random(image_size(1)) //random pixel position 
    y = random(image_size(2)) 
    p = random()    // in [0,1] range 
    If p < I(x,y) do 
    select pixel 
    n=n+1 
    Endif 
Endwhile 

編輯:在這樣的解決方案,如果圖像很暗,它可以循環比確定性方法更長。

+0

謝謝,你是對的,troutinator *的代碼* CPU密集在一個大的圖像,但這對我來說應該沒有問題。但是在你的例子中,Normalize(I)是什麼意思? – Marc

+0

通過歸一化,我的意思是將最亮的像素設置爲1,將最暗的像素設置爲0.公式爲Normalize(I)=(I-min(I))/(max(I)-min(I)) –