Получение CGImage из CIImage

У меня есть UIImage, который загружается из CIImage с помощью:

tempImage = [UIImage imageWithCIImage:ciImage];

Проблема в том, что мне нужно обрезать tempImage до определенного CGRect, и единственный известный мне способ сделать это — использовать CGImage. Проблема в том, что в документации iOS 6.0 я нашел это:

CGImage
If the UIImage object was initialized using a CIImage object, the value of the property is NULL.

A. Как преобразовать CIImage в CGImage? Я использую этот код, но у меня есть утечка памяти (и не могу понять, где):

+(UIImage*)UIImageFromCIImage:(CIImage*)ciImage {  
    CGSize size = ciImage.extent.size;  
    UIGraphicsBeginImageContext(size);  
    CGRect rect;  
    rect.origin = CGPointZero;  
    rect.size   = size;  
    UIImage *remImage = [UIImage imageWithCIImage:ciImage];  
    [remImage drawInRect:rect];  
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext();  
    remImage = nil;  
    ciImage = nil;  
    //
    return result;  
}

person tagyro    schedule 18.01.2013    source источник
comment
Вы упомянули, что вам нужен CGImage для обрезки. Как сказал Джорис Клюиверс, вы можете сделать обрезку без CGImage, используя фильтр CICrop на CIImage. Есть ли что-нибудь еще, для чего вам нужен CGImage? Если да, то?   -  person Peter Hosey    schedule 18.01.2013
comment
Кроме того, что касается утечки памяти, вы пытались использовать шаблон Instruments's Leaks? Между инструментом Leaks и инструментом Heapshot инструмента Allocations вы должны быть в состоянии определить, где в вашем приложении происходит утечка или накопление памяти.   -  person Peter Hosey    schedule 18.01.2013
comment
@PeterHosey Я это сделал и обнаружил, что по какой-то причине у меня есть более 200 живых экземпляров CIImage и более 100 экземпляров CGImage, все они получены с помощью этого метода. я просто не вижу где   -  person tagyro    schedule 18.01.2013


Ответы (3)


См. документацию CIContext для createCGImage:fromRect:

CGImageRef img = [myContext createCGImage:ciImage fromRect:[ciImage extent]];

Из ответа на аналогичный вопрос: https://stackoverflow.com/a/10472842/474896

Кроме того, поскольку у вас есть CIImage для начала, вы можете использовать CIFilter, чтобы обрезать изображение.

person Joris Kluivers    schedule 18.01.2013
comment
Мог бы и должен: Core Image чрезвычайно ленив, в том смысле, что createCGImage:fromRect: (или любой другой метод, требующий готовых пикселей) — это точка, в которой фактически выполняется вся работа; до этого фактическая фильтрация не производилась. Обрезка с помощью фильтра Core Image на самом деле сэкономит довольно много работы (пропорционально тому, сколько вы обрезаете), поскольку в этом случае вы не будете запрашивать обрезанные пиксели, поэтому они вообще не будут отображаться. (Конечно, другим способом было бы передать прямоугольник обрезки для fromRect:, что будет иметь тот же эффект.) - person Peter Hosey; 18.01.2013
comment
@Joris Kluivers спасибо за ответ, но я получаю тот же результат: CIContext *context = [CIContext new]; CGImageRef ref = [контекст createCGImage:ciImage fromRect:[экстент ciImage]]; tempImage = [UIImage imageWithCGImage:ref]; CGImageRelease (ссылка); NSLog(@tempImage: %f %f,tempImage.size.width,tempImage.size.height); выходы: tempImage: 0.000000 0.000000 - person tagyro; 18.01.2013
comment
@PeterHosey Вы правы, но, к сожалению, у меня нет информации об обрезке, когда я делаю преобразование, и мне нужно сделать преобразование раньше, потому что я использую CGImage. Спасибо - person tagyro; 18.01.2013
comment
@AndreiStoleru: вы можете попробовать использовать contextWithOptions: вместо new для создания контекста. Кроме того, что вы получите в своем журнале, если запишете значение [ciImage extent]? - person Peter Hosey; 18.01.2013
comment
@PeterHosey NSLog(@extent: %f,ciImage.extent.size.width); DEBUG -[CamViewController captureOutput:didOutputSampleBuffer:fromConnection:]:180 - экстент: 1280.000000 Также пробовал с contextWithOptions:, но тот же результат. - person tagyro; 18.01.2013
comment
Вот как вы создаете свой контекст для получения CGImage: CIContext *myContext = [CIContext contextWithOptions:nil]; CGImageRef imgRef = [myContext createCGImage:ciImage fromRect:[экстент ciImage]]; UIImage *imagefromCGImage = [UIImage imageWithCGImage:imgRef]; CGImageRelease(imgRef); - person Alex Zavatone; 04.06.2014
comment
Лучше НЕ делать это преобразование в основном потоке, это стоит много времени. - person Itachi; 08.12.2016

Swift 3, Swift 4 и Swift 5

Вот хорошая маленькая функция для преобразования CIImage в CGImage в Swift.

func convertCIImageToCGImage(inputImage: CIImage) -> CGImage? {
    let context = CIContext(options: nil)
    if let cgImage = context.createCGImage(inputImage, from: inputImage.extent) {
        return cgImage
    }
    return nil
}
person skymook    schedule 22.08.2017

После некоторого поиска в Google я нашел этот метод, который преобразует CMSampleBufferRef в CGImage:

+ (CGImageRef)imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer // Create a CGImageRef from sample buffer data
{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer,0);        // Lock the image buffer

    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);   // Get information of the image
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    CGImageRef newImage = CGBitmapContextCreateImage(newContext);
    CGContextRelease(newContext);

    CGColorSpaceRelease(colorSpace);
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
    /* CVBufferRelease(imageBuffer); */  // do not call this!

    return newImage;
}

(но я закрыл вкладку, так что не знаю, откуда я это взял)

person tagyro    schedule 18.01.2013
comment
Это вообще не связано с CIImage. Итак, вы действительно намеревались создать CGImage из CMSampleBuffer с самого начала, а CIImage был просто средством, которое вы имели в виду для этого? - person Peter Hosey; 18.01.2013
comment
@PeterHosey Как вы, вероятно, могли бы сделать вывод, я получаю SampleBuffer от AVCaptureOutput и использую CIImage для обнаружения лиц. Конечная цель состоит в том, чтобы обрезать только лицо из захваченного изображения, и, поскольку я слишком глуп, чтобы понять CIImage и CGImage, я искал другое решение: CMSampleBuffer ps. Я принял ответ Джориса, потому что это правильный ответ на мой вопрос. - person tagyro; 18.01.2013
comment
А, распознавание лиц. Это законно. Вы уже смотрели на AVCaptureMetadataOutput и AVMetadataFaceObject? - person Peter Hosey; 18.01.2013
comment
@PeterHosey Спасибо за предложение, кажется, это быстрее, чем CIDetector;) - person tagyro; 19.01.2013