C#数字图像处理时注意图像的未用区域
来源:互联网 发布:爬虫软件是什么 编辑:程序博客网 时间:2024/05/21 17:36
图1. 被锁定图像像素数组基本布局
如图1所示,数组的宽度并不一定等于图像像素数组的宽度,还有一部分未用区域。这是为了提高效率,系统要确定每行的字节数必须为4的倍数。例如一幅24位、宽为17个像素的图像,它需要每行占有的空间为51(3 * 17)个字节,但51不是4的倍数,因此还需要扩充1个字节,从而使每行的字节数扩展为52(4 * 13,即Stride=52),这样就满足了每行字节数是4的倍数的条件。需要扩展多少个字节不仅是由图像的宽度决定,而且还由图像像素的格式决定。
如果处理的是任意宽度的图像,那么在进行下一行扫描的时候,需要把不含图像数据、仅起对齐作用的扩展字节去掉。此时对图像像素数组的遍历的形式如下:
(1).灰度图像:
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat);IntPtr ptr = bmpData.Scan0;// 首地址int bytes = bmpData.Stride * bmpData.Height;// 像素个数,包括未用空间byte[] grayValues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);for (int i = 0; i < bmpData.Height; i++){ // 仅处理每行中为图像像素的数据,舍弃未用空间 for (int j = 0; j < bmpData.Width; j++) { // use of grayValues[i * bmpData.Stride + j]; }}System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);bitmap.UnlockBits(bmpData);
或者:
// 获取图像参数int stride = bmpData.Stride; // 扫描线的宽度int offset = stride - width; // 显示宽度与扫描线宽度的间隙IntPtr iptr = bmpData.Scan0; // 获取bmpData的内存起始位置int scanBytes = stride * height; // 用stride宽度,表示这是内存区域的大小// 位置指针,指向源数组int posScan = 0;byte[] grayValues = new byte[scanBytes]; // <SPAN style="FONT-FAMILY: Arial">为目标数组分配内存</SPAN>for (int x = 0; x < height; x++){ // 下面的循环节是模拟行扫描 for (int y = 0; y < width; y++) { // grayValues[posScan++] } posScan += offset; // 行扫描结束,跳过未用空间字节}
(2).24位RGB图像:
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat);IntPtr ptr = bmpData.Scan0;// 首地址int bytes = bmpData.Stride * bmpData.Height;// 像素个数,包括未用空间byte[] rgbValues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr, rbgValues, 0, bytes);for (int i = 0; i < bmpData.Height; i++){ // 仅处理每行中为图像像素的数据,舍弃未用空间 for (int j = 0; j < bmpData.Width * 3; j += 3) { // R: rgbValues[i * bmpData.Stride + j + 2] // G: rgbValues[i * bmpData.Stride + j + 1] // B: rgbValues[i * bmpData.Stride + j] }}System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);bitmap.UnlockBits(bmpData);
以上代码将图像的整个像素数组都复制到数组grayValue或者rgbValue中,包括像素和仅用于对齐的未用空间,然后再在数组grayValue或者rgbValue中只对像素数据进行处理,跳过每一行的未用空间(跳过末尾几列)。
以下实验中,对任意尺度(每行字节数不是4字节的整数倍)的图像进行灰度直方图绘制,如果不考虑未用空间的话会导致错误结果(本实验中错误程度较小)。
图2.未考虑图像中未用空间的错误结果
用Matlab进行灰度直方图计算会发现真实结果中最大灰度的像素个数不是52811,而是53195。
f = imread('GrayTest.bmp');h = imhist(f)
图3.Matlab计算出的最大频率灰度像素个数
错误的原因是,因为图像的字节宽度不是4字节的整数倍,图像的像素数组包括了未用空间(每一行中都包括了未用空间)程序只从规模为bmpData.Stride * bmpData.Height字节的像素数组中复制了curBitmap.Width * curBitmap.Height规模的字节(灰度像素,1字节),这些字节中既包含了像素也包含了未用空间,如图4所示:
图4.出错时对像素数组复制的字节
最后在代码中考虑未用空间能得到正确结果:
图5.正确结果
- C#数字图像处理时注意图像的未用区域
- C#数字图像处理时注意图像的未用区域
- C#数字图像处理时注意图像的未用区域
- 冈萨雷斯数字图像处理学习7:图像分割 基于区域的分割分水岭
- 数字图像处理的区域生长算法
- 数字图像处理----区域生长
- 数字图像处理,图像的伪彩色处理
- 数字图像处理—图像分割—串行区域(区域生长)(分裂合并)
- 【数字图像处理】图像的gamma校正
- 【数字图像处理】图像的简单几何变换
- 数字图像处理标准图像Lena的故事
- 数字图像处理标准图像Lena的故事
- 数字图像处理标准图像Lena的故事
- 数字图像处理对图像的放缩
- 【数字图像处理一】BMP图像的读取
- 数字图像处理-图像的边缘检测
- 数字图像处理-图像的平滑和锐化。
- python数字图像处理:图像的绘制
- MyISAM InnoDB 区别
- maven+spring+cxf编写web service (2)
- SQL Server,MySQL,Oracle,PostgreSQL中常用函数用法(1)——日期操作
- Android中 AsyncTask的使用
- PHP-FPM启动脚本/etc/init.d/php-fpm
- C#数字图像处理时注意图像的未用区域
- linux sda adb
- 游戏中移动讨论
- WCDMA PPP test
- 浅学设计模式之单例<singleton>模式 .
- 教你如何计算腰围~~
- 每日必做1月13日更新
- DataTable某一列的最大值
- FAR FRR EER