2016-07-23 14 views
0

イメージがある場合はIと別のイメージJと置き換えて、位置をI(t,s)に置き換えてJ(t,s) 。 Core Imageやカスタムカーネルでどうすればいいですか?イメージ内の正確に1ピクセル置き換えてSwiftを介して別のイメージに入れます

これは、Core Imageの仕組みを考えると簡単ではないようです。しかし、ピクセルの値を(t,s)に抽出する方法があるのだろうかと疑問に思っていましたが、Jと同じ大きさの画像Kを作成し、その1点でJKをオーバーレイします。ちょうどアイデア、うまくいけば良い方法があります。

答えて

1

ただを1つのピクセルに設定する場合は、渡されたターゲット座標と現在の座標を比較し、出力を適切に色付けする小さなカラーカーネルを作成できます。たとえば:

その後
let kernel = CIColorKernel(string: 
"kernel vec4 setPixelColorAtCoord(__sample pixel, vec2 targetCoord, vec4 targetColor)" + 
    "{" + 
    " return int(targetCoord.x) == int(destCoord().x) && int(targetCoord.y) == int(destCoord().y) ? targetColor : pixel; " + 
    "}" 
) 

は、画像与えられた、のは、赤色の固体を言わせて:

let image = CIImage(color: CIColor(red: 1, green: 0, blue: 0)) 
    .imageByCroppingToRect(CGRect(x: 0, y: 0, width: 640, height: 640)) 

我々は青に、500で100ピクセルを設定する場合:

let targetCoord = CIVector(x: 500, y: 100) 
let targetColor = CIColor(red: 0, green: 0, blue: 1) 

次の例では、finalという名前のCIImageという名前の青いピクセルが赤の海に表示されます。

let args = [image, targetCoord, targetColor] 
let final = kernel?.applyWithExtent(image.extent, arguments: args) 

複数のピクセルを描画したい場合、これは最適な解決策ではないかもしれません。

サイモン

+0

Simon from the rescue!途中であなたの本を愛する! –

+0

実際には簡単な質問です。イメージから使用している色を参照したいと思います。 'vec4 targetColor'を実行する代わりに、色を取得するために別の__サンプルがあるとどうなりますか? 'vec4 targetColor = sample(pixel2、targetCoord)'を使って、参照する色を教えてください。 –

+0

カーネルに両方のイメージを渡し、 'vec2 imageSpaceCoord = samplerTransform(xyzImage、destCoord());でソースピクセルの色を取得することができます。 vec4 targetColor = sample(image、imageSpaceCoord); ' - ここで' xyzImage'はサンプリング元の画像です。この本のおかげで、ありがとうございました:) –

2

ピクセル単位で画像を扱うための有用なヘルパーを作成しました。基本的にはRGBA画像コンテキストを作成し、その画像を画像にコピーします(画像データをjpegなどで処理できるように)。そして、その生データバッファを取得します。これは私が作ったクラスです。

public final class RGBAPixels { 
    static let bitmapInfo = CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedLast.rawValue 
    static let colorSpace = CGColorSpaceCreateDeviceRGB() 
    public typealias Pixel = (r: UInt8, g: UInt8, b: UInt8, a: UInt8) 

    let context : CGContext 
    let pointer : UnsafeMutablePointer<Pixel> 

    public let width : Int 
    public let height : Int 

    public let range : (x: Range<Int>, y: Range<Int>) 

    /// Generates an image from the current pixels 
    public var CGImage : CGImageRef? { 
     return CGBitmapContextCreateImage(context) 
    } 

    public init?(CGImage: CGImageRef) { 
     width = CGImageGetWidth(CGImage) 
     height = CGImageGetHeight(CGImage) 

     range = (0..<width, 0..<height) 

     guard let context = CGBitmapContextCreate(
      nil, width, height, 8, sizeof(Pixel) * width, 
      RGBAPixels.colorSpace, RGBAPixels.bitmapInfo) 
     else { return nil } 

     self.context = context 

     let rect = CGRect(origin: .zero, size: CGSize(width: width, height: height)) 
     CGContextDrawImage(context, rect, CGImage) 

     pointer = UnsafeMutablePointer(CGBitmapContextGetData(context)) 
    } 


    public subscript (x: Int, y: Int) -> Pixel { 
     get { 
      assert(range.x ~= x && range.y ~= y, "Pixel position (\(x), \(y)) is out of the bounds \(range))") 
      return pointer[y * width + x] 
     } 
     set { 
      assert(range.x ~= x && range.y ~= y, "Pixel position (\(x), \(y)) is out of the bounds \(range))") 
      pointer[y * width + x] = newValue 
     } 
    } 
} 

それはは、それ自体で使用可能ですが、いくつかのより多くの利便性を持っている場合があります:

public protocol Image { 
    var CGImage : CGImageRef? { get } 
} 

public extension Image { 
    public var pixels : RGBAPixels? { 
     return CGImage.flatMap(RGBAPixels.init) 
    } 

    public func copy(@noescape modifying : (pixels: RGBAPixels) -> Void) -> CGImageRef? { 
     return pixels.flatMap{ pixels in 
      modifying(pixels: pixels) 
      return pixels.CGImage 
     } 
    } 
} 

extension CGImage : Image { 
    public var CGImage: CGImageRef? { return self } 
} 

#if os(iOS) 

import class UIKit.UIImage 

extension UIImage : Image {} 

extension RGBAPixels { 
    public var image : UIImage? { 
     return CGImage.map(UIImage.init) 
    } 
} 

#elseif os(OSX) 

import class AppKit.NSImage 

extension NSImage : Image { 
    public var CGImage : CGImageRef? { 
     var rect = CGRect(origin: .zero, size: size) 
     return CGImageForProposedRect(&rect, context: nil, hints: nil) 
    } 
} 

extension RGBAPixels { 
    public var image : NSImage? { 
     return cgImage.flatMap{ img in 
      NSImage(CGImage: img, size: CGSize(width: width, height: height)) 
     } 
    } 
} 

#endif 

それはこのように使用可能です:

let image = UIImage(named: "image")! 
let pixels = image.pixels! 

// Add a red square 
for x in 10..<15 { 
    for y in 10..<15 { 
     pixels[x, y] = (255, 0, 0, 255) 
    } 
} 

let modifiedImage = pixels.image 

// Copy the image, while changing the pixel at (10, 10) to be blue 
let otherImage = UIImage(named: "image")!.copy{ $0[10, 10] = (0, 255, 0, 255) } 


let a = UIImage(named: "image")!.pixels! 
let b = UIImage(named: "image")!.pixels! 

// Set the pixel at (10, 10) of a to the pixel at (20, 20) of b 
a[10, 10] = b[20, 20] 

let result = a.image! 

私はデモのためにラップしていませんが、実際にあなたのアプリでこれをしないでください。

実装はCPUと同じくらい高速です。ちょうどコピーするより複雑な方法でたくさんのイメージを変更する必要がある場合は、代わりにCoreImageを使用することができます。

OSXのNSImage s iOSのUIImageの両方でこの作業を行いました。

+0

は、しかし、これは私が主で働いていたものであるコアイメージ、代替を大好きだ、素晴らしいです。私はこれを行うにはUIImageにしてから変換するには少し非効率的かもしれないと思いますワンステップ。 –

+0

@DavidSacco私は、私はそう思った。誰かがCPU版を探しているなら、ここで見つけることができます:D –

関連する問題