2014年3月9日 星期日

Objective C-Resize Image

一陣子沒在這裡寫網誌喏,在實驗室用wordpress架惹另外一個網誌來寫Machine Learning(真自虐!看到一堆國內外不錯的文章,學到不少),話說wordpress用起來還是不太習慣,各種code syntax的plugin都過期QQ,不過可以嵌入github的code還不錯用,只是很慢!囧rz!

最近在公司寫有關影音的app常常遇到需要把webcam的image轉成小圖,samplebuffer轉cgimage的方法網路一堆,不過還是記錄一下做法,共五個步驟

  • 先用function CMSampleBufferGetImageBuffer來得到CVImageBufferRef
  • CVPixelBufferGet*之類的function來獲得buffer的資訊(影像的長寬還有image所在的記憶體位置)
  • create color space
  • 然後用CGBitmapContextCreate將image畫在context上
  • 最後用CGBitmapContextCreateImage這個function產生CGImage
// 1. Get Image Buffer
CVImageBufferRef imageBuffer= CMSampleBufferGetImageBuffer(sampleBuffer);
// Lock Image to avoid sync problem
CVPixelBufferLockBaseAddress(imageBuffer,0);

// 2. Get imageBuffer information
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
       
// 3. Create color space     
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// 4. Draw sampleBuffer on context
CGContextRef context = CGBitmapContextCreate(baseAddress,
                                                   width,
                                                  height,
                                                       8,
                                             bytesPerRow,
                                              colorSpace,
                  kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
            
if(!context){
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    return;
}
CGColorSpaceRelease(colorSpace);

// 5. Create CGImage from context      
cgImage = CGBitmapContextCreateImage(context);

上面的code google一下應該就有很多類似的code(話說去年要找到類似的code還真給他困難),當然現在要面對的是怎麼Resize image,UIImage或是NSImage都可以轉換成CGImage,所以這裡只記錄從CGImage怎麼Resize,主要有有四個步驟

  • 用malloc create一塊記憶體空間放context
  • 將步驟一的記憶體空間給context
  • 將原來的CGImage畫到context上面
  • 用CGBitmapContextCreateImage這function create CGImage
// Assume we already have a CGImage: originCGImage
            
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

size_t resizeWidth = 640;
size_t resizeHeight = height*640/width;

// 1. Create a memory to store Image
uint32_t *pixels = (uint32_t *)malloc(resizeWidth*resizeHeight*sizeof(uint32_t));

// 2. Create an empty context
CGContextRef context = CGBitmapContextCreate(pixels,
                                        resizeWidth,
                                       resizeHeight,
                                                  8,
                       resizeWidth*sizeof(uint32_t),
                                         colorSpace, 
                   kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);

// 3. Draw Image to context
CGContextDrawImage(context, CGRectMake(0, 0, resizeWidth, resizeHeight), originCGImage);

// 4. Create a new CGImage
CGImageRef newCGImage = CGBitmapContextCreateImage(context);

free(pixels);
CGImageRelease(originCGImage);
CGColorSpaceRelease(colorSpace);

基本resize的想法很簡單,假設已經有一個想要resize的CGImage,要做的事情就是1. 開記憶體->2. 把記憶體配給一張畫布(context)-> 3. 用CGContextDrawImage這個function把原本的CGImage畫到畫布上->4. 根據這個畫布來create新的CGImage,當然最後還要記得把該free掉或release掉的都清掉,不然會造成memory leak,這是在操作CG框架庫要注意的!原因就跟CG是C language所寫出來的有關,ARC memory manage在這個部分並沒有支援,所以拉!如果以前寫C有free的好習慣,使用CG framework的時候也記得要保持好習慣,不要被ARC這厲害的東西給寵壞惹!

沒有留言:

張貼留言