影像與資料陣列的轉換,是在對圖片做影像處理時會使用到的技巧,目的是將圖片轉換至人類可以理解的 RGBA 的資料結構陣列上,接著分別對每個像素點做影像處理,最後將處理的結果的轉換成影像並顯示,下面所要介紹的方法為通用方法,除了 iOS,您也可以使用在 MAC OS X Cocoa Application 上。
資料結構的宣告
首先要先了解影像處理所要使用的色域,在示範中主要是針對 32 位元的深度的影像,也就是包含 RGBA 資訊的影像(紅色、綠色、藍色和透明度,每個資訊共 8 位元, 0-255 的表示值),並使用 typedef struct 來定義其結構(rgba順序要正確)。
typedef struct RGBAData {
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} RGBAData;
將影像轉入資料陣列中
接下來要利用先前所製作的資料結構將影像轉存進來,方法是利用此結構製作一個與影像相同大小的一維陣列,並利用 CGContextRef 來做影像與資料結構的轉換。
//將圖片轉換成 CGImageRef 格式並取得大小
CGImageRef imageRef = [myImageView.image CGImage];
int width = CGImageGetWidth(imageRef);
int height = CGImageGetHeight(imageRef);
//資料結構的參數和色域
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//宣告一個與圖片大小相同的資料結構一維陣列
RGBAData *sourceData = malloc(height * width * bytesPerPixel);
//將圖片資訊寫入資料結構陣列中
CGContextRef context = CGBitmapContextCreate((unsigned char *)sourceData,
width,
height,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
現在我們已經成功將影像內的資訊轉存到 sourceData 中,而 sourceData 的形態為 RGBAData 結構的一維陣列。
對資料陣列做影像處理
將影像轉換成人類可以理解的資料結構之後,就可以對此結構做影像處理,下列程式碼是對影像做鏡射的簡單示範(將 sourceData 中的資訊做反序排列)。
//製作一個新的資料結構陣列來存放處理的結果
RGBAData *resultData = malloc(height * width * bytesPerPixel);
//影像做鏡射
for (int y=0; y!=height; y++)
for (int x=0; x!=width; x++) {
//取得陣列中像素的索引值
int pixelIndex = (width * y) + x ;
//製作鏡射
int length = width * height;
resultData[pixelIndex].r = sourceData[length-1 - pixelIndex].r;
resultData[pixelIndex].g = sourceData[length-1 - pixelIndex].g;
resultData[pixelIndex].b = sourceData[length-1 - pixelIndex].b;
resultData[pixelIndex].a = 255;
}
程式碼到此,我們已經成功將鏡射後的影像資訊放在 resultData 中,接下來就是將此結構內的資訊在轉換成電腦能解讀圖片資訊。
將資料陣列中的資訊轉成圖片
同樣透過 CGContextRef 來做資料結構與影像之間的轉換,在此必須注意,由於轉換是對等的,所以在製作 CGContextRef 時,參數大小和色域模型都必須和之前的 CGContextRef 保持一致。
//先轉成CGContextRef
context = CGBitmapContextCreate((unsigned char *)resultData,
width,
height,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
//再由CGContextRef轉成CGImageRef
CGImageRef cgImage=CGBitmapContextCreateImage(context);
//放入UIImageView
[myImageView setImage:[UIImage imageWithCGImage:cgImage]];
ps:補充一下大致的轉換過程,以便釐清每個步驟的程式碼。
UIImage -> CGImageRef -> CGContextRef -> RGBA Pixel Data -> Image Process -> New RGBA Pixel Data -> CGContextRef -> CGImageRef -> UIImage
沒有留言:
張貼留言