2016-07-23 3 views
0

간단히 말해서 이미지가 I이고 다른 이미지가 J 인 경우, I(t,s)의 RGB 값을 대체하고 해당 픽셀을 J(t,s) . 코어 이미지 나 커스텀 커널에서 어떻게하면됩니까?이미지의 정확히 하나의 픽셀을 바꾸어 Swift를 통해 다른 이미지에 넣기

이것은 Core Image가 작동하는 방식을 고려할 때 쉬운 일이 아닌 것처럼 보입니다. 그러나, 어쩌면 거기에 (t,s)에서 픽셀의 값을 추출 할 수있는 방법이 궁금 해서요, J만큼 큰 픽셀로 이미지를 만들고 JK 그 한 지점에서만 오버레이. 그냥 아이디어, 잘하면 더 좋은 방법이 있습니다.

답변

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) 

하나 이상의 픽셀을 그리려면이 방법이 최적의 솔루션이 아닐 수도 있습니다.

사이먼

이, 그러나 내가 주로에서 일한지 무슨. 내가이 작업을 수행하기 위해와있는 UIImage로 변환하는 약간 비효율적 일 수 있습니다 생각입니다 코어 이미지에 대한 대안을 사랑 중대하다
+0

Simon from the rescue! 그나저나 책을 사랑해! –

+0

빠른 질문 - 실제로 이미지에서 사용하고있는 색상을 참조하고 싶습니다. 'vec4 targetColor'를하는 대신 색상을 얻을 다른 __sample이 있으면 어떻게 될까요? 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

한 걸음. –

+0

@DavidSacco 알았어, 나는 그렇게 생각했다.누군가 CPU 버전을 찾고 있다면 여기에서 찾을 수 있습니다 : D –