在屏幕上随机绘制具有不等概率分布的像素

我想在屏幕上随机绘制像素,因此概率不应均匀分布。

示例:假设屏幕有 1920 x 1080 像素。在绘制事件中,位于 100 x 100 矩形中位置 (500,500) 的像素被绘制的概率应该是矩形外像素的 10 倍。

为了实现这一点,我首先创建了一个包含概率的数组。矩形内的位置的值为 10,所有其他位置的值为 1。

 for i := 1 to 1920 do
 begin
   for j := 1 to 1080 do
   begin
     FProbability[i,j]:=1;
     if InRange(i,500,600) and InRange(j,600) then
     begin
       FProbability[i,j]:=10;
     end;
   end;
 end;

然后我列出所有像素:

 FPixelList:=TList<TPoint>.Create;
 for i := 1 to 1920 do
 begin
   for j := 1 to 1080 do
   begin
     for k := 1 to FProbabilty[i,j] do
     begin
       FPixelList.Add(TPoint.Create(i,j))
     end;
   end;
 end;

对于矩形内的每个像素,像素列表现在有 10 个条目,对于所有其他像素位置有 1 个条目。

在绘制事件中,我得到要绘制的像素位置

FPixelList[RandomRange(0,FPixelList.Count-1)]

这很好用。

但是我想知道是否有其他解决方案可以解决此问题。如果屏幕尺寸变大,我的解决方案会使用大量内存,而我只能使用整数值作为概率。

tjb1216 回答:在屏幕上随机绘制具有不等概率分布的像素

正如 David Heffernan 在评论中指出的那样,没有必要为此使用额外的存储空间。

相反,我们可以将随机选择的范围扩展到图像大小之外以包含 (regionOptions-1)*regionSize 个附加值,其中 regionOptions 表示选择像素的可能性增加,在您的示例中为 10,在大小为 regionSize 的区域中。如果随机选择的值小于图像大小,那么我们直接将其用作图像中的位置。如果大于,则进行计算以确定感兴趣区域中的相应位置。

恐怕我不熟悉 Delphi,所以这里有一些 Java 代码来说明。

int imWidth = 1920;
int imHeight = 1000;
int[][] image = new int[imWidth][imHeight];

int regionOptions = 10;
Rectangle region = new Rectangle(500,500,100,100);

int imSize = imWidth * imHeight;

int randomRange = imSize + (regionOptions-1)*region.width*region.height;
        
int max = 0;
Random rand = new Random();
for(int i=0; i<region.width*region.height*1000; i++)
{
    int randPos = rand.nextInt(randomRange);
    
    int x,y;
    if(randPos < imSize)
    {
        x = randPos % imWidth;
        y = randPos / imWidth;
    }
    else
    {
        randPos = (randPos - imSize) / (regionOptions - 1);
        x = region.x + randPos % region.width;
        y = region.x + randPos / region.height;             
    }

    image[x][y] += 1;
    max = Math.max(max,image[x][y]);
}

为了演示目的,我使用以下代码创建了一个规范化的图像:

BufferedImage im = new BufferedImage(imWidth,imHeight,BufferedImage.TYPE_BYTE_GRAY);
for(int i=0; i<imWidth; i++)
{
    for(int j=0; j<imHeight; j++)
    {
        int level = (int)(255.0*image[i][j]/max);
        im.setRGB(i,j,(level << 16) | (level << 8) | level);
    }
}       
try
{
    ImageIO.write(im,"png",new File("probIm.png"));
}
catch(Exception e)
{
    e.printStackTrace();
}

这是使用 regionOptions = 2 从图像中剪下的区域。值为 10 时,归一化像素在感兴趣区域中过于聚集,无法显示任何背景。

enter image description here

,

为什么不使用不同的方法,首先在整个区域中绘制一定数量的随机位置像素,计算其中有多少是在聚焦区域中绘制的,有多少是在正常区域中绘制的。

那么你可以简单地将正常区域的像素数乘以 10 并减去焦点中已经绘制的像素数,得到焦点中仍然需要绘制的像素数,以满足所需的口粮。获得此数字后,您只需在聚焦区域内额外渲染所需数量的随机定位像素。

执行此操作的代码如下所示:

procedure TForm2.Button1Click(Sender: TObject);
var X,Y,N: Integer;
    Rect: Trect;
    Pt: Tpoint;
    NormalAreaCount,FocusedAreaCount: Integer;
begin
  //Set the rectagle boundaries where pixels needs to be more focused
  Rect.Left := 500;
  Rect.Top := 500;
  Rect.Width := 100;
  Rect.Height := 100;

  //Initialize pixels count variables to 0. Othervise they might end up bein unitialized.
  NormalAreaCount := 0;
  FocusedAreaCount := 0;

  //Use first loop do draw certain number of random pixels across the whole area
  for N := 0 to 200 do
  begin
    X := Random(PaintBox1.Width);
    Y := Random(PaintBox1.Height);
    PaintBox1.Canvas.Pixels[X,Y] := clBlack;
    Pt.X := X;
    Pt.Y := Y;
    if PtInRect(Rect,Pt) then
    begin
      //if the drawn pixel was in are of focus rectangle increase FocusedAreaCount
      Inc(FocusedAreaCount);
    end
    //else increase NormalAreaCount
    else Inc(NormalAreaCount);
  end;

  //In scond loop draw more random pixels only in focused rectangle area
  //You get the number of pixels taht needs to be drawn by multiplying the number of pixels
  //taht were drawn outsite focused area by 10 and then substract the number of pixels that
  //were already drawn within the focused area
  for N := 0 to (NormalAreaCount*10)-FocusedAreaCount-1 do
  begin
    X := RandomRange(Rect.Left,Rect.Right);
    Y := RandomRange(Rect.Top,Rect.Bottom);
    PaintBox1.Canvas.Pixels[X,Y] := clBlack;
    //Here I increase the FocusedArea count so I can verify the corect number of pixels drawn
    Inc(FocusedAreaCount);
  end;

  //Simply display the number of pixels drawn in focused and normal area for visual verificatiuon
  Form2.Caption := IntToStr(NormalAreaCount)+':'+IntToStr(FocusedAreaCount);
end;

当然,这种方法并不能保证总像素数是固定的,因为在正常区域中绘制的初始像素数有点随机。此外,此代码不保证聚焦区域中的像素不会在第二个循环中被绘制。

本文链接:https://www.f2er.com/1658.html

大家都在问