首页 > 编程知识 正文

图像处理在生活中应用,机器视觉中的图像处理

时间:2023-05-03 10:47:09 阅读:143843 作者:4502

每行有11个像素(Width=11 ),32位(每像素4字节)的图像的Stride=11 * 4=44。

还有字节对齐问题,如:

每行有11个像素(Width=11 ),24位(每像素3字节)的图像的stride=11*3)3=36。

为什么不是Stride=33? 因为4个字节就齐了。

根据以上内容,可以手动计算Stride的值:

1、Stride=每像素占用的字节数(即像素比特数/8) * Width;

2、如果Stride不是4的倍数,则stride=stride(4-stridemod4);

在下面的例子中,测试并验证了上述想法:

uses GdiPlus; procedure tform1. form paint (发送者: tobject; varBitmap: IGPBitmap; Rect: TGPRect; Graphics: IGPGraphics; Data: TGPBitmapData; n :整数; beginchdir(c:(gdiplusimg ) ); bitmap :=TGP bitmap.create (grapes.jpg ); rect.initialize (0,0,Bitmap.Width,Bitmap.Height ); DATA:=bitmap.lockbits(rect,[ImageLockModeRead],Bitmap.PixelFormat ); n :=getpixelformatsize (data.pixel format ) div 8 * Data.Width; n:=n(4-nmod4; showmessagefmt('%d,%d,%d ',[Data.Width,Data.Stride,n] ); { 187,564,564 } bitmap.unlock bits (data ); //bitmap :=TGP bitmap.create (bird.BMP ); rect.initialize (0,0,Bitmap.Width,Bitmap.Height ); DATA:=bitmap.lockbits(rect,[ImageLockModeRead],Bitmap.PixelFormat ); n :=getpixelformatsize (data.pixel format ) div 8 * Data.Width; ifnmod40thenn:=n(4-nmod4); showmessagefmt('%d,%d,%d ',[Data.Width,Data.Stride,n] ); { 110,112,112 } bitmap.unlock bits (data ); //bitmap :=TGP bitmap.create (apple.gif ); rect.initialize (0,0,Bitmap.Width,Bitmap.Height ); DATA:=bitmap.lockbits(rect,[ImageLockModeRead],Bitmap.PixelFormat ); n :=getpixelformatsize (data.pixel format ) div 8 * Data.Width; ifnmod40thenn:=n(4-nmod4); showmessagefmt('%d,%d,%d ',[Data.Width,Data.Stride,n] ); { 120,120,120 } bitmap.unlock bits (data ); //bitmap :=TGP bitmap.create (image file small.jpg ); rect.initialize (0,0,Bitmap.Width,Bitmap.Height ); DATA:=bitmap.lockbits(rect,[ImageLockModeRead],Bitmap.PixelFormat ); n :=getpixelformatsize (data.pixel format ) div 8 * Data.Width; ifnmod40thenn:=n(4-nmod4); showmessagefmt('%d,%d,%d ',[Data.Width,Data.Stride,n] ); { 320,960,960 } bitmap.unlock bits (data ); 结束; 图像处理中跨距(stride )使用C#的BitmapData

最近要开发平台,正在研究C#。 C#可以,但是处理图像时一像素一像素的操作像素一般不慢。 其实Delphi也是一样的,好在Delphi的Bitmap类提供了ScanLines,可以一行一行地看图,很高效。 支持C#

该也有类似的东东。经过一番搜索,终于发现了BitmapData类。

先看个例子,这是对一张位图的每个像素按FF取补,然后输出到一个新图(代码有点啰嗦,不过应该可以说明问题了)。

int h = m_Bmp.Height;int w = m_Bmp.Width;Bitmap bmpOut = new Bitmap(w, h, PixelFormat.Format24bppRgb);BitmapData dataIn = m_Bmp.LockBits(new Rectangle(0,0,w,h),ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb;BitmapData dataOut = bmpOut.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);unsafe{byte* pIn = (byte*)(dataIn.Scan0.ToPointer());byte * pOut = (byte*)(dataOut.Scan0.ToPointer());for (int y = 0; y < dataIn.Height; y++){for (int x = 0; x < dataIn.Width; x++){pOut[0] = (byte)(255 - pIn[0]);pOut[1] = (byte)(255 - pIn[1]);pOut[2] = (byte)(255 - pIn[2]);pIn += 3;pOut += 3;}pIn += dataIn.Stride - dataIn.Width * 3;pOut += dataOut.Stride - dataOut.Width * 3;}}bmpOut.UnlockBits(dataOut);m_Bmp.UnlockBits(dataIn);

貌似比Delphi复杂得多,难道我真的天生对指针过敏?还是Delphi的比较好理解,就是扫描每一行,然后对当前像素点的三个分量做处理,非常方便。而且C#代码中的Stride是个什么东东?

查找了不少资料,现在我是这么理解的:

假设有一张图片宽度为6,因为是Format24bppRgb格式(每像素3字节。在以下的讨论中,除非特别说明,否则Bitmap都被认为是24位RGB)的,显然,每一行需要6*3=18个字节存储。对于Bitmap就是如此。但对于BitmapData,虽然BitmapData.Width还是等于Bitmap.Width,但大概是出于显示性能的考虑,每行的实际的字节数将变成大于等于它的那个离它最近的4的整倍数,此时的实际字节数就是Stride。就此例而言,18不是4的整倍数,而比18大的离18最近的4的倍数是20,所以这个BitmapData.Stride = 20。显然,当宽度本身就是4的倍数时,BitmapData.Stride = Bitmap.Width * 3。

画个图可能更好理解。R、G、B 分别代表3个原色分量字节,BGR就表示一个像素。为了看起来方便我在每个像素之间插了个空格,实际上是没有的。X表示补足4的倍数而自动插入的字节。为了符合人类的阅读习惯我分行了,其实在计算机内存中应该看成连续的一大段。

Scan0||———Stride—————–||———Width————-| | 注:Width是图片(BGR作为一个单位)宽度BGR BGR BGR BGR BGR BGR XXBGR BGR BGR BGR BGR BGR XX...

现在应该很好理解了。首先用 BitmapData.Scan0找到第0个像素的第0个分量的地址。这个地址指向的是个byte类型,所以当时定义为byte* pIn。
行扫描时,在当前指针位置(不妨看成当前像素的第0个颜色分量)连续取出三个值(3个原色分量。注意,0 1 2代表的次序是B G R。在取指针指向的值时,貌似p[n]和p += n再取p[0]是等价的),然后下移3个位置(pIn += 3,看成指到下一个像素的第0个颜色分量)。做过Bitmap.Width次操作后,就到达了Bitmap.Width * 3的位置,应该要跳过图中标记为X的字节了(共有Stride - Width * 3个字节),代码中就是 pIn += dataIn.Stride - dataIn.Width * 3;

跳过以后指针就到达下行的第0个像素了。按照此算法,一共需要做Bitmap.Height次行扫描(代码就是 for (int y = 0; y < dataIn.Height; y++))。

另外,因为使用了unsafe,所以编译的时候需要设置“允许不安全的代码”。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。