根据基础图像的亮度将像素设置在随机位置 [英] Set pixel on randomized position depending on brightness in the underlying image

查看:71
本文介绍了根据基础图像的亮度将像素设置在随机位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望这对某些人来说是一个有趣的问题。

I hope this is an interesting question for some people.

我想在图像的随机位置上创建一些像素,但是随机化应取决于亮度,因此创建像素的可能性应该在图像的明亮部分较高,而在黑暗部分较低(但仍然可以)。

I want to create some pixels on randomized positions on an image, but the randomizing should be depended on the brightness, so the possibility to create a pixel should be high on a bright part of the image and low on a dark part (but still possible).

让我们拍摄此图像例如:

Lets take this image for example:

我想创建一个函数SetRandomizedPixel,该函数将获取位图并在随机位置上设置像素。在位置1上创建像素的可能性应该较高,在位置2上处于中等位置,位置3上应该处于较低位置。

I want to create a function SetRandomizedPixel which will get the bitmap and sets a pixel on a randomized position. The possibility that the pixel will be created on position 1 should be high, on position 2 medium and on position 3 low.

我正在使用C#和Bitmap / Graphic,但这无关紧要

I'm working with C# and Bitmap/Graphic, but that should not matter.

我唯一需要的是关于如何开始的建议,因为我不知道将其存档的好方法。

The only thing I need is a suggestion how to start because I can't figure out a good way to archive this.

也许可以读取所有图像像素的亮度和位置,并按亮度对列表进行排序-但是我该如何进行随机化处理呢?

Maybe read the brightness and positions of all image pixels and sort the list by brightness - but how can I do a randomize which prefer the brighter areas then?

更新:研究答案

以下代码产生的图像如下:

The following code results in images like this:

但是如果我们仔细观察,左侧会有很多像素:

But if we look closer there are a lot of pixels on the left side:

这就是代码(C#/ MVC3):

That's the code (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();
}


推荐答案

您可以采用灰度图片的图片,然后对像素的总和求和。然后,如果将每个像素除以该总数,则将得到一个权重。然后,您选择一个介于0到1之间的数字,并从第一个加权像素开始,并不断增加宽度,直到到达第一个像素,其总和大于您的随机数。然后根据需要为原始图像上的像素着色。

You could take a grey scale image of the picture and then sum up the total value of the pixels. Then if you divide each pixel by this total you get a weighting. Then you pick a number between 0 and 1 and start at the first weighted pixel and keep adding up the wieghts until you get to the first pixel who makes the sum greater than your random number. Then color that pixel on the original image however you want.

编辑:伪代码

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)

编辑:理论的随机像素strong>

Theory

其背后的理论是,我们希望根据每个像素的亮度将图像转换为概率分布。这样,较暗的像素更有可能选择较亮的像素。通过将每个像素减少到单个数字而不是RGB三倍,转换为灰度有助于我们生成PDF或weightedMatrix。我们采用灰度矩阵的总和来获得创建加权矩阵所需的总值。加权矩阵用灰度矩阵初始化,但是每个元素除以总权重。这意味着加权矩阵的总和为1,这是它表示PDF的要求。现在我们可以选择一个介于0到1之间的随机概率。使用这个概率,我们可以沿着加权矩阵求和,直到像素的和大于我们的概率,从而选择一个像素。发生像素是我们随机选择的像素。这是从列表中随机选择一个与每个项目相关联的概率的标准方法。

The theory behind this is that we want to transform the image to a probability distribution based on the brightness of each pixel. This way brighter pixels are more likely to be picked than dimmer ones. The conversion to grayscale aids us in generating the PDF or weightedMatrix by reducing each pixel to a single number instead of an RGB triple. We take the sume of the grayscale matrix to get the total value which is needed to create the weighted matrix. The weighted matrix is intialized with the grayscale matrix, but then each element is divided by the total weight. This means that the sum of the weighted matrix is 1, which is a requirement for it to represent a PDF. Now we can pick a random probability, which is between 0 and 1. Using this we pick a pixel by summing along the weighted matrix until the sum is just greater than our probability. The pixel at which that happens is our randomly picked pixel. This is a standard way of randomly picking an item from a list with probabilities associated with each item.

编辑:固定左侧线

OP带来的问题是边界条件导致在Y,X扫描线中循环遍历数组。如果将代码修改为使用线性数组,然后将索引转换为X,Y对,则会删除左侧的实线。如果将main方法的中间部分更改为以下内容,则它将按预期工作:

The problem the OP brought up has to with boundry conditions from looping over the array in Y,X scan lines. If the code is reworked to use a linear array and then transform the index into an X,Y pair the solid line on the left is removed. If the middle chunk of the main method is changed to the following it works as intended:

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;
        }
    }
}

这篇关于根据基础图像的亮度将像素设置在随机位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