#c# #image-processing #colors #bitmap #pixel
#c# #обработка изображений #Цвет #растровое изображение #пиксель
Вопрос:
У меня это работает, но оно чертовски медленно работает с изображениями в формате 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() "%)rn" 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;
}
Комментарии:
1. Проблема, которую я вижу в вашем алгоритме, заключается в том, что вы обновляете пользовательский интерфейс и загружаете очередь сообщений окна на каждый пиксель, обновляя индикатор выполнения и вызывая DoEvents. Попробуйте делать это каждые n пикселей подряд, например, каждые 1000 пикселей.
2. Каждый шаг (т.Е. Во внешнем цикле) — лучшее место для касания элементов пользовательского интерфейса. Кроме того, вы добавляете новый элемент в словарь для каждого отдельного пикселя — это снизит вашу производительность. Вы должны создать массив с длиной, соответствующей количеству цветов, которые вы хотите обнаружить, и вместо этого увеличить связанные значения. Нет необходимости в словаре, когда ваши ключи являются последовательными целыми числами.
Ответ №1:
GetPixel на самом деле не является быстрым способом доступа к данным изображения. Используйте метод LockBits.
Ну, вы много чего делаете со строками. Построение словаря pixelData таким образом довольно бесполезно, почему бы вам сразу не обработать отдельные цвета? Color — это неизменяемая структура, так что это уже хороший ключ для нашего словаря.
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);
}
И это должно сделать это, за исключением случаев, когда вы хотите сделать это еще быстрее и использовать блокировочные биты вместо 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);
Почему фрукты !? Похоже, вы скопировали это откуда-то.
Комментарии:
2. lol да, я никогда раньше не использовал LINQ, поэтому просто перепутал то, что мне нужно, чтобы заставить его работать 🙂 сейчас попробую вашу реализацию и отмечу, работает ли она 🙂
3. По сути, вам нужно решить для каждого цвета, с каким другим цветом вы хотели бы его объединить, или если вы хотите объединить оба с новым промежуточным цветом … прямого решения нет. Самым простым способом было бы следовать предложению ComputerLinguist применить сглаживание / квантование к изображениям. Вы можете использовать . NET или библиотека обработки изображений, чтобы уменьшить изображение, например, до 256 цветов или, если это оттенки серого, до 16 оттенков серого. Это статья из уже упомянутого AForge.NET .
4. 1, как в вашем разделе «некоторые другие наблюдения». Ответы, идущие дальше, чем исходные вопросы, являются лучшими для изучения.
Ответ №2:
Похоже, это часть более масштабной цели обработки изображений. Платформа Aforge является идеальным выбором для анализа и обработки изображений в .NET, и она чрезвычайно быстра. Вероятно, в нем уже есть нужный вам код.
Вы упомянули систему допусков — для меня это звучит так, как будто вам нужно квантование — округление цвета.
Получив квантованное растровое изображение, вы можете создать и создать массив с длиной, соответствующей размеру палитры, заблокировать растровое изображение и использовать индекс цвета для каждого пикселя в качестве индекса массива для каждого пикселя для накопления статистики использования.
Не могли бы вы поделиться дополнительной информацией о ваших целях для этого кода? Что именно он должен делать?
Комментарии:
1. Да, в основном требуется проверить плотность цвета в изображении, но вместо того, чтобы возвращаться с 12 оттенками черного, он должен вернуться с одним, так что, например, RGB от 0, 0, 0 до 5, 5, 5 вернется в виде одного цвета и от 200, 200, 200 до 255, 255, 255 вернутся как белые
2. Яркость зависит от цвета — например, лучшим диапазоном для черного будет от 0,0,0 до 13,5,50, если вы ищете воспринимаемые диапазоны яркости. Плотность цвета обычно представлена гистограммой — возможно, вы могли бы предоставить больше информации о том, для чего пользователи будут использовать это?
3. чтобы определить плотность стружки в материале, стружка может быть любого цвета, но необходимо знать общий процент покрытия стружки по сравнению с материалом.
4. Тогда определенно квантовать / постеризировать. Таким образом, вы можете выбрать, до какого количества цветов вы хотите округлить. И вы должны быть в состоянии получить очень хорошую производительность из алгоритма, упомянутого в моем ответе.
Ответ №3:
Мой метод вычисления процентного содержания цвета изображения заключается в следующем, также таким образом мы можем
вычислите любой процент пикселей для любого цвета.
1. Используйте программное обеспечение с именем «ImageJ» в этом месте, оно бесплатное.
http://rsb.info.nih.gov/ij/download.html
2. Откройте изображение с помощью этого инструмента
- Перейдите в меню Анализ и выберите Гистограмма, откроется окно гистограммы
4.In окно гистограммы, в левом нижнем углу нажмите кнопку «список», откроется окно списка
5.In в окне списка выберите «сохранить как», это позволит сохранить количество пикселей для каждого цвета в диапазоне 0-256
6. Для измерения площади вычислите размер в пикселях по разрешению и умножьте на количество
пикселей. Используйте Excel для любого другого численного анализа, особенно сводных таблиц.
Вот программное обеспечение ImageJ, файл Excel, который я использовал, и скриншот.
Комментарии:
1. пожалуйста, разместите скриншот здесь. ссылка на некоторые неизвестные файлы .rar — не лучший способ ответить…
2. Хороший пост, но вы не смогли прочитать исходный вопрос, это зависит от стороннего программного обеспечения, и процедура требовалась для C#