2015-10-19 46 views
2

我試圖通過更改像素來編輯圖像。如何使用CGContext獲取像素的RGB值?

我有以下代碼:

let imageRect = CGRectMake(0, 0, self.image.image!.size.width, self.image.image!.size.height) 

    UIGraphicsBeginImageContext(self.image.image!.size) 
    let context = UIGraphicsGetCurrentContext() 

    CGContextSaveGState(context) 
    CGContextDrawImage(context, imageRect, self.image.image!.CGImage) 

    for x in 0...Int(self.image.image!.size.width) { 
     for y in 0...Int(self.image.image!.size.height) { 
      var red = 0 
      if y % 2 == 0 { 
       red = 255 
      } 

      CGContextSetRGBFillColor(context, CGFloat(red/255), 0.5, 0.5, 1) 
      CGContextFillRect(context, CGRectMake(CGFloat(x), CGFloat(y), 1, 1)) 
     } 
    } 
    CGContextRestoreGState(context) 
    self.image.image = UIGraphicsGetImageFromCurrentImageContext() 

我循環通過所有的像素,並且改變每個像素的值,然後將其轉換回圖像。想要我想要做的是以某種方式獲取當前像素的值(在y for for循環中)並對該數據執行某些操作。在互聯網上我沒有發現任何關於這個特殊問題的信息。

+1

你試過這個:http://stackoverflow.com/questions/144250/how-to-get-the-rgb-values-for-a--pixel-on-an-image-on-the-iphone –

+0

相關的答案看起來不錯IMO –

回答

2

好吧,我想我有一個應該爲你在斯威夫特工作2

幸得this answer爲以下的UIColor擴展的解決方案。

因爲我需要的圖像,以測試這對我選擇了一個切片 - 您的gravatar(50×50左上角)...

所以下面的代碼轉換這樣的:
enter image description here

要這樣:
enter image description here

這在操場對我的作品 - 所有你應該做的就是複製並粘貼到操場看到的結果:

//: Playground - noun: a place where people can play 

import UIKit 
import XCPlayground 

extension CALayer { 

    func colorOfPoint(point:CGPoint) -> UIColor 
    { 
     var pixel:[CUnsignedChar] = [0,0,0,0] 

     let colorSpace = CGColorSpaceCreateDeviceRGB() 
     let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue) 

     let context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, colorSpace,bitmapInfo.rawValue) 

     CGContextTranslateCTM(context, -point.x, -point.y) 

     self.renderInContext(context!) 

     let red:CGFloat = CGFloat(pixel[0])/255.0 
     let green:CGFloat = CGFloat(pixel[1])/255.0 
     let blue:CGFloat = CGFloat(pixel[2])/255.0 
     let alpha:CGFloat = CGFloat(pixel[3])/255.0 

     //println("point color - red:\(red) green:\(green) blue:\(blue)") 

     let color = UIColor(red:red, green: green, blue:blue, alpha:alpha) 

     return color 
    } 
} 

extension UIColor { 
    var components:(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { 
     var r:CGFloat = 0 
     var g:CGFloat = 0 
     var b:CGFloat = 0 
     var a:CGFloat = 0 
     getRed(&r, green: &g, blue: &b, alpha: &a) 
     return (r,g,b,a) 
    } 
} 


//get an image we can work on 
var imageFromURL = UIImage(data: NSData(contentsOfURL: NSURL(string:"https://www.gravatar.com/avatar/ba4178644a33a51e928ffd820269347c?s=328&d=identicon&r=PG&f=1")!)!) 
//only use a small area of that image - 50 x 50 square 
let imageSliceArea = CGRectMake(0, 0, 50, 50); 
let imageSlice = CGImageCreateWithImageInRect(imageFromURL?.CGImage, imageSliceArea); 
//we'll work on this image 
var image = UIImage(CGImage: imageSlice!) 


let imageView = UIImageView(image: image) 
//test out the extension above on the point (0,0) - returns r 0.541 g 0.78 b 0.227 a 1.0 
var pointColor = imageView.layer.colorOfPoint(CGPoint(x: 0, y: 0)) 



let imageRect = CGRectMake(0, 0, image.size.width, image.size.height) 

UIGraphicsBeginImageContext(image.size) 
let context = UIGraphicsGetCurrentContext() 

CGContextSaveGState(context) 
CGContextDrawImage(context, imageRect, image.CGImage) 

for x in 0...Int(image.size.width) { 
    for y in 0...Int(image.size.height) { 
     var pointColor = imageView.layer.colorOfPoint(CGPoint(x: x, y: y)) 
     //I used my own creativity here - change this to whatever logic you want 
     if y % 2 == 0 { 
      CGContextSetRGBFillColor(context, pointColor.components.red , 0.5, 0.5, 1) 
     } 
     else { 
      CGContextSetRGBFillColor(context, 255, 0.5, 0.5, 1) 
     } 

     CGContextFillRect(context, CGRectMake(CGFloat(x), CGFloat(y), 1, 1)) 
    } 
} 
CGContextRestoreGState(context) 
image = UIGraphicsGetImageFromCurrentImageContext() 

我希望這對你有用。我玩得很開心!

+0

你的意思是:定義上下文時的bitmapInfo.rawValue – SemAllush

+0

是的,謝謝,我添加了Swift 2特定的代碼... – ProgrammierTier

+0

沒有工作:layer.bounds.maxX與image.size不同。寬度,所以它縮小圖片,並用黑色填充其餘的部分 – SemAllush

0

在封面下,UIGraphicsBeginImageContext創建了一個CGBitmapContext。您可以使用CGBitmapContextGetData訪問上下文的像素存儲。這種方法的問題是UIGraphicsBeginImageContext函數選擇用於存儲像素數據的字節順序和顏色空間。這些選擇(尤其是字節順序)可能會在未來版本的iOS中(甚至在不同的設備上)發生變化。

所以我們直接用CGBitmapContextCreate創建上下文,這樣我們就可以確定字節順序和顏色空間。

在我的操場上,我添加了一張名爲[email protected]的測試圖像。

import XCPlayground 
import UIKit 

let image = UIImage(named: "pic.jpeg")! 
XCPCaptureValue("image", value: image) 

下面是我們如何創建位圖背景下,拍攝圖像的規模考慮(你沒有在你的問題做):

let rowCount = Int(image.size.height * image.scale) 
let columnCount = Int(image.size.width * image.scale) 
let stride = 64 * ((columnCount * 4 + 63)/64) 
let context = CGBitmapContextCreate(nil, columnCount, rowCount, 8, stride, 
    CGColorSpaceCreateDeviceRGB(), 
    CGBitmapInfo.ByteOrder32Little.rawValue | 
    CGImageAlphaInfo.PremultipliedLast.rawValue) 

接下來,我們調整座標系匹配的內容UIGraphicsBeginImageContextWithOptions會做,這樣我們就可以正確地和輕鬆地繪製圖像:

CGContextTranslateCTM(context, 0, CGFloat(rowCount)) 
CGContextScaleCTM(context, image.scale, -image.scale) 

UIGraphicsPushContext(context!) 
image.drawAtPoint(CGPointZero) 
UIGraphicsPopContext() 

注意UIImage.drawAtPoint需要image.orientation考慮。 CGContextDrawImage不。

現在我們來看一個指向上下文中原始像素數據的指針。該代碼是更清楚,如果我們定義一個結構來訪問每個像素的各個部件:

struct Pixel { 
    var a: UInt8 
    var b: UInt8 
    var g: UInt8 
    var r: UInt8 
} 

let pixels = UnsafeMutablePointer<Pixel>(CGBitmapContextGetData(context)) 

注意,Pixel成員的順序被定義爲我在bitmapInfo參數設置爲CGBitmapContextCreate特定比特匹配。

現在我們可以遍歷像素。注意,我們使用rowCountcolumnCount,上面計算,訪問所有的像素,不顧形象的規模:

for y in 0 ..< rowCount { 
    if y % 2 == 0 { 
     for x in 0 ..< columnCount { 
      let pixel = pixels.advancedBy(y * stride/sizeof(Pixel.self) + x) 
      pixel.memory.r = 255 
     } 
    } 
} 

最後,我們從上下文的新形象:

let newImage = UIImage(CGImage: CGBitmapContextCreateImage(context)!, scale: image.scale, orientation: UIImageOrientation.Up) 

XCPCaptureValue("newImage", value: newImage) 

結果在我的遊樂場的時間表:

timeline screenshot

最後,請注意,如果你的圖片是大的,要通過PIX以像素爲單位可能會很慢。如果您可以找到一種方法來使用Core Image或GPUImage來執行圖像處理,它將會快得多。否則,使用Objective-C並手動向量化(使用NEON內在函數)可能會大大提升。

+0

你有鏈接到NEON內部函數嗎? – SemAllush

+0

只是谷歌它。有很多列表和例子。 –

+0

它可以讓我改變像素數據嗎? – SemAllush