画像処理に使えるUIImageのTips10個

このエントリーを含むはてなブックマークはてなブックマーク - 画像処理に使えるUIImageのTips10個

 
 
 
(1) 画像をUIImageに読み込む

指定したファイルから画像を読み込み、UIImageに格納するためにはUIImageのクラスメソッドであるimageNameメソッドを使います。このメソッドはinitWithContentsOfFileよりも高速です。

//画像を読み込む
UIImage *image = [UIImage imageNamed:@"test.jpg"];

 
 
 
 
(2) 画像をファイルパスから読み込む

ファイルパスを指定して画像を読み込むためには、NSBundleクラスを用いてパスを作成し、そのパスをinitWithContentsOfFileの引数にしてわたします。ただし、initWithContentsOfFileで作成したUIImageの描画は非常に遅いので注意。

NSString *filePath 
= [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
	
UIImage *img
= [[UIImage alloc] initWithContentsOfFile:filePath];

 
[参考]

  • UIImage#imageNamed:は読み込みも描画もUIImage#imageWithContentsOfFile:やそれ以外のメソッドより5~6倍速い
  • Sun Limited Mt. UIImage#ImageWithContentsOfData: などは描画が激遅
  •  
     
      
     
     
    (3) UIImageをカメラロールに保存する

    作成したUIImageをカメラロールに保存するためにはUIImageWriteToSavedPhotosAlbum関数を利用します。引数には保存画像、デリゲート、完了を知らせるコールバック関数を指定します。

    このメソッドで指定した画像はJPG形式に変換され保存されるため、画質の劣化は避けられません。画質は93%の圧縮画像になるようです。今のところ、このメソッドがカメラロールに保存する唯一の方法です。

    - (void) finishExport:(UIImage *)image
    didFinishSavingWithError:(NSError *)error
    contextInfo:(void *)contextInfo
    {
      NSLog(@"save image successfully"); 
    }
    
    UIImageWriteToSavedPhotosAlbum(image, self, @selector(finishExport:didFinishSavingWithError:contextInfo:),
    nil);
    
    

    [参考]

  • iPhoneアプリ開発ブログ UIViewのスクリーンショットの画質を良くしたい
  • Unnamed Red UIImage をカメラロールに保存する
  •  
     
     
     
    (4) UIImageを拡大縮小する

    第一引数に元画像を、第二引数にリサイズ後のサイズを渡すことで、画像のアスペクトを保持したままリサイズを行い、その画像を返してくれるメソッド。アスペクトを保持するため、始めの4行で拡大率を固定している。

    リサイズを行うため、まずはUIGraphicsBeginImageContextメソッドで指定サイズのグラフィックスコンテキストを取得し、そこに画像を描画する。グラフィックスコンテキストに描画された画像を再びUIGraphicsGetImageFromCurrentImageContextメソッドで取得してUIImage型に再合成している。
     

    - (UIImage*)resizedImage:(UIImage *)img size:(CGSize)size
    {
    	CGFloat widthRatio  = size.width  / img.size.width;
    	CGFloat heightRatio = size.height / img.size.height;
    	CGFloat ratio = (widthRatio < heightRatio) ? widthRatio : heightRatio;
    	CGSize resizedSize = CGSizeMake(img.size.width*ratio, img.size.height*ratio);
    	
    	UIGraphicsBeginImageContext(resizedSize);
    	
    	&#91;img drawInRect:CGRectMake(0, 0, resizedSize.width, resizedSize.height)&#93;;	
    	UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext();
    	
    	UIGraphicsEndImageContext();
    	
    	return resizedImage;
    }
    &#91;/cpp&#93;
    
    &#91;参考&#93;
    <li><a href="http://i.studio23c.com/?p=612">iPhoneメモ UIImageの縮小 〜比率を保持して/カテゴリでメソッドを追加編〜</a></li>
     
     
     
     
    <span style="font-size:large;color:RoyalBlue"><strong>(5) UIImageを回転させる</strong></span>
    
    <a href="http://iphone.moo.jp/app/wp-content/uploads/rotateuiimage.jpg"><img src="http://iphone.moo.jp/app/wp-content/uploads/rotateuiimage.jpg" alt="" title="rotateuiimage" width="382" height="102" class="alignnone size-full wp-image-803" /></a>
    
    第一引数に元画像を、第二引数に回転角度を渡すことで、回転した画像を返してくれるメソッド。回転角度には90, 180, 270度のみ指定可能。
    
    こちらも画像の拡大縮小と同様、グラフィックスコンテキストに一度描画を行い、そのグラフィックスコンテキストに対して回転処理をほどこした後、UIImage型に再合成しています。
     
    [cpp]
    - (UIImage *) rotateImage:(UIImage *)img angle:(int)angle
    {
    	CGImageRef imgRef = [img CGImage];
    	CGContextRef context;
    	
        switch (angle) {  
    		case 90:  
    			UIGraphicsBeginImageContext(CGSizeMake(img.size.height, img.size.width));					
    			context = UIGraphicsGetCurrentContext();  			
    			CGContextTranslateCTM(context, img.size.height, img.size.width);  
    			CGContextScaleCTM(context, 1.0, -1.0);  
    			CGContextRotateCTM(context, M_PI/2.0);  
    			break; 
    		case 180:
    			UIGraphicsBeginImageContext(CGSizeMake(img.size.width, img.size.height));					
    			context = UIGraphicsGetCurrentContext();  
    			CGContextTranslateCTM(context, img.size.width, 0);  
    			CGContextScaleCTM(context, 1.0, -1.0);  
    			CGContextRotateCTM(context, -M_PI);  
    			break;  
    		case 270:  
    			UIGraphicsBeginImageContext(CGSizeMake(img.size.height, img.size.width));					
    			context = UIGraphicsGetCurrentContext();  
    			CGContextScaleCTM(context, 1.0, -1.0);  
    			CGContextRotateCTM(context, -M_PI/2.0);  
    			break;  
    		default:
    			NSLog(@"you can select an angle of 90, 180, 270");
    			return nil;
        }  
    	
        CGContextDrawImage(context, CGRectMake(0, 0, img.size.width, img.size.height), imgRef);  
        UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();  
        
        UIGraphicsEndImageContext();  
    	return ret;
    }
    
    

    [参考]

  • 琴線探査 iPhoneで画像を回転させて保存するには?
  •  
     
     
     
    (7) UIImageのピクセルにアクセスする

    UIImageに対して独自の画像処理を行う場合には、UIImageのピクセルにアクセスする必要があります。下の例はUIImageのピクセルにアクセスして、画像をグレースケール化しています。

    具体的にはUIImageからCGImage型を経てピクセル配列へと分解し、ピクセルに対して画像処理を行ったあと、分解とは逆の操作を行うことでUIImageまで再合成しています。
     

    	// pixel値の抽出
    	UIImage *img = [UIImage imageNamed:@"test.jpg"];	
    	CGImageRef cgImage = [img CGImage];
    	size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
    	CGDataProviderRef dataProvider = CGImageGetDataProvider(cgImage);
    	CFDataRef data = CGDataProviderCopyData(dataProvider);
    	UInt8* pixels = (UInt8*)CFDataGetBytePtr(data);
    	
    	// 画像処理(グレースケール化)
    	for (int y = 0 ; y < img.size.height; y++){
    		for (int x = 0; x < img.size.width; x++){
    			UInt8* buf = pixels + y * bytesPerRow + x * 4;		
    			UInt8 r, g, b;
    			r = *(buf + 0);
    			g = *(buf + 1);
    			b = *(buf + 2);
    			UInt8 gray = (77 * r + 28 * g + 151 * b)>>8;
    			*(buf + 0) = gray;
    			*(buf + 1) = gray;
    			*(buf + 2) = gray;
    		}
    	}
    	
    	// pixel値からUIImageの再合成
    	CFDataRef resultData = CFDataCreate(NULL, pixels, CFDataGetLength(data));
    	CGDataProviderRef resultDataProvider = CGDataProviderCreateWithCFData(resultData);
    	CGImageRef resultCgImage = CGImageCreate(
    						   CGImageGetWidth(cgImage), CGImageGetHeight(cgImage), 
    						   CGImageGetBitsPerComponent(cgImage), CGImageGetBitsPerPixel(cgImage), bytesPerRow, 
    						   CGImageGetColorSpace(cgImage), CGImageGetBitmapInfo(cgImage), resultDataProvider, 
    						   NULL, CGImageGetShouldInterpolate(cgImage), CGImageGetRenderingIntent(cgImage));
    	UIImage* result = [[[UIImage alloc] initWithCGImage:resultCgImage] autorelease];
    	
    	// 後処理
    	CGImageRelease(resultCgImage);
    	CFRelease(resultDataProvider);
    	CFRelease(resultData);
    	CFRelease(data);
    

    [参考]

  • sonson@Picture&Software UIImageでピクセルを扱う
  • iPhoneアプリで稼げるのか カメラアプリ系の画像処理をする
  •  
     
     
     
    (8) UIImageでアニメーションを作る

    animation

    UIImageの配列を作成し、それをImageVIewクラスに登録することでアニメーション表示することができます。animationDurationでアニメの実行時間を指定できます。

        NSArray *imageArray = [[NSArray alloc] initWithObjects:
    						 [UIImage imageNamed:@"test.jpg"],
    						 [UIImage imageNamed:@"test2.jpg"],
    						 [UIImage imageNamed:@"test3.jpg"],	
    						 [UIImage imageNamed:@"test4.jpg"],	
    						 [UIImage imageNamed:@"test5.jpg"],	 
    						 nil];
    
        imageView.animationImages = imageArray;
        imageView.animationDuration = 1.0f;
      
        [imageView startAnimating];
    

     

    [参考]

  • UIImageで手っ取り早くアニメーションを作ってしまう方法
  •  
      
     
     
    (9) マスク処理で角丸画像を作成する

    UIImageの画像にマスクをかけるにはCGImageCreateWithMaskメソッドを使用します。引数として与えるマスク画像はCGImageMaskCreateメソッドを使って作成しています。この際、角丸のマスク画像を使用することで、元画像を角丸画像に変換することが出来ます。

    - (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
     
    	CGImageRef maskRef = maskImage.CGImage; 
     
    	CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
    		CGImageGetHeight(maskRef),
    		CGImageGetBitsPerComponent(maskRef),
    		CGImageGetBitsPerPixel(maskRef),
    		CGImageGetBytesPerRow(maskRef),
    		CGImageGetDataProvider(maskRef), NULL, false);
     
    	CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
    	return [UIImage imageWithCGImage:masked];
     
    }
    

      

    [参考]

  • [iOS developer:tips]; How to Mask an Image
  •  
     
     
     
    (10) IplImageとUIImageの相互変換

    opencvuiimage

    ここまでは、UIImageに対して直接処理を行って来ましたが、本格的な画像処理を行う場合にはOpenCVを使ったほうが簡単に行なえます。しかし、iPhoneプログラミングではcvLoadImge関数を使って画像を読み込むことは出来ないので、

    • imageNamedメソッドで画像読み込み
    • UIImage から IplImage型に変換
    • OpenCVで画像処理
    • IplImage から UIImage型に変換して表示

    という流れになります。

    ここでは、UIImageとIplImageの相互変換のプログラムを紹介します。まずはUIImageをIplImageに変換するメソッド。

    - (UIImage *)resizedImageArbitrarily:(UIImage *)img size:(CGSize)size
    IplImage* createIplImageFromUIImage(UIImage* image)
    {
    	// CGImageをUIImageから取得
    	CGImageRef imageRef = image.CGImage;
    	
    	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    	// 一時的なIplImageを作成
    	IplImage *iplimage = cvCreateImage(cvSize(image.size.width,image.size.height), IPL_DEPTH_8U, 4 );
    	
    	// CGContextを一時的なIplImageから作成
    	CGContextRef contextRef = CGBitmapContextCreate(
    													iplimage->imageData, iplimage->width, iplimage->height,
    													iplimage->depth, iplimage->widthStep,
    													colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault);
    	// CGImageをCGContextに描画
    	CGContextDrawImage(
    					   contextRef,
    					   CGRectMake(0, 0, image.size.width, image.size.height),
    					   imageRef);
    	
    	CGContextRelease(contextRef);
    	CGColorSpaceRelease(colorSpace);
    	
    	// 最終的なIplImageを作成
    	IplImage *ret = cvCreateImage(cvGetSize(iplimage), IPL_DEPTH_8U, 3);
    	cvCvtColor(iplimage, ret, CV_RGBA2BGR);
    	cvReleaseImage(&iplimage);
    	
    	return ret;
    }
    

    こちらは逆にOpenCVのIplImageからUIImageに変換するメソッド。

    UIImage* createUIImageFromIplImage(IplImage *image)
    {
    	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    	// CGImageのためのバッファを確保
    	NSData *data =
        [NSData dataWithBytes:image->imageData length:image->imageSize];
    	CGDataProviderRef provider =
        CGDataProviderCreateWithCFData((CFDataRef)data);
    	// IplImageのデータからCGImageを作成
    	CGImageRef imageRef = CGImageCreate(
    										image->width, image->height,
    										image->depth, image->depth * image->nChannels, image->widthStep,
    										colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault,
    										provider, NULL, false, kCGRenderingIntentDefault
    										);
    	// UIImageをCGImageから取得
    	UIImage *ret = [UIImage imageWithCGImage:imageRef];
    	CGImageRelease(imageRef);
    	CGDataProviderRelease(provider);
    	CGColorSpaceRelease(colorSpace);
    	return ret;
    }
    

    [参考]

  • yoshimasa niwa iPhoneでOpenCVを使う方法
  •  

    3 Responses to “画像処理に使えるUIImageのTips10個”

    1. [...] This post was mentioned on Twitter by dandelion. dandelion said: RT @apphokuson: ブログ更新:画像処理に使えるUIImageのTips10個 http://t.co/JQvFnqG [...]

    2. [...] iPhoneに関する、はてなブックマーク新着情報です。 画像処理に使えるUIImageのTips10個 [...]

    3. public relations job より:

      public relations job…

      [...]画像処理に使えるUIImageのTips10個[...]…

    Leave a Reply

    You must be logged in to post a comment.