Setpixel не поддерживается для изображений имеющих форматы с индексированными пикселями

Обновлено: 08.07.2024

Репутация: нет
Всего: 1

Столкнулся с проблемой : нужно присвоить цвета сразу большому количеству пикселей. Разумеется, пробегать их в цикле и каждый раз вызывать SetPixel неправильно. Поискал, нашел упоминание о процедуре SetPixels. По-видимому, она присваивает сразу целый массив пикселей. Однако я не смог найти подробных сведений об ее использовании. Дело в том, что она принимает ряд непонятных мне параметров. Подскажите, пожалуйста, как правильно использовать процедуру SetPixels. Или как решить подобную задачу другим образом?
И, если можно, какой нибудь простенький пример. Например, для заполнения квадрата пикселями случайного цвета.

Pereant qui ante nos nostra dixerunt! (лат.) Да погибнут те, кто раньше нас высказал наши мысли!

Репутация: 31
Всего: 159


что за SetPixel? что за SetPixels? Какого класса эти методы? почему процедура, а не метод? причем тут Java?

нет времени думать - нужно писать КОД!

Репутация: нет
Всего: 1

Ок. Объясню. Это методы класса java.awt.Graphics . Java тут понятно при чем.
Пусть постановка задачи будет следующая - заполнение всех точек квадрата точками случайного цвета. В принципе сделал, но для больших размеров квадрата работает слишком долго. Потому что нехорошо каждому пикселю присваивать цвет по отдельности. Обычно для этого забивается массив цветов точек а потом одной операцией присваиваются цвета сразу всем точкам.
Вот, соответственно, и вопрос.
Пытался найти сам - только обрывки.
Pereant qui ante nos nostra dixerunt! (лат.) Да погибнут те, кто раньше нас высказал наши мысли!

Репутация: 31
Всего: 159

нет времени думать - нужно писать КОД!

Репутация: нет
Всего: 1

Да, я обманул. Об этом я прочитал в демосах JDK. И там использовалось super.setPixels .
И, возможно, я многого не понимаю. Но постановка задачи остается всё той же.
И, кстати, PowerOn, по той ссылке, что ты мне дал я нашел что-то вроде DrawBytes. Это похоже на то, что мне нужно. Так ли это? По-видимому, не так.

Pereant qui ante nos nostra dixerunt! (лат.) Да погибнут те, кто раньше нас высказал наши мысли!

Репутация: 31
Всего: 159

Для рисования отдельного пикселя в точке x, y, можно использовать к примеру метод рисования линии: g.drawLine(x, y, x, y);

нет времени думать - нужно писать КОД!

Репутация: нет
Всего: 1

Вот. Моя тема перенесена, но постановка задачи остается той же. Необходимо изменять цвета пикселей не по одному, а все скопом. Помогите, если такое вообще возможно.
Pereant qui ante nos nostra dixerunt! (лат.) Да погибнут те, кто раньше нас высказал наши мысли!

Репутация: 3
Всего: 5

Код

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;

import javax.swing.JComponent;
import javax.swing.JFrame;

Наша жизнь растрачивается на мелочи… Упрощайте, упрощайте. [Генри Торо]

Репутация: нет
Всего: 1

Спасибо большое Goliath. В твоем коде не хватало нескольких импортов, как то

Код

import java.awt.image.BufferedImage;
import java.awt.TexturePaint;
import java.awt.Rectangle;

но с этим я уже разобрался.

  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, jk1.

[ Время генерации скрипта: 0.1157 ] [ Использовано запросов: 21 ] [ GZIP включён ]

Как только он попадает внутрь цикла, он делает исключение в строке:

Если я изменю экземпляр bmp2 на:

Затем он будет работать, но я хочу, чтобы SetPixel пиксели поверх исходного радара001486.GIF, а не на новом пустом Bitmap.

Проблема в том, что вы используете GIF, поскольку он имеет индексированные пиксели. Попробуйте преобразовать его в png, если сможете; или если вы не можете, превратите его в неиндексированное изображение, используя:

Примечание. Если у вас есть возможность сделать это (например, незагруженные изображения или у вас есть доступ к серверу), определите их преобразование в PNG.

Изображение, которое вы пытаетесь изменить, - это индексированный GIF. Это означает, что изображение не содержит серию пикселей с соответствующими значениями цвета (как это делает ваш новый Bitmap ); скорее, он содержит цветовую палитру в сочетании с серией пикселей со значениями индекса в палитре. Формат пикселя вашего изображения, загруженного с диска, вероятно, похож на Format8bppIndexed .

