影象的深度和通道
影象的深度
影象中畫素點佔得bit位數,就是影象的深度,比如以下影象的深度。
二值影象:
影象的畫素點不是0 就是1 (影象不是黑色就是白色),影象畫素點佔的位數就是 1 位,影象的深度就是1,也稱作點陣圖。
灰度影象:
影象的畫素點位於0-255之間,(0:全黑,255代表:全白,在0-255之間插入了255個等級的灰度)。最大值255的二進位制表示為11111111,佔有8個bit位,即2^8=256,影象的深度是8。
影象的通道
通道,是數字影象中儲存不同型別資訊的灰度影象。一個影象最多可以有數十個通道,常用的RGB和Lab影象預設有三個通道,而CMYK影象則預設有四個通道。 一張RGB影象含有三個通道:紅(Red)、綠(Green)、藍(Blue)。 一張CMYK影象含有四個通道:青色(Cyan)、品紅(Magenta)、黃色、黑色。
所以想灰度圖就只有一個通道,佔有8個bit位,也就是8點陣圖。所以RGB影象佔有三個通道,3*8=24,所以RGB影象就是24點陣圖。
影象在記憶體中的儲存
影象畫素點的儲存就是對應的原圖從左到右,從上到下,依次排列,每個點的值就是就是畫素點的值,每個點的地址就是畫素畫素點的地址。
如第一幅圖就是灰度圖的儲存,只有單通道。在記憶體中的儲存即可用一個一維陣列來表示,根據順序從左到右,從上到下,依次按順序存入陣列。
圖二則為RGB影象的儲存模型,每一個畫素有3個通道,所以需要一個二維陣列來表示,順序也是從左到右,從上到下,如[[234,200,0],[234,0,0],[255,55,0],....]這樣,當然其中的數子,在記憶體中需要用對應的二進位制來表示。
python輸出影象資料
我們來用python來輸出一個圖片的畫素資料,來驗證看看上面所說的儲存模型。
import sys
import tensorflow as tf
from PIL import Image, ImageFilter
import numpy as np
def imageprepare(argv):
testImage=Image.open(argv).convert('L')
testImage = testImage.resize((6, 4))
test_input=np.array(testImage)
print(test_input)
def main(argv):
"""
Main function.
"""
imvalue = imageprepare(argv)
if __name__ == "__main__":
main(sys.argv[1])
複製程式碼
我這裡傳進去一張圖片,然後轉換成L
模型(L表示灰度圖),設定寬高位(6,4),輸出如下所示,這裡np.array把圖片資料轉換成了一個二維陣列,方便根據(x,y)來讀取:
[[254 255 254 97 255 248]
[246 255 15 180 255 255]
[252 227 227 246 44 252]
[244 254 229 151 243 248]]
複製程式碼
如我們之前所說根據從左到右,從上到下儲存的話,則可以方便的用以下方法來讀取:
width = testImage.size[0]
height = testImage.size[1]
y = 0
while y<height:
x = 0
while x<width:
print(test_input[y,x])
x += 1
y += 1
複製程式碼
對應的RGB圖片,我們轉換模型改一下testImage=Image.open(argv).convert('RGB')
,轉換為array之後,就變成了一個rowscolschannels的三維矩陣,輸出讀取如下所示:
[[[254 254 254]
[255 255 255]
[254 254 254]
[ 97 97 97]
[255 255 255]
[248 248 248]]
[[246 246 246]
[255 255 255]
[ 15 15 15]
[180 180 180]
[255 255 255]
[255 255 255]]
[[252 252 252]
[227 227 227]
[227 227 227]
[246 246 246]
[ 44 44 44]
[252 252 252]]
[[244 244 244]
[254 254 254]
[229 229 229]
[151 151 151]
[243 243 243]
[248 248 248]]]
複製程式碼
width = testImage.size[0]
height = testImage.size[1]
y = 0
while y<height:
x = 0
while x<width:
# 畫素的3通道值
print(test_input[y,x])
print('R: ' + str(test_input[y,x,0]))
print('G: ' + str(test_input[y,x,1]))
print('B: ' + str(test_input[y,x,2]))
x += 1
y += 1
複製程式碼
iOS仿python影象處理庫PIL
python程式碼
以下為python中PIL把圖片轉換為畫素資料陣列的程式碼,我們先把圖片轉化為RGBA格式,然後輸出對應位置的畫素資料。當然RGBA一個畫素有4個通道,所以我們可以依次輸出每個通道的值,如R通道:test_input[y,x,0]
。
def imageprepare(argv):
testImage=Image.open(argv).convert('RGBA')
testImage = testImage.resize((28, 28))
test_input=np.array(testImage)
print(test_input)
width = testImage.size[0]
height = testImage.size[1]
y = 0
while y<height:
x = 0
while x<width:
print(test_input[y,x])
# print('R: ' + str(test_input[y,x,0]))
x += 1
y += 1
複製程式碼
iOS程式碼
在iOS中圖片轉化為圖片資料格式相對於python和Android中來講相對麻煩一些,所以我這裡封裝了一個iOS圖片轉圖片資料的類。輸出的格式跟python中類似,但是python支援多種編碼格式,分別為1,L,P,RGB,RGBA,CMYK,YCbCr,I,F。這裡iOS開發中只支援RGBA,CMYK。
在iOS中我們會先根據圖片的編碼格式來生成一個CGContextRef(畫布),以下程式碼是對RGBA格式圖片處理生成的CGContextRef。
- (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image {
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
uint32_t *bitmapData;
size_t bitsPerPixel = 32;
size_t bitsPerComponent = 8;
size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
size_t bytesPerRow = width * bytesPerPixel;
size_t bufferLength = bytesPerRow * height;
colorSpace = CGColorSpaceCreateDeviceRGB();
if(!colorSpace) {
NSLog(@"Error allocating color space Gray\n");
return NULL;
}
// Allocate memory for image data
bitmapData = (uint32_t *)malloc(bufferLength);
if(!bitmapData) {
NSLog(@"Error allocating memory for bitmap\n");
CGColorSpaceRelease(colorSpace);
return NULL;
}
//Create bitmap context
context = CGBitmapContextCreate(bitmapData,
width,
height,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast);
if(!context) {
free(bitmapData);
NSLog(@"Bitmap context not created");
}
CGColorSpaceRelease(colorSpace);
return context;
}
複製程式碼
要理解以上程式碼,首先要知道什麼是畫素格式:
點陣圖其實就是一個畫素陣列,而畫素格式則是用來描述每個畫素的組成格式,它包括以下資訊:
Bits per component :一個畫素中每個獨立的顏色分量使用的 bit 數;
Bits per pixel : 一個畫素使用的總 bit 數;
Bytes per row : 點陣圖中的每一行使用的位元組數。有一點需要注意的是,對於點陣圖來說,畫素格式並不是隨意組合的,目前iOS、Mac OS X開發只支援以下有限的 17 種特定組合: 官方文件
原始碼
DSImageBitmaps這是我iOS原始碼的地址,其中包含了python的程式碼,我iOS裡面的圖片直接使用的是python裁剪過大小的圖片,然後能發現資料的資料是一樣的。
但是我用iOS裡面直接裁剪大小後的圖片就跟python處理過大小的圖片輸出的資料就不一樣了,說是python的image.resize用到了濾波器,具體是什麼我也不太清楚。反正就是iOS和python處理圖片大小內部的演算法有些許差異,但是你能發現每一個畫素上的資料差異不大,具體到一張圖顯示的話人眼是識別不出來的。
還有就算要注意iOS中處理的圖片大小問題,也就是iOS中畫素和image.size的關係:
test.png (畫素 20*20) test@2x.png(畫素40*40) test@3x.png(畫素 60*60)
UIImage *image = [UIImageimageNamed:@"test.png"];
image.size輸出大小為(20,20);
UIImage *image = [UIImage imageNamed:@"test@2x.png"];
image.size輸出大小為(20,20);
UIImage *image = [UIImage imageNamed:@"test@3x.png"];
image.size輸出大小為(20,20);
image.size輸出的大小會自動識別圖片是幾倍的,如果是3倍的輸出的結果就是畫素除以3,2倍的畫素除以2。
複製程式碼