我需要从另一个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;
}
已编辑1:
在回复评论时,以下是方法bitmapFromImage
和imageWithBits
。
// 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 :(得分:8)
如果您正在寻找的是对图像进行阈值处理 - 比某个值更亮的所有内容都会变为白色,一切颜色变黑,然后您选择该值 - 那么像GPU Image这样的库将会起作用你。
答案 1 :(得分: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];
}
}
答案 2 :(得分:2)
虽然对于您的目的而言可能有些过分,但我会在示例应用程序here中使用iPhone相机的实时视频。该应用程序采用颜色和灵敏度,并且可以将所有像素变为白色,即使不是,也可以是透明的。我为此使用OpenGL ES 2.0可编程着色器以获得实时响应。这篇文章here中描述了整个事情。
同样,这可能对你想要的东西有点过分。在想要转换为黑白的简单UIImage的情况下,您可以读取原始像素,遍历它们,并应用我所做的相同类型的阈值来输出最终图像。这不会像着色器方法那么快,但编码会更简单。
答案 3 :(得分: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;
}
}
希望它能奏效。
答案 4 :(得分:1)
使用Swift 3,我能够通过使用CIFilter来实现此效果,首先应用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)
}
}
答案 5 :(得分:0)
这是一个迅速的解决方案:
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
}