Вы не можете использовать SetPixel для этого типа изображения, потому что SetPixel хочет напрямую установить значения R, G и B для пикселя. Это не то, как работает индексированное изображение.

Чтобы изменить этот вид изображения, у вас есть несколько вариантов:

Лучше всего использовать WPF, который имеет GifBitmapEncoder и GifBitmapDecoder. Это позволяет вам декодировать данные GIF во что-то, что WPF может нарисовать, а затем преобразовать обратно. Поскольку это использует DirectX, а не GDI +, у него нет ограничений таких вещей, как SetPixel . Я действительно хотел бы предложить вам пойти по этому маршруту, если это возможно, но если нет:

Используйте GDI + для Преобразовать изображение в неиндексированный тип изображения, измените его и convert он вернулся. Это, как правило, ужасная идея: GDI + и индексированные форматы не ладят друг с другом, и это включает кодирование растрового изображения в качестве индексированного GIF. Качество изображения, вероятно, будет ужасным.

Отредактируйте данные байта напрямую. Для этого вам нужно извлечь данные GIF в массив и установить пиксели в правильные индексированные значения. Фокус здесь заключается в определении правильного значения индекса; или, если в палитре окажется пустой, вы можете просто добавить еще один. Вам нужно углубиться в формат GIF, чтобы понять это, хотя он, вероятно, будет наиболее эффективным с точки зрения как пространства, так и скорости без снижения качества изображения. Когда вы знаете, какое значение индекса для записи, вы делаете что-то вроде этого:

Выделяю прямоугольную область на цветной картинке 1.Требуется вывести одновременно выделенный черно-белый(бинаризированный) график с выделенными пиками с помощью красных кружков . Но после бинаризации изображение переводится в пиксельный формат,сразу вылетает ошибка SetPixel не поддерживается для изображений, имеющих форматы с индексированными точками. Выдаёт просто выделенный цветной кусок изображения с красными кружками. Как совместить два метода?

вот метод GraphExtractor где бинаризируется картинка,может я неправильно конвертирую из пиксельного формата в Bitmap?
вроде прописал правильно

__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь


Метод дихотомии для уравнения с индексированными переменными
Привет, ребята!:) В свое время использовала несложную программу в Маткаде для своих нужд. И вот.

Ввод даты вида хх.хх.хххх и её преобразоватие в другие форматы форматы. String
пользователь вводит дату рождения вида хх.хх.хххх, написать программу, которая выводит эту дату в.

Среднее время ожидания на рейде отдельно для судов, имеющих и не имеющих приоритета в обслуживании
Здравствуйте! Задача. В морском порту имеются 2 причала: старый и новый. У старого причала.


Аналоги для GetPixel/SetPixel
Есть такой код: var bmp = pictureBox1.Image as Bitmap; for (int i = 0;.

может я неправильно конвертирую из пиксельного формата в Bitmap?
вроде прописал правильно Вероятно, эти методы возвращют Bitmap c PixelFormat = Indexed. Надо как-то перевести в обычный или научиться задавать цвет иначе. Не знаю как.

У вас с английским лучше,я уверен что в той же самой библиотеке EmguCV есть функция,которая переводит из пиксельного формата в обычный Image.Поможете найти?

попробуй использовать свойство Bitmap вместо метода ToBitmap
Ну а вообще, насколько я понял, проблема в том, что цвета в конечном изображении задаются не напрямую, а через палитру (Palette).

Добавлено через 1 час 47 минут
Если не получается конвертировать пиксельный вид картинки,то можно обойти это всё,сделав метод не автоматизированным.Можно попытаться сохранить на компьютер выделенный бинаризированный фрагмент,загрузить его как картинку снова,только в другое окошко(новое),picturebox с параметрами Normal,затем получить пиксели,перекрасить с отрисовкой выделенных максимумов,отрисовать сетку,используя ваш код,сетка отрисуется как раз под масштаб,тока доработать придётся чутка.Рисунок получится у нас уже как отдельный объект. Сохранить хоть возможно так? в формат jpeg,png,bmp?


Цифровая обработка изображений — весьма интересная область, но она таит в себе множество подводных камней, на которые постоянно натыкаются новички. Мы активно привлекаем студентов к участию в грантах и проектах, но когда мы пытались давать студентам реальные задания, которые требуют реализации новых алгоритмов обработки изображений, мы были в ужасе от совершаемых ими детских ошибок.

Поэтому перед постановкой полноценных задач мы стали давать студентам ряд практических заданий по реализации стандартных алгоритмов обработки изображений: базовые операции над изображениями (поворот, размытие), свёртка, интерполяция с помощью простых фильтров (билинейная, бикубическая), направленная интерполяция, выделение границ с помощью алгоритма Канни, детектирование ключевых точек и т.д. Язык программирования мог быть любым, однако при выполнении заданий не допускается использование сторонних библиотек, за исключением чтения и записи изображений. Это связано с тем, что задания носят обучающий характер, самостоятельная реализация алгоритмов является хорошей практикой в программировании и позволяет понять, как работают методы изнутри.

Данная статья описывает наиболее частые ошибки, совершаемые студентами при выполнении практических заданий по обработке изображений. Изображения обычные, никакой экзотики типа 16-битной глубины цвета, панхроматичности и 3D-изображений нет.

Ошибка 1. Работа с пикселями, используя системные объекты Bitmap, HBITMAP и им подобные для хранения изображений

Решение: использовать данные классы только для чтения из файла, записи в файл и вывод на экран, в остальных случаях работать с классами, имеющими эффективный доступ к пикселям.

Замечание: в некоторых случаях в Windows удобно работать с DIB (device independent bitmap): есть и прямой доступ к пикселям, и возможность вывода на экран, минус — ограничение на тип пикселя.

Ошибка 2. Использование библиотек для работы с изображениями при отсутствии опыта обработки изображений

Использование библиотек чревато непониманием работы алгоритмов и дальнейшими трудностями при решении практических задач, требующих разработки собственных алгоритмов, которых нет в библиотеках. Я сталкивался с хорошо программирующими студентами, которые не могли реализовать даже элементарные операции типа свёртки: то не получалось подключить библиотеку, то работало не так, но на написание функции из 10 строчек ума уже не хватало.

Решение: не использовать сторонние библиотеки, а писать свои классы для работы с изображениями и самостоятельно реализовывать основные алгоритмы. Особенно полезно это для тех, кто не имеет достаточного опыта программирования. Лучше несколько раз сломать велосипед, чем завалить целый проект из-за глупых ошибок.

Ошибка 3. Потеря в точности при округлении

В результате применения различных алгоритмов обработки изображений возникают промежуточные результаты, имеющие вещественный тип. Пример: практически любой усредняющий фильтр, например, фильтр Гаусса. Приведение результатов к типу byte приводит к внесению дополнительной ошибки и менее точной работе алгоритмов.

Ниже приведён пример работы алгоритма детектировании контуров Канни, одним из составных частей которого является вычисление модуля градиента. Слева — модуль градиента после вычисления хранится в типе float, справа — округляется до byte.

Без округления
С округлением

Несложно заметить, что при округлении контуры становятся рваными.

Решение: если для алгоритма критична точность, то используйте тип float вместо byte для хранения значений пикселей, не занимайтесь преждевременной оптимизацией — сначала добейтесь нормальной работы алгоритма на float, а затем уже думайте, где можно использовать byte так, чтобы не снизилось качество.

Замечание: скорость работы современных процессоров с вещественными числами сопоставима с целыми. В некоторых случаях компилятор может применить автоматическую векторизацию, что приведёт к более быстрому коду с float. Также код с float может получиться более быстрым при большом количестве преобразований byte-float, округлений и отсечений. А вот использование double редко бывает оправдано, а мешанина из float и double так вообще является следствием непонимания типов и принципов работы с ними.

Использование целочисленных типов (byte, int16, uint16) особенно эффективно при использовании векторных операций, когда скорость доступа к памяти становится узким местом.

Ошибка 4. Выход значений пикселей за пределы диапазона [0, 255]

У вас нет проблем с точностью и вы всё ещё хотите для хранения значений пикселей использовать тип byte? Тогда возникает ещё одна проблема: многие операции, например бикубическая интерполяция или повышение резкости, приводят к появлению значений, выходящих за пределы указанного диапазона. Если не учитывать этот факт, то возникает эффект, называемый wrapping: значение 260 превращается в 4, а –3 — в 253. Появляются яркие точки и линии на тёмном фоне и тёмные — на светлом (слева — правильная реализация, справа — с ошибкой).

С использованием clamp
Без использования clamp

Решение: при выполнении промежуточных операций проверяйте на каждом шаге диапазон возможных значений, а при преобразовании в байтовый тип обязательна проверка на выход за границы диапазона, например, так:

Ошибка 5. Потеря значений в результате приведения к диапазону [0, 255]

Вы предпочитаете работать с типом byte и используете функцию clamp ? А вы уверены, что ничего не теряете, как в случае с округлением?

Видел на практике, как студенты при вычислении производной или при применении фильтра Собеля таким образом теряли отрицательные значения.

Решение: используйте типы достаточного размера для хранения промежуточных результатов, а функцию clamp только для сохранения в файл или вывода на экран. Для визуализации производной добавляйте 128 к значению пикселя, либо берите модуль.

Ошибка 6. Неправильный порядок обхода по пикселям изображения, приводящий к замедлению работы программы

Память в компьютере одномерна. Двумерные изображения хранятся в памяти в виде одномерных массивов. Обычно они записываются построчно: сначала идёт 0-я строка, затем 1-я и т.д.
Последовательный доступ к памяти осуществляется быстрее, чем произвольный. Это связано с работой кэша процессора, который помещает данные из памяти в кэш большими блоками, например, по 64 байта для современных процессоров. В этот блок попадают сразу несколько соседних по горизонтали пикселей. Значит, при обращении к последующим пикселям в той же строке скорость доступа будет выше, чем к последующим пикселям в столбце.

Решение: Обход по изображению нужно делать так, чтобы доступ к памяти был последовательный: во внешнем цикле производится обход по вертикали, а во внутреннем — по горизонтали:

Примечание: В разных языках способ представления многомерных массивов в памяти может быть различным. Имейте это в виду.

Ошибка 7. Путаница с шириной и высотой

Классическая проблема: тестирование либо отсутствует, либо осуществляется только на квадратных изображениях, в полевых условиях при работе с прямоугольными изображениями происходит выход за границу массива.

Решение: не забывайте про тестирование! Спор о TDD предлагаю не разводить: его использование — это личное дело каждого.

Ошибка 8. Отказ от абстракций

Боязнь плодить сущности — типичная ошибка новичков, она приводит к проблемам с читаемостью и восприятием кода. Здесь можно привести много примеров.

1. Обращение к пикселям через непосредственное вычисление индексов в массиве вместо использования методов getPixel(x, y) и setPixel(x, y) . Помимо удобства, в этих методах можно проверять и корректно обрабатывать выход за границы изображения. Например, не выдавать ошибку, а эктраполировать значения изображения.

Просто посмотрите на этот прекрасный код (в коде, кстати, есть ошибка, и не одна)

Это реализация бикубической интерполяции в исполнении студента.
Лишь немногие студенты догадались, что бикубическая интерполяция сепарабельна, и сумели обойтись четырьмя коэффициентами вместо шестнадцати.

2. Дублирование кода при работе с цветными изображениями, приводящее к ошибкам (см. пример выше). Вместо copy-paste кода и замены r на g и на b достаточно было бы использовать перегрузку операторов. В три раза меньше кода, в три раза понятнее.

3. Использование двумерных массивов вместо создания отдельного класса для изображения.
Проблема заключается в том, что индексация получается неестественной — (y, x) вместо (x, y) , а размерности массива не очевидны: непонятно, что из GetLength(0) и GetLength(1) есть ширина, а что — высота. Высок риск просто перепутать индексы.

4. Использование трёхмерных массивов для хранения цветных изображений вместо создания отдельного класса для изображения. В дополнение к предыдущему пункту, приходится помнить, какой из индексов соответствует какой цветовой компоненте. Также видел, как трёхмерные массивы используются для хранения векторов, как в виде (vx, vy) , так и в виде (v, angle) . Запутаться легко.

5. Использование массива вместо класса. Угадайте, что возвращает следующая функция?

Ответ: массив из 11 элементов, каждый из элементов имеет свой сакральный смысл, непонятный без длительного анализа кода. Не делайте так! Заведите класс и назовите каждое из полей по-человечески.

6. Переиспользование переменных с изменением семантики. Видите в коде gradx и grady и думаете, что это призводные по x и по y ? А вот и нет, это модуль и угол:

Решение: никаких магических констант и индексов быть не должно. Оформляйте изображения как отдельные классы, сами пиксели тоже должны быть типизированы, а доступ к пикселям должен осуществляться только через специальные методы.

Ошибка 9. Применение некоторых математических функций неправильно или не к месту

Здесь виной всему слабое понимание архитектуры процессора, набора инструкций и времени их выполнения. Простительно, приходит с опытом, но некоторые моменты я отмечу:

1. Возведение в квадрат в виде Math.Pow(x, 2) или pow(x, 2) вместо x * x .
Компиляторы не оптимизируют эти конструкции, вместо однотактового умножения они генерируют довольно сложный код, включающий в себя вычисление экспоненты и логарифма, что приводит к снижению скорости на порядок-два.

Вызов pow(x, y) разворачивается в exp(log(x) * y) . Это занимает около 300 тактов при использовании команд x87. В SSE же экспоненты и логарифма до сих пор нет, существует множество реализаций exp и log с различной производительностью, например, вот. В лучшем случае возведение в степень займёт 30-50 тактов. На умножение же уйдёт всего один такт.

2. Взятие целой части как (int)Math.Floor((float)(j) / k) , причём k — вещественное и не меняется внутри цикла.

Здесь достаточно было бы написать (int)(j / k) , а ещё лучше (int)(j * inv_k) , где float inv_k = 1.0f / k .

Дело в том, что floor возвращает вещественное число, которое затем нужно дополнительно преобразовывать в целое. Получается лишняя довольно дорогая операция. Ну а замена деления на умножение — просто оптимизация, операция деления до сих пор дорогая.

(int)floor(x) и (int)x зквивалентны только при неотрицательных x. Функция floor всегда округляет вниз, тогда как (int)x — в сторону нуля.

3. Вычисление обратного значения.

Зачем так делать, когда можно написать _sum = 1.0 / sum?

Решение: применяйте математические функции только там, где они нужны.

Ошибка 10. Незнание языка

И опять проблемы с математикой:

1. Путаница с типами. Использование long long для индексов пикселей вместо int , постоянные преобразования между float , double и int . Например, зачем писать (float)(1.0 / 16) , когда можно написать 1.0f / 16.0f ?

2. Вычисление полярного угла через возню с atan и проблемой с делением на ноль вместо использования atan2 , которая делает именно то, что надо.

3. Необычная экспонента и магические константы:

Здесь студент просто забыл про существование функции exp и константы pi . А вместо (float)1 можно просто написать 1.0f .

Решение: программируйте больше, только так вы наберётесь опыта.

Ошибка 11. Обфускация кода

Начинающие программисты любят показать своё мастерство, предпочитая писать короткий код, а не понятный.

1. Сложные циклы

Здесь правильно было бы сделать цикл от -1 до 1, а x1 и x2 вычислять уже внутри цикла, ну и порядок поменять:

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

2. Крутые функции

А нормальные люди просто напишут

А это вообще за гранью добра и зла:

Для тех, кто не понял: ldexp(x, -1) — это просто деление на 2.

Решение: просто помните, что рано или поздно вам отобьют пальцы молотком за такой код.

Ошибка 12. Порча значений обрабатываемых изображений

Вот кусок кода из подавления немаксимумов, являющегося частью алгоритма Канни:

Здесь некоторые значения зануляются grad[x, y] = 0 , а на последующих итерациях циклах к ним происходит обращение. Ошибка бы не произошла, если бы для вычисления промежуточного результата создавалось новое изображение, а не перезаписывалось текущее.

Решение: не стремитесь экономить память раньше времени, подумайте о функциональной парадигме.

Остальные ошибки

Остальные ошибки уже имеют непрограммистский характер. Это ошибки в реализации алгоритмов вследствие их непонимания, они индивидуальны. Например, неверный выбор размера ядра для фильтра Гаусса.

Фильтр Гаусса — один из основных фильтров в обработке изображений. Он лежит в основе огромного числа алгоритмов: детектирование контуров (edges) и хребтов (ridges), поиск ключевых точек, повышение резкости и т.д. Фильтр Гаусса имеет параметр «сигма», определяющий уровень размытия, его ядро описывается формулой:

Формула

а график имеет вид:

График

Данная функция нигде не обращается в ноль, а свёртка с ядром бесконечного размера не имеет смысла. Поэтому размер ядра выбирается таким, чтобы ошибка была ничтожно мала. Для практических задач достаточно взять ядро с радиусом (int)(3 * sigma) — ошибка будет меньше 1/1000 . Выбор слишком маленького ядра (красная функция на графике выше) приведёт к искажению фильтра Гаусса. Использование ядра фиксированного размера, например, 5х5 и приводит к некорректным результатам уже при sigma = 1.5 .

Итог: общие рекомендации для начинающих работать с изображениями

  1. Не используйте системные объекты Bitmap, HBITMAP и им подобные.
  2. Прежде, чем использовать библиотеки для работы с изображениями, начните с написания велосипедов, а уже затем бросайтесь в бой.
  3. Используйте тип float для хранения значений пикселей, если типа byte не хватает для хранения значений пикселей как по точности, так и по диапазону. А набравшись опыта, вы сможете использовать арифметику с фиксированной точкой и добиться максимальной эффективности.
  4. При преобразовании из float в byte помните об ошибках округления и выход за границы типа.
  5. Помните об отрицательных значениях.
  6. Совершайте обход по пикселям изображения в правильном порядке.
  7. Тщательно тестируйте код.
  8. Не бойтесь плодить сущности. Код должен быть понятным.
  9. Используйте математические операции с умом.
  10. Учите язык.
  11. Не пытайтесь показать мастерство.
  12. Читайте учебники по обработке изображений — там много всего полезного пишут.

Для облегчения написания программ я создал проекты, в которых уже реализовано чтение и запись изображений, созданы классы для хранения изображений с минимально возможным функционалом и приведён пример операции над изображениями:

Версий под Linux нет — студенты, использующие Linux, обычно не испытывают проблем с такими вещами.

Ну и на закуску — просто картинки.

Выделение контуров с помощью алгоритма Канни. Слева вверху — входное изображение, второе слева — правильный результат, остальное — ошибочные результаты.

Я работаю с изображениями на Java, я разработал более 100 + изображений(.jpg) формат, все они были прозрачными и черными цветными рисунками.

проблема в том, что теперь меня попросили изменить цвет рисунка (черный-на ).

но он вообще не соответствовал, я отладил его, по всему файлу не было значения красных,зеленых, синих параметров переменной Color (originalColor).

кто-нибудь может помочь?

вот решение, которое я сделал с пикселями.

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

У меня есть примеры изображений 128x128 (ширина x высота).

enter image description here

/ / ниже изображение образца и различные результаты путем прикладывать различный цвет

изменения кода будут высоко оценены.

прежде чем мы поговорим о perfromance давайте проверим ваш код:

здесь есть две ошибки:

  1. вы не сравниваете с Color.Black а вы присвоить Color.Black to originalColor .
  2. вы не обрабатываете прозрачность.

чтобы проверить прозрачность вы должны сравнить не Color объект, но значения R, G, B, Давайте изменим на:

теперь вы увидите, что он работает, но для этого требуется очень долгое время для обработки каждого изображения: GetPixel и SetPixel довольно медленные (первичные, потому что они проверяют и вычисляют все для каждого вызова). Гораздо лучше обрабатывать растровые данные напрямую. Если вы знаете формат изображения заранее (и он фиксирован для каждого изображения), то вы можете сделать это намного быстрее с небольшим количеством кода:

конечно это может быть дополнительно оптимизирован и вам может потребоваться обрабатывать различные форматы ( см. этот список пикселей форматы и в этой статье об их макете) , но считают его отправной точкой для работы с растровыми изображениями.

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

Также обратите внимание, что это рассмотреть альфа-канал в сравнении (так 50% прозрачный зеленый, например, не такой же цвет, как 30% прозрачный зеленый). Игнорировать Альфа тебя может использовать что-то вроде этого:

наконец, если вы знаете, что пикселей для замены мало, вы можете создать сырую копию исходного изображения (используя Graphics.FromImage создать контекст и втянуть в нее source bitmap), таким образом вы вызовете SetPixel() только когда есть замена. IMO любая оптимизация здесь довольно бесполезна: если вам нужна производительность, используйте первое решение.

один из способов эффективной замены цвета-использовать таблицу переназначения. В следующем примере изображение рисуется внутри окна изображения. В событии Paint цвет.Черный цвет меняется на цвет.Синий:

Я дам вам другое решение, так как это не вычисляется для каждого пикселя.

Читайте также: