Получите процент использования каждого цвета в изображении

У меня есть этот работает, но он очень чертовски медленный на изображениях в формате JPEG и также нуждается в некоторых изменениях.

Мне нужно знать отдельные цвета на изображении (с допуском +/- 1 для RGB) и% изображения, который является этим цветом.

так что если бы изображение было черно-белым, оно бы говорило примерно так: белый: 74% черный: 26%

Приведенный ниже код работает, как я сказал, но мне нужно также добавить систему допусков, и я понятия не имею, как мне это сделать.

private Dictionary<string, string> getPixelData(Bitmap image)
{
    Dictionary<string, string> pixelData = new Dictionary<string, string>();
    //int col, row;
    //int r, g, b;
    Color pixel;

    double offset = 0.000001;
    int hmm = (image.Height * image.Width);
    double current = 0;
    offset = 100 / double.Parse(hmm.ToString());// 0.01;// 100 / (image.Height * image.Width) * 10000;

    try
    {
        for (int i = 0; i < image.Height; i++)
        {
            for (int j = 0; j < image.Width; j++)
            {
                current = current + offset;
                pixel = image.GetPixel(i, j);                        
                pixelData.Add(i + "," + j, (pixel.R.ToString() + " " + pixel.G.ToString() + " " + pixel.B.ToString()));
                pBarprocess.Value = int.Parse(Math.Floor(current).ToString());
                pBarprocess.Update();
                Application.DoEvents();
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Unable to parse image " + ex);
    }

    return pixelData;
}

И другая функция

private void btnProcess_Click(object sender, EventArgs e)
{
    pBarprocess.Value = 0;
    pBarprocess.Enabled = false;
    Bitmap foo = Bitmap.FromFile(@txtFileName.Text) as Bitmap;
    Dictionary<string, string> pixelData = new Dictionary<string, string>();

    lblProcess.Text = "Processing pixel map";
    pixelData = getPixelData(foo);

    lblProcess.Text = "Calculating Density";
    lblProcess.Update();

    var distinctList = pixelData.Values.Distinct().ToList();

    Console.WriteLine("DL = " + distinctList.Count);
    double offset = 100 / double.Parse(distinctList.Count.ToString());
    double current = 0;

    foreach (var value in distinctList)
    {
        IEnumerable<string> query = pixelData.Values.Where(fruit => fruit == value);
        double perc = (double.Parse(query.Count().ToString()) / double.Parse(pixelData.Count.ToString())) * 100;
        Console.WriteLine(value + " = " + query.Count() + "(" + perc + "%)");
        txtAnalysis.Text = "Colour " + value + " : " + query.Count() + " (" + perc.ToString() + "%)\r\n" + txtAnalysis.Text;
        txtAnalysis.Update();
        pBarprocess.Value = int.Parse(Math.Floor(current).ToString());
        pBarprocess.Update();
        Application.DoEvents();
    }

    lblProcess.Text = "Finished.";
    pBarprocess.Value = 0;
    pBarprocess.Enabled = false;
}

3 ответа

Решение

GetPixel не очень быстрый способ получить доступ к данным изображения. Используйте метод LockBits.

РЕДАКТИРОВАТЬ:

Ну, вы делаете много вещей со строками. Создание словаря pixelData таким способом довольно бесполезно, почему бы вам сразу не обработать отдельные цвета? Цвет является неизменной структурой, так что это хороший ключ для нашего словаря.

Dictionary<Color, int> frequency = new Dictionary<Color, int>();
for (int i = 0; i < image.Height; i++) {
  for (int j = 0; j < image.Width; j++) {
    pixel = image.GetPixel(i, j);
    if (frequency.ContainsKey(pixel)) frequency[pixel]++;
    else frequency.Add(pixel, 1);
  }
}

// and finally
int totalPixels = image.Width * image.Height;
foreach (var kvp in frequency) {
  Console.WriteLine("Color (R={0},G={1},B={2}): {3}", kvp.Key.R, kvp.Key.G, kvp.Key.B, kvp.Value / (double)totalPixels);
}

И это должно быть сделано, за исключением случаев, когда вы хотите сделать это еще быстрее и использовать LockBits вместо GetPixel.

Некоторые другие наблюдения:

int hmm = (image.Height * image.Width);
double offset = 100 / double.Parse(hmm.ToString());

Вы используете очень странный и медленный способ приведения из int в double. Вы можете просто написать double offset = 100 / (double)hmm; и это то же самое (вы также можете написать 100.0, а не 100, и компилятор создаст для вас double, так что вам не нужно приводить hmm).

Это заставило меня смеяться

IEnumerable<string> query = pixelData.Values.Where(fruit => fruit == value);

Почему фрукты!? Похоже, вы скопировали это откуда-то.

Кажется, что это является частью большей цели обработки изображений. Платформа Aforge - лучший выбор для анализа и обработки изображений в.NET, и она очень быстрая. Скорее всего, он уже содержит код, который вам нужен.

Вы упомянули систему толерантности - для меня это звучит так, как будто вам нужно квантование - округление цветов.

После того как у вас есть квантованное растровое изображение, вы можете создать и создать массив с длиной, соответствующей размеру палитры, LockBits растрового изображения и использовать индекс цвета для каждого пикселя в качестве индекса массива для каждого пикселя для накопления статистики использования.

Не могли бы вы поделиться более подробной информацией о ваших целях для этого кода? Что именно он должен делать?

Мой метод расчета цветового процента изображения следующий, также таким образом мы можем

рассчитать любой процент пикселей для любого цвета.

1. Использование программного обеспечения с именем "ImageJ" в этом месте, это бесплатно.

http://rsb.info.nih.gov/ij/download.html

2. Откройте изображение с помощью этого инструмента.

  1. Зайдите в меню "Анализ" и выберите "Гистограмма", откроется окно гистограммы.

4.В окне гистограммы, в левом нижнем углу нажмите кнопку "список", откроется окно списка

5. В окне списка выберите "сохранить как", это позволит сохранить количество пикселей на цвета в диапазоне 0-256.

6. Для измерения площади рассчитайте размер в пикселях по разрешению и умножьте на количество

пиксели. Используйте Excel любой другой числовой анализ, особенно сводные таблицы.

Вот программное обеспечение ImageJ, файл Excel, который я использовал, и скриншот.

https://www.mediafire.com/?htwk83rwgio4zds

Другие вопросы по тегам