首先声明,本系列笔记既“采菊东篱下”,又“悠然见南山”。是笔者在学习C#的图像处理的过程中借鉴、引申的笔录。欢迎访客指正。
(原文链接 C#图像处理之一 基本概念_bitmapdata stride-优快云博客)
概念要点:
1. 图像格式
为简单起见,笔者的学习是从 Bitmap.PixelFormat == PixelFormat.Format24bppRgb 开始的。因为这个图像格式采用的是24位色,每3个字节表示一个颜色,每字节分别对应R G B。
Bitmap 对象是对图像处理的一个非常方便的封装。如无特别说明,笔记中的所有图像处理,都为 Bitmap 且 Bitmap.PixelFormat=Format24bppRgb的格式。
2. 图像数据 - BitmapData
BitmapData是位图图像的属性封装,可以通过
BitmapData bmpdata = Bitmap.LockBits()来获得。
其相应的属性列表如下:
BitmapData.Height, 像素高度,或叫扫描行数
BitmapData.Width, 像素宽度,或叫一个扫描行中的像素数
BitmapData.Scan0, 像素数据的起始地址,当然也是位图数据中的第一行的开始。
BitmapData.Stride, 跨距宽度,或叫扫描宽度。MSDN的示意为: 跨距是单行像素(一个扫描行)的宽度,舍入为一个 4 字节的边界。如果跨距为正,则位图自顶向下。如果跨距为负,则位图颠倒。用程序员的语言表述,就是: Stride指一个扫描行占用的字节数。根据BMP格式的标准,Stride一定是4的倍数。比如一个 24x11 的图像,每行的像素信息就是 24*3 = 72, 正好是4的倍数,而一副 21x11的位图,每行像素信息为 21*3=63, 因为不足4的倍数,所以用1个字节来填充,这样每行像素信息为21*3+1=64字节,这一个字节在笔记中成为 offset, 所以 offset = BitmapData.Stride - BitmapData.Width * 3
3. 图像地址
因为图像处理比较复杂,比如对于一个width=100×height=100的图像来说,所有像素的遍历意味着要访问100×100×3个字节,所以在图像处理中,笔者尽量采用指针操作,以提高处理效率(感谢上帝,c#还允许我们进行指针操作)。
对于图像中的任意一个点,如 f(x,y),其中 x 表示行数,y表示列数。用地址指针表示,就为
byte* ptr = BitmapData.Scan0 + ( x * Stride ) + y * 3;
并且 RGB 可以通过 ptr[0], ptr[1], ptr[2] 来获得