Зашумление изображения v2.0 - C#

Узнай цену своей работы

Формулировка задачи:

Всем доброго времени суток! Нашла интересную и полезную тему на просторах форума (Зашумление изображения). К сожалению, она старовата (да и не моя), а вопросы у меня возникли. Собственно для этого и была данная Разъясните мне пожалуйста вот эту строчку:
byte r = (byte)(rnd.Next(0, 2) == 1 ? color.R : 255);
Как именно генерируется/выбирается случайный пиксель? Почему в результате получаем картинку с разноцветным шумом (скрин прилагается),хотя автор говорил
Если нужен ровный белый шум
(или я что-то не то понимаю под белым шумом?) И как в конечном итоге "зашумить" изображение белым и серым цветом?

Решение задачи: «Зашумление изображения v2.0»

textual
Листинг программы
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Net;
using System.Windows.Forms;
 
namespace WindowsFormsApplication330
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //загружаем изображение
            var img = new Bitmap(new WebClient { Proxy = null }.OpenRead("http://vignette2.wikia.nocookie.net/callofduty/images/1/11/Personal_Sasi_don_image.jpg/revision/latest?cb=20140511142238"));
 
            //добавляем шум
            var img1 = AddSpeckleNoise(img, 0.04f);
            //выводим
            new PictureBox { Image = img, Parent = this, Size = new Size(250, 200), SizeMode = PictureBoxSizeMode.StretchImage };
            new PictureBox { Image = img1, Parent = this, Size = new Size(250, 200), SizeMode = PictureBoxSizeMode.StretchImage, Left = 300 };
        }
 
        Bitmap AddSpeckleNoise(Bitmap bmp, float v = 0.04f)
        {
            var res = (Bitmap)bmp.Clone();
            var rnd = new Random();
            var stdDev = Math.Sqrt(v);//девиация - корень из дисперсии
 
            using (var wr = new ImageWrapper(res))
                foreach (var p in wr)
                {
                    var c = wr[p];
                    var noise = (rnd.NextDouble() - 0.5f) * 2 * stdDev;//равномерное распр со средним = 0, дисперсия = v
                    wr.SetPixel(p, c.R + noise * c.R, c.G + noise * c.G, c.B + noise * c.B);//Id=Is+n*Is
                }
 
            return res;
        }
    }
 
    /// <summary>
    /// Обертка над Bitmap для быстрого чтения и изменения пикселов.
    /// Также, класс контролирует выход за пределы изображения: при чтении за границей изображения - возвращает DefaultColor, при записи за границей изображения - игнорирует присвоение.
    /// </summary>
    public class ImageWrapper : IDisposable, IEnumerable<Point>
    {
        /// <summary>
        /// Ширина изображения
        /// </summary>
        public int Width { get; private set; }
        /// <summary>
        /// Высота изображения
        /// </summary>
        public int Height { get; private set; }
        /// <summary>
        /// Цвет по-умолачнию (используется при выходе координат за пределы изображения)
        /// </summary>
        public Color DefaultColor { get; set; }
 
        private byte[] data;//буфер исходного изображения
        private byte[] outData;//выходной буфер
        private int stride;
        private BitmapData bmpData;
        private Bitmap bmp;
 
        /// <summary>
        /// Создание обертки поверх bitmap.
        /// </summary>
        /// <param name="copySourceToOutput">Копирует исходное изображение в выходной буфер</param>
        public ImageWrapper(Bitmap bmp, bool copySourceToOutput = false)
        {
            Width = bmp.Width;
            Height = bmp.Height;
            this.bmp = bmp;
 
            bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            stride = bmpData.Stride;
 
            data = new byte[stride * Height];
            System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, data.Length);
 
            outData = copySourceToOutput ? (byte[])data.Clone() : new byte[stride * Height];
        }
 
        /// <summary>
        /// Возвращает пиксел из исходнго изображения.
        /// Либо заносит пиксел в выходной буфер.
        /// </summary>
        public Color this[int x, int y]
        {
            get
            {
                var i = GetIndex(x, y);
                return i < 0 ? DefaultColor : Color.FromArgb(data[i + 3], data[i + 2], data[i + 1], data[i]);
            }
 
            set
            {
                var i = GetIndex(x, y);
                if (i >= 0)
                {
                    outData[i] = value.B;
                    outData[i + 1] = value.G;
                    outData[i + 2] = value.R;
                    outData[i + 3] = value.A;
                };
            }
        }
 
        /// <summary>
        /// Возвращает пиксел из исходнго изображения.
        /// Либо заносит пиксел в выходной буфер.
        /// </summary>
        public Color this[Point p]
        {
            get { return this[p.X, p.Y]; }
            set { this[p.X, p.Y] = value; }
        }
 
        /// <summary>
        /// Заносит в выходной буфер значение цвета, заданные в double.
        /// Допускает выход double за пределы 0-255.
        /// </summary>
        public void SetPixel(Point p, double r, double g, double b)
        {
            if (r < 0) r = 0;
            if (r >= 256) r = 255;
            if (g < 0) g = 0;
            if (g >= 256) g = 255;
            if (b < 0) b = 0;
            if (b >= 256) b = 255;
 
            this[p.X, p.Y] = Color.FromArgb((int)r, (int)g, (int)b);
        }
 
        int GetIndex(int x, int y)
        {
            return (x < 0 || x >= Width || y < 0 || y >= Height) ? -1 : x * 4 + y * stride;
        }
 
        /// <summary>
        /// Заносит в bitmap выходной буфер и снимает лок.
        /// Этот метод обязателен к исполнению (либо явно, лмбо через using)
        /// </summary>
        public void Dispose()
        {
            System.Runtime.InteropServices.Marshal.Copy(outData, 0, bmpData.Scan0, outData.Length);
            bmp.UnlockBits(bmpData);
        }
 
        /// <summary>
        /// Перечисление всех точек изображения
        /// </summary>
        public IEnumerator<Point> GetEnumerator()
        {
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                    yield return new Point(x, y);
        }
 
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
 
        /// <summary>
        /// Меняет местами входной и выходной буферы
        /// </summary>
        public void SwapBuffers()
        {
            var temp = data;
            data = outData;
            outData = temp;
        }
    }
}

Оцени полезность:

15   голосов , оценка 3.6 из 5