2010-12-09 46 views
4

我需要從另一個UIImage(非灰度)獲取純黑白UIImage。任何人都可以幫助我?獲取黑白UIImage(非灰度)

感謝您的閱讀。

編輯:

這裏所提出的解決方案。謝謝大家。幾乎我知道這不是更好的方式,它可以正常工作。

// Gets an pure black and white image from an original image. 
- (UIImage *)pureBlackAndWhiteImage:(UIImage *)image { 

    unsigned char *dataBitmap = [self bitmapFromImage:image]; 

    for (int i = 0; i < image.size.width * image.size.height * 4; i += 4) { 

     if ((dataBitmap[i + 1] + dataBitmap[i + 2] + dataBitmap[i + 3]) < (255 * 3/2)) { 
      dataBitmap[i + 1] = 0; 
      dataBitmap[i + 2] = 0; 
      dataBitmap[i + 3] = 0; 
     } else { 
      dataBitmap[i + 1] = 255; 
      dataBitmap[i + 2] = 255; 
      dataBitmap[i + 3] = 255; 
     } 
    } 

    image = [self imageWithBits:dataBitmap withSize:image.size]; 

    return image; 
} 

EDITED 1:

響應於評論,這裏是方法bitmapFromImageimageWithBits

// Retrieves the bits from the context once the image has been drawn. 
- (unsigned char *)bitmapFromImage:(UIImage *)image { 

    // Creates a bitmap from the given image. 
    CGContextRef contex = CreateARGBBitmapContext(image.size); 
    if (contex == NULL) { 
     return NULL; 
    } 

    CGRect rect = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height); 
    CGContextDrawImage(contex, rect, image.CGImage); 
    unsigned char *data = CGBitmapContextGetData(contex); 
    CGContextRelease(contex); 

    return data; 
} 

// Fills an image with bits. 
- (UIImage *)imageWithBits:(unsigned char *)bits withSize:(CGSize)size { 

    // Creates a color space 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    if (colorSpace == NULL) { 

     fprintf(stderr, "Error allocating color space\n"); 
     free(bits); 
     return nil; 
    } 

    CGContextRef context = CGBitmapContextCreate (bits, size.width, size.height, 8, size.width * 4, colorSpace, kCGImageAlphaPremultipliedFirst); 
    if (context == NULL) { 

     fprintf (stderr, "Error. Context not created\n"); 
     free (bits); 
     CGColorSpaceRelease(colorSpace); 
     return nil; 
    } 

    CGColorSpaceRelease(colorSpace); 
    CGImageRef ref = CGBitmapContextCreateImage(context); 
    free(CGBitmapContextGetData(context)); 
    CGContextRelease(context); 

    UIImage *img = [UIImage imageWithCGImage:ref]; 
    CFRelease(ref); 
    return img; 
} 
+0

我編輯了我的問題,並添加了Brad Larson和您提出的答案。 – 2010-12-10 16:41:56

+0

您可以發佈`bitmapFromImage`和`imageWithBits`方法嗎? – Osi 2013-03-16 12:40:30

+0

在這裏,你有他們@Osi。對不起,延遲。 – 2014-02-24 17:29:02

回答

8

如果你正在尋找的是圖像的閾值 - 比某個值更亮的東西變成白色,一切變黑變成黑色,然後選擇該值 - 那麼像GPU Image這樣的圖書館將適合你。

2

雖然它可能是矯枉過正你的目的,我做到這一點從iPhone的攝像頭在我的示例應用程序here視頻直播。該應用程序需要一種顏色和一種敏感度,並且可以將所有像素都設置爲白色,如果不是這樣,則爲透明。我使用OpenGL ES 2.0可編程着色器來獲得實時響應。整個事情在這篇文章here中描述。

同樣,這可能是你想要的矯枉過正。在想要轉換爲黑白的簡單UIImage的情況下,您可以讀取原始像素,遍歷它們,並應用相同類型的閾值來輸出最終圖像。這不會像着色器方法那樣快,但編碼會更簡單。

1

的代碼工作適合我,只是需要一些好辦法...這裏是我做了,通過設定值dataBitmap[] array的零指數正常工作這幾年的變化......

 for (int i = 0; i < image.size.width * image.size.height * 4; i += 4) { 
      //here an index for zeroth element is assigned 
      if ((dataBitmap[i + 0]+dataBitmap[i + 1] + dataBitmap[i + 2] + dataBitmap[i + 3]) < (255 * 4/2)) { 
     // multiply four,instead of three    
       dataBitmap[i + 0] = 0; 
       dataBitmap[i + 1] = 0; 
       dataBitmap[i + 2] = 0; 
       dataBitmap[i + 3] = 0; 
      } else { 
       dataBitmap[i + 0] = 255; 
       dataBitmap[i + 1] = 255; 
       dataBitmap[i + 2] = 255; 
       dataBitmap[i + 3] = 255; 
      } 
     } 

