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

Мой вопрос: если у меня есть изображение Льва, я хочу изменить цвет льва, а не цвет фона. Для этого я назвал этот вопрос SO, но он превратил цвет всего изображения. Кроме того, изображение не выглядит великолепным. Мне нужно изменение цвета, как Photoshop. возможно ли это сделать в coregraphics, или мне нужно использовать любую другую библиотеку.

EDIT: Мне нужно изменить цвет, чтобы быть как приложение iQuikColor

введите описание изображения здесь

См. Ответы ниже. Шахта не дает полного решения.


Вот эскиз возможного решения с использованием OpenCV:

  • Преобразуйте изображение из RGB в HSV с помощью cvCvtColor (мы хотим только изменить оттенок).
  • cvThreshold цвет с cvThreshold указав определенный допуск (вы хотите диапазон цветов, а не один плоский цвет).
  • Отбросьте области цвета ниже минимального размера, используя библиотеку детектирования blob, такую ​​как cvBlobsLib . Это избавит вас от точек подобного цвета в сцене.
  • cvInRangeS цвет cvInRangeS и используйте полученную маску для применения нового оттенка.
  • cvMerge новое изображение с новым оттенком с изображением, состоящим из каналов насыщенности и яркости, которые вы сохранили на cvMerge шаге.

В сети есть несколько портов iOS OpenCV, например: http://www.eosgarden.com/en/opensource/opencv-ios/overview/ Я не пробовал это сам, но, похоже, является хорошим направлением исследований.

Это заняло довольно много времени, чтобы понять, в основном потому, что я хотел его запустить и запустить в Swift с помощью Core Image и CIColorCube.

Объяснение Мигеля объясняется тем, как вам нужно заменить «диапазон углов оттенков» другим «диапазоном углов оттенка». Вы можете прочитать его сообщение выше, чтобы узнать, что такое Угол углов Хюэ.

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

введите описание изображения здесь

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

Я жестко кодирую диапазон Hue равным 60 gradleусам, который обычно, как представляется, охватывает большую часть определенного цвета, но вы можете редактировать это, если вам нужно.

введите описание изображения здесь

введите описание изображения здесь

Обратите внимание на то, что он не окрашивает шины или задние фонари, потому что это находится за пределами 60-gradleусного диапазона голубого оттенка по умолчанию для грузовика, но он отлично справляется с затенением.

Сначала вам нужен код для преобразования RGB в HSV (значение оттенка):

 func RGBtoHSV(r : Float, g : Float, b : Float) -> (h : Float, s : Float, v : Float) { var h : CGFloat = 0 var s : CGFloat = 0 var v : CGFloat = 0 let col = UIColor(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: 1.0) col.getHue(&h, saturation: &s, brightness: &v, alpha: nil) return (Float(h), Float(s), Float(v)) } 

Затем вам нужно преобразовать HSV в RGB. Вы хотите использовать это, когда обнаруживаете оттенок, который в вашем желаемом диапазоне оттенков (ака, цвет, который является тем же самым синим оттенком грузовика по умолчанию), чтобы сэкономить любые корректировки, которые вы делаете.

 func HSVtoRGB(h : Float, s : Float, v : Float) -> (r : Float, g : Float, b : Float) { var r : Float = 0 var g : Float = 0 var b : Float = 0 let C = s * v let HS = h * 6.0 let X = C * (1.0 - fabsf(fmodf(HS, 2.0) - 1.0)) if (HS >= 0 && HS < 1) { r = C g = X b = 0 } else if (HS >= 1 && HS < 2) { r = X g = C b = 0 } else if (HS >= 2 && HS < 3) { r = 0 g = C b = X } else if (HS >= 3 && HS < 4) { r = 0 g = X b = C } else if (HS >= 4 && HS < 5) { r = X g = 0 b = C } else if (HS >= 5 && HS < 6) { r = C g = 0 b = X } let m = v - C r += m g += m b += m return (r, g, b) } 

Теперь вы просто пропустите полный цветовой куб RGBA и «настроите» любые цвета в диапазоне оттенков «по умолчанию» с теми же оттенками нового оттенка. Затем используйте Core Image и фильтр CIColorCube, чтобы применить настроенный куб цвета к изображению.

 func render() { let centerHueAngle: Float = 214.0/360.0 //default color of truck body blue let destCenterHueAngle: Float = slider.value let minHueAngle: Float = (214.0 - 60.0/2.0) / 360 //60 degree range = +30 -30 let maxHueAngle: Float = (214.0 + 60.0/2.0) / 360 var hueAdjustment = centerHueAngle - destCenterHueAngle let size = 64 var cubeData = [Float](count: size * size * size * 4, repeatedValue: 0) var rgb: [Float] = [0, 0, 0] var hsv: (h : Float, s : Float, v : Float) var newRGB: (r : Float, g : Float, b : Float) var offset = 0 for var z = 0; z < size; z++ { rgb[2] = Float(z) / Float(size) // blue value for var y = 0; y < size; y++ { rgb[1] = Float(y) / Float(size) // green value for var x = 0; x < size; x++ { rgb[0] = Float(x) / Float(size) // red value hsv = RGBtoHSV(rgb[0], g: rgb[1], b: rgb[2]) if hsv.h < minHueAngle || hsv.h > maxHueAngle { newRGB.r = rgb[0] newRGB.g = rgb[1] newRGB.b = rgb[2] } else { hsv.h = destCenterHueAngle == 1 ? 0 : hsv.h - hueAdjustment //force red if slider angle is 360 newRGB = HSVtoRGB(hsv.h, s:hsv.s, v:hsv.v) } cubeData[offset] = newRGB.r cubeData[offset+1] = newRGB.g cubeData[offset+2] = newRGB.b cubeData[offset+3] = 1.0 offset += 4 } } } let data = NSData(bytes: cubeData, length: cubeData.count * sizeof(Float)) let colorCube = CIFilter(name: "CIColorCube")! colorCube.setValue(size, forKey: "inputCubeDimension") colorCube.setValue(data, forKey: "inputCubeData") colorCube.setValue(ciImage, forKey: kCIInputImageKey) if let outImage = colorCube.outputImage { let context = CIContext(options: nil) let outputImageRef = context.createCGImage(outImage, fromRect: outImage.extent) imageView.image = UIImage(CGImage: outputImageRef) } } 

Вы можете скачать образец проекта здесь . Он использует Xcode 7 и Swift 2.0.

Я сделаю предположение, что вы знаете, как выполнять эти основные операции, поэтому они не будут включены в мое решение:

  • загрузить изображение
  • получить значение RGB заданного пикселя загруженного изображения
  • установить значение RGB заданного пикселя
  • отображать загруженное изображение и / или сохранять его обратно на диск.

Прежде всего, давайте рассмотрим, как вы можете описать цвета источника и назначения. Ясно, что вы не можете указать их как точное значение RGB, так как фотография будет иметь небольшие изменения в цвете. Например, зеленые пиксели в изображении грузовика, который вы опубликовали, не совсем точно совпадают с зеленым. Цветовая модель RGB не очень хороша для выражения базовых цветовых характеристик, поэтому вы получите гораздо лучшие результаты, если будете конвертировать пиксели в HSL. Вот C-функции для преобразования RGB в HSL и обратно.

Цветовая модель HSL описывает три аспекта цвета:

  1. Хюэ – основной воспринимаемый цвет – то есть красный, зеленый, оранжевый и т. Д.
  2. Насыщенность – как «полный» цвет – то есть от полного цвета до какого-либо цвета вообще
  3. Легкость – насколько яркий цвет

Например, если вы хотите найти все зеленые пиксели на изображении, вы будете конвертировать каждый пиксель из RGB в HSL, а затем искать значения H, соответствующие зеленому, с некоторым допуском для цветов «ближе зеленого». Ниже приведен график оттенков, из Википедии:

Поэтому в вашем случае вы будете искать пиксели с оттенком 120 gradleусов +/- некоторую сумму. Чем больше диапазон, тем больше цветов будет выбрано. Если вы сделаете свой диапазон слишком широким, вы начнете выбирать выбранные желтые и голубые пиксели, поэтому вам нужно будет найти правильный диапазон, и вы даже можете предложить пользователю ваших элементов управления приложениями выбрать этот диапазон.

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

Наконец, вы можете предложить пользователю возможность нарисовать «выбор лассо», чтобы отдельные части изображения могли быть исключены из раскраски. Вот как вы могли бы сказать приложению, что хотите тело зеленого грузовика, но не зеленое колесо.

Как только вы узнаете, какие пиксели вы хотите изменить, пришло время изменить их цвет.

Самый простой способ раскрасить пиксели – это просто изменить оттенок, оставив Насыщенность и Легкость от исходного пикселя. Например, если вы хотите сделать зеленые пиксели magenta, вы добавите 180 gradleусов к всем значениям оттенка выбранных пикселей (убедитесь, что вы используете математику по модулю 360).

Если вы хотите стать более сложными, вы также можете применить изменения к Saturation, и это даст вам более широкий диапазон тем, в которые вы можете пойти. Я думаю, что Lightness лучше оставить в покое, вы можете сделать небольшие настройки, и изображение по-прежнему будет выглядеть хорошо, но если вы заходите слишком далеко от оригинала, вы можете начать видеть жесткие края, где пиксели процесса граничат с фоновыми пикселями.

Как только у вас есть раскрашенный пиксел HSL, вы просто преобразуете его обратно в RGB и записываете обратно в изображение.

Надеюсь, это поможет. Последний комментарий, который я должен сделать, это то, что значения Hue в коде обычно записываются в диапазоне 0-255, но многие приложения показывают их как цветовое колесо с диапазоном от 0 до 360 gradleусов. Запомни!

Могу ли я предложить вам изучить OpenCV ? Это библиотека управления изображениями с открытым исходным кодом, и у нее тоже есть порт iOS. Есть много сообщений в блогах о том, как их использовать и настроить.

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

Он был разработан некоторыми людьми в Массачусетском технологическом институте, так как вы могли бы ожидать, что он справится с довольно хорошей работой в таких областях, как обнаружение границ и отслеживание объектов. Я помню, как читал блог о том, как отделить определенный цвет от изображения с помощью OpenCV – примеры показали довольно хороший результат. См. Здесь пример. Оттуда я не могу представить, что было бы огромной работой, чтобы фактически изменить выделенный цвет на что-то еще.

Я не знаю об операции CoreGraphics для этого, и я не вижу подходящего фильтра CoreImage для этого. Если это правильно, то вот толчок в правильном направлении:

Предполагая, что у вас есть CGImage (или uiImage.CGImage ):

  • Начните с создания нового CGBitmapContext
  • Нарисуйте исходное изображение в растровом контексте
  • Получить дескриптор пиксельных данных растрового изображения

Узнайте, как структурирован буфер, чтобы вы могли правильно заполнить 2D-массив значений пикселей, которые имеют форму:

 typedef struct t_pixel { uint8_t r, g, b, a; } t_pixel; 

Затем создайте цвет для поиска:

 const t_pixel ColorToLocate = { 0,0,0,255 }; // << black, opaque 

И его значение замены:

 const t_pixel SubstitutionColor = { 255,255,255,255 }; // << white, opaque 
  • Итерации в пиксельном буфере контекста t_pixel , создавая t_pixel s.
  • Когда вы найдете пиксель, который соответствует ColorToLocate , замените исходные значения значениями в SubstitutionColor .

  • Создайте новый CGImage из CGBitmapContext .

Это легкая часть! Все, что делает, - это CGImage , замена точных совпадений цветов и создание нового CGImage .

То, что вы хотите, более изощренно. Для этой задачи вам понадобится хороший алгоритм обнаружения края.

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

Если (в приложении, которое вы связали), пользователь может выбрать произвольные цвета, значения и граничные пороги, тогда вам придется использовать реальное смешение и обнаружение края. Если вам нужно посмотреть, как это делается, вы можете проверить пакет, такой как Gimp (это открытый редактор изображений) - у них есть algos для обнаружения краев и выбора по цвету.

  • Координаты текстуры OpenGL в пиксельном пространстве
  • Использование Objective C / Cocoa для unescape символов Unicode, то есть \ u1234
  • Почему NSUserDefaults не удалось сохранить NSMutableDictionary в iPhone SDK?
  • @synthesize vs @dynamic, каковы различия?
  • На iPhone: узнать, какая песня сейчас играет? (в музыкальном проигрывателе iPod)
  • Xcode - обновить текст метки ViewController с другого вида
  • Синглтон в iOS 5?
  • Можно ли перепроектировать мое приложение iPhone?
  • Какую строку формата я использую в миллисекундах в строках даты на iPhone?
  • drawRect не вызывается в моем подclassе UIImageView
  • Использование Swift CFunctionPointer для передачи обратного вызова API CoreMIDI
  • Interesting Posts
    Давайте будем гением компьютера.