2016-03-29 1 views
2

Существуют ли существующие фильтры, которые можно использовать как плавный порог? Под этим я подразумеваю, что значения пикселей должны быть пороговыми между двумя значениями, но промежуточные значения интерполируются.Как использовать CoreImage для создания гладкого порогового фильтра?

В принципе, я пытаюсь осуществить это:

https://www.filterforge.com/wiki/index.php/Thresholds#Interpolation_.28.22Blending.22.29

ответ

6

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

Я бы использовал smoothstep и передал два значения по краю вместе с яркостью текущего пикселя. CIKL может выглядеть примерно так:

kernel vec4 color(__sample pixel, float inputEdgeO, float inputEdge1) 
{ 
    float luma = dot(pixel.rgb, vec3(0.2126, 0.7152, 0.0722)); 
    float threshold = smoothstep(inputEdgeO, inputEdge1, luma); 
    return vec4(threshold, threshold, threshold, 1.0); 
} 

Вы можете обернуть это в CIFilter со следующим кодом:

class SmoothThreshold: CIFilter 
{ 
    var inputImage : CIImage? 
    var inputEdgeO: CGFloat = 0.25 
    var inputEdge1: CGFloat = 0.75 

    var colorKernel = CIColorKernel(string: 
     "kernel vec4 color(__sample pixel, float inputEdgeO, float inputEdge1)" + 
     "{" + 
     " float luma = dot(pixel.rgb, vec3(0.2126, 0.7152, 0.0722));" + 
     " float threshold = smoothstep(inputEdgeO, inputEdge1, luma);" + 
     " return vec4(threshold, threshold, threshold, 1.0);" + 
     "}" 
    ) 

    override var outputImage: CIImage! 
    { 
     guard let inputImage = inputImage, 
      colorKernel = colorKernel else 
     { 
      return nil 
     } 

     let extent = inputImage.extent 
     let arguments = [inputImage, 
         inputEdgeO, 
         inputEdge1] 

     return colorKernel.applyWithExtent(extent, 
              arguments: arguments) 
    } 
} 

Обратите внимание, что вам необходимо обеспечить inputEdge0 меньше inputEdge1, или в smoothstep будет немного сумасшедшим. Вы можете saturate их тоже, чтобы убедиться, что они между 0 и 1.

Посмотрите CIFilter.registerFilterName, который позволит вам создать экземпляр SmoothThreshold с знакомым синтаксисом, хотя это будет работать нормально:

let image = CIImage(image: UIImage(named: "monalisa.jpg")!)! 

let filter = SmoothThreshold() 
filter.inputImage = image 

let final = filter.outputImage 

Приветствия!

Simon

+0

Спасибо! Меня больше интересовал алгоритм, так как я знаком с созданием ядер. Почему вы сравниваете канал яркости? (Меня интересует только сравнение средних значений RGB, но мне все еще интересно узнать о причине яркости). – joelg

+1

Зависит от варианта использования: если это пороговое значение по воспринимаемой яркости, усреднение не совсем корректно. Чистый зеленый (0,1,0) намного ярче, чем чистый синий (0,0,1), но имеет одинаковые средние значения. –

+0

Да, общий смысл. В конце дня я просто пытался выполнить то, что описано здесь: https://www.filterforge.com/wiki/index.php/Thresholds#Interpolation_.28.22Blending.22.29 – joelg

1

Это в конечном итоге работает для меня:

[CIColorKernel kernelWithString: 
       @"kernel vec4 threshold(__sample s, float thresh) {\n" 
       "float avg = (s.r + s.g + s.b)/3.0;\n" 
       "float val = smoothstep(0.0, thresh, avg);" 
       "return vec4(val, val, val, 1.0);\n}"];