希望它會工作。

6

此代碼可以幫助:

for (int i = 0; i < image.size.width * image.size.height * 4; i += 4) { 
     if (dataBitmap[i + 0] >= dataBitmap[i + 1] && dataBitmap[i + 0] >= dataBitmap[i + 2]){ 
     dataBitmap[i + 1] = dataBitmap[i + 0]; 
     dataBitmap[i + 2] = dataBitmap[i + 0]; 
    } 
    else if (dataBitmap[i + 1] >= dataBitmap[i + 0] && dataBitmap[i + 1] >= dataBitmap[i + 2]) { 
     dataBitmap[i + 0] = dataBitmap[i + 1]; 
     dataBitmap[i + 2] = dataBitmap[i + 1]; 
    } 
    else { 
     dataBitmap[i + 0] = dataBitmap[i + 2]; 
     dataBitmap[i + 1] = dataBitmap[i + 2]; 
    } 
} 
0

這裏有一個快速的3溶液:

class func pureBlackAndWhiteImage(_ inputImage: UIImage) -> UIImage? { 

    guard let inputCGImage = inputImage.cgImage, let context = getImageContext(for: inputCGImage), let data = context.data else { return nil } 

    let white = RGBA32(red: 255, green: 255, blue: 255, alpha: 255) 
    let black = RGBA32(red: 0, green: 0, blue: 0, alpha: 255) 

    let width = Int(inputCGImage.width) 
    let height = Int(inputCGImage.height) 
    let pixelBuffer = data.bindMemory(to: RGBA32.self, capacity: width * height) 

    for x in 0 ..< height { 
     for y in 0 ..< width { 
      let offset = x * width + y 
      if pixelBuffer[offset].red > 0 || pixelBuffer[offset].green > 0 || pixelBuffer[offset].blue > 0 { 
       pixelBuffer[offset] = black 
      } else { 
       pixelBuffer[offset] = white 
      } 
     } 
    } 

    let outputCGImage = context.makeImage() 
    let outputImage = UIImage(cgImage: outputCGImage!, scale: inputImage.scale, orientation: inputImage.imageOrientation) 

    return outputImage 
} 

class func getImageContext(for inputCGImage: CGImage) ->CGContext? { 

    let colorSpace  = CGColorSpaceCreateDeviceRGB() 
    let width   = inputCGImage.width 
    let height   = inputCGImage.height 
    let bytesPerPixel = 4 
    let bitsPerComponent = 8 
    let bytesPerRow  = bytesPerPixel * width 
    let bitmapInfo  = RGBA32.bitmapInfo 

    guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { 
     print("unable to create context") 
     return nil 
    } 

    context.setBlendMode(.copy) 
    context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height))) 

    return context 
} 

struct RGBA32: Equatable { 
    var color: UInt32 

    var red: UInt8 { 
     return UInt8((color >> 24) & 255) 
    } 

    var green: UInt8 { 
     return UInt8((color >> 16) & 255) 
    } 

    var blue: UInt8 { 
     return UInt8((color >> 8) & 255) 
    } 

    var alpha: UInt8 { 
     return UInt8((color >> 0) & 255) 
    } 

    init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) { 
     color = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0) 
    } 

    static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue 
} 

func ==(lhs: RGBA32, rhs: RGBA32) -> Bool { 
    return lhs.color == rhs.color 
} 
0

與SWIFT 3,我能夠通過使用CIFilters,首先通過應用CIPhotoEffectNoir來實現這種效果(以使其灰度),然後應用CIColorControl篩選器,將kCIInputContrastKey輸入參數設置爲較高值(即50)。設置kCIInputBrightnessKey參數還會調整黑白對比度的強度,對較暗的圖像爲負值,對較亮的圖像爲正值。例如:

extension UIImage { 
    func toBlackAndWhite() -> UIImage? { 
     guard let ciImage = CIImage(image: self) else { 
      return nil 
     } 
     guard let grayImage = CIFilter(name: "CIPhotoEffectNoir", withInputParameters: [kCIInputImageKey: ciImage])?.outputImage else { 
      return nil 
     } 
     let bAndWParams: [String: Any] = [kCIInputImageKey: grayImage, 
              kCIInputContrastKey: 50.0, 
              kCIInputBrightnessKey: 10.0] 
     guard let bAndWImage = CIFilter(name: "CIColorControls", withInputParameters: bAndWParams)?.outputImage else { 
      return nil 
     } 
     guard let cgImage = CIContext(options: nil).createCGImage(bAndWImage, from: bAndWImage.extent) else { 
      return nil 
     } 
     return UIImage(cgImage: cgImage) 
    } 
}