@qidiandasheng
2018-08-04T07:05:37.000000Z
字数 4449
阅读 2940
技术
图像中像素点占得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来输出一个图片的像素数据,来验证看看上面所说的存储模型。
import sysimport tensorflow as tffrom PIL import Image, ImageFilterimport numpy as npdef 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 = 0while y<height:x = 0while x<width:print(test_input[y,x])x += 1y += 1
对应的RGB图片,我们转换模型改一下testImage=Image.open(argv).convert('RGB'),转换为array之后,就变成了一个rows*cols*channels的三维矩阵,输出读取如下所示:
[[[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 = 0while y<height:x = 0while 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 += 1y += 1
以下为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 = 0while y<height:x = 0while x<width:print(test_input[y,x])# print('R: ' + str(test_input[y,x,0]))x += 1y += 1
在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 databitmapData = (uint32_t *)malloc(bufferLength);if(!bitmapData) {NSLog(@"Error allocating memory for bitmap\n");CGColorSpaceRelease(colorSpace);return NULL;}//Create bitmap contextcontext = 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。
Converting UIImage to RGBA8 Bitmaps and Back
一张图片引发的深思
谈谈 iOS 中图片的解压缩