Image Stride(内存图像行跨度)

 

Image Stride(内存图像行跨度)

When a video image is stored in memory, the memory buffer might contain extra padding bytes after each row of pixels. The padding bytes affect how the image is store in memory, but do not affect how the image is displayed.

当视频图像存储在内存时,图像的每一行末尾也许包含一些扩展的内容,这些扩展的内容只影响图像如何存储在内存中,但是不影响图像如何显示出来;

The stride is the number of bytes from one row of pixels in memory to the next row of pixels in memory. Stride is also called pitch. If padding bytes are present, the stride is wider than the width of the image, as shown in the following illustration.

Stride 就是这些扩展内容的名称,Stride 也被称作 Pitch,如果图像的每一行像素末尾拥有扩展内容,Stride 的值一定大于图像的宽度值,就像下图所示:

Two buffers that contain video frames with equal dimensions can have two different strides. If you process a video image, you must take into the stride into account.

两个缓冲区包含同样大小(宽度和高度)的视频帧,却不一定拥有同样的 Stride 值,如果你处理一个视频帧,你必须在计算的时候把 Stride 考虑进去;

In addition, there are two ways that an image can be arranged in memory. In a top-down image, the top row of pixels in the image appears first in memory. In a bottom-up image, the last row of pixels appears first in memory. The following illustration shows the difference between a top-down image and a bottom-up image.

另外,一张图像在内存中有两种不同的存储序列(arranged),对于一个从上而下存储(Top-Down) 的图像,最顶行的像素保存在内存中最开头的部分,对于一张从下而上存储(Bottom-Up)的图像,最后一行的像素保存在内存中最开头的部分,下面图示展示了这两种情况:

A bottom-up image has a negative stride, because stride is defined as the number of bytes need to move down a row of pixels, relative to the displayed image. YUV images should always be top-down, and any image that is contained in a Direct3D surface must be top-down. RGB images in system memory are usually bottom-up. 

一张从下而上的图像拥有一个负的 Stride 值,因为 Stride 被定义为[从一行像素移动到下一行像素时需要跨过多少个像素],仅相对于被显示出来的图像而言;而 YUV 图像永远都是从上而下表示的,以及任何包含在 Direct3D Surface 中的图像必须是从上而下,RGB 图像保存在系统内存时通常是从下而上;

Video transforms in particular need to handle buffers with mismatched strides, because the input buffer might not match the output buffer. For example, suppose that you want to convert a source image and write the result to a destination image. Assume that both images have the same width and height, but might not have the same pixel format or the same image stride.

尤其是视频变换,特别需要处理不同 Stride 值的图像,因为输入缓冲也许与输出缓冲不匹配,举个例子,假设你想要将源图像转换并且将结果写入到目标图像,假设两个图像拥有相同的宽度和高度,但是其像素格式与 Stride 值也许不同;

The following example code shows a generalized approach for writing this kind of function. This is not a complete working example, because it abstracts many of the specific details.

下面代码演示了一种通用方法来编写这种功能,这段代码并不完整,因为这只是一个抽象的算法,没有完全考虑到真实需求中的所有细节;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

void ProcessVideoImage(

    BYTE*       pDestScanLine0,    

    LONG        lDestStride,       

    const BYTE* pSrcScanLine0,     

    LONG        lSrcStride,        

    DWORD       dwWidthInPixels,    

    DWORD       dwHeightInPixels

    )

{

    for (DWORD y = 0; y < dwHeightInPixels; y++)

    {

        SOURCE_PIXEL_TYPE *pSrcPixel = (SOURCE_PIXEL_TYPE*)pDestScanLine0;

        DEST_PIXEL_TYPE *pDestPixel = (DEST_PIXEL_TYPE*)pSrcScanLine0;

 

        for (DWORD x = 0; x < dwWidthInPixels; x +=2)

        {

            pDestPixel[x] = TransformPixelValue(pSrcPixel[x]);

        }

        pDestScanLine0 += lDestStride;

        pSrcScanLine0 += lSrcStride;

    }

}

This function takes six parameters:

  • A pointer to the start of scan line 0 in the destination image.

  • The stride of the destination image.

  • A pointer to the start of scan line 0 in the source image.

  • The stride of the source image.

  • The width of the image in pixels.

  • The height of the image in pixels.

这个函数需要六个参数:

  1. 目标图像的起始扫描行的内存指针

  2. 目标图像的 Stride 值

  3. 源图像的起始扫描行的内存指针

  4. 源图像的 Stride 值

  5. 图像的宽度值(以像素为单位)

  6. 图像的高度值(以像素为单位)

The general idea is to process one row at a time, iterating over each pixel in the row. Assume that SOURCE_PIXEL_TYPE and DEST_PIXEL_TYPE are structures representing the pixel layout for the source and destination images, respectively. (For example, 32-bit RGB uses the RGBQUAD structure. Not every pixel format has a pre-defined structure.) Casting the array pointer to the structure type enables you to access the RGB or YUV components of each pixel. At the start of each row, the function stores a pointer to the row. At the end of the row, it increments the pointer by the width of the image stride, which advances the pointer to the next row.

这里的要点是如何一次处理一行像素,遍历一行里面的每一个像素,假设源像素类型与目标像素类型各自在像素的层面上已经结构化来表示一个源图像与目标图像的像素,(举个例子,32 位 RGB 像素使用 RGBQUAD 结构体,并不是每一种像素类型都有预定义结构体的)强制转换数组指针到这样的结构体指针,可以方便你直接读写每一个像素的 RGB 或者 YUV 值,在每一行的开头,这个函数保存了一个指向这行像素的指针,函数的最后一行,通过图像的 Stride 值直接将指针跳转到图像的下一行像素的起始点;

This example calls a hypothetical function named TransformPixelValue for each pixel. This could be any function that calculates a target pixel from a source pixel. Of course, the exact details will depend on the particular task. For example, if you have a planar YUV format, you must access the chroma planes independently from the luma plane; with interlaced video, you might need to process the fields separately; and so forth.

To give a more concrete example, the following code converts a 32-bit RGB image into an AYUV image. The RGB pixels are accessed using an RGBQUAD structure, and the AYUV pixels are accessed using aDXVA2_AYUVSample8 Structure structure.

<think>好的,我现在需要解决如何将VisionPro图像转换为Halcon支持的图像格式的问题。首先,我需要了解两者的图像数据结构差异。根据引用[2],不同相机的图像数据包结构可能不同,第三方视觉库如Halcon和VisionPro需要特定的图像格式,如果使用相机自己的SDK采图,可能需要转换。 VisionPro通常使用CogImage8Grey或CogImage24PlanarColor等图像类,而Halcon使用HImage对象。转换的关键在于获取像素数据的指针,并将其传递给Halcon的接口。我需要找到如何从VisionPro图像中提取像素数据,比如使用CogImage8Grey.GetPixelData方法获取像素数组。 然后,将这些数据传递给Halcon的HImage对象。Halcon的GenImage1或GenImage3函数可以用来创建图像,需要指定图像类型(如byte)、宽度、高度和像素数据指针。需要注意的是,VisionPro和Halcon在内存存储方式上是否有差异,例如对齐或通道顺序。例如,VisionPro的彩色图像可能是Planar格式(各通道分开存储),而Halcon可能需要Interleaved格式(RGBRGB排列),这时需要进转换。 另外,引用[3]提到VisionPro和Halcon各自有不同的开发工具,可能需要中间处理步骤。可能需要将VisionPro图像保存为通用格式(如BMP、TIFF),再用Halcon读取,但这种方法效率较低,不适合实时处理。因此,直接内存拷贝是更优的方法。 总结步骤:1. 从VisionPro图像获取像素数据指针;2. 确定图像参数(宽、高、通道、位深);3. 使用Halcon的API创建HImage对象;4. 处理可能的格式差异,如Planar转Interleaved。此外,还需要注意内存管理和异常处理,确保数据正确转换。</think>### VisionPro图像转换为Halcon图像的解决方案 #### 一、核心原理分析 VisionPro和Halcon的图像格式差异主要体现在内存布局和数据结构封装上。VisionPro使用$CogImage$系列对象(如$CogImage8Grey$),而Halcon使用$HImage$对象。转换过程需完成以下步骤: 1. 从VisionPro图像中提取原始像素数据指针 2. 解析图像参数(宽度、高度、像素类型、通道数) 3. 通过Halcon API构造$HImage$对象[^2] #### 二、具体实现方法 ##### 方法1:直接内存拷贝(推荐) ```csharp // 假设已获取VisionPro图像对象cogImage CogImage8Grey greyImage = (CogImage8Grey)cogImage; // 获取图像参数 int width = greyImage.Width; int height = greyImage.Height; IntPtr ptr = greyImage.GetPixelData(CogImageDataModeConstants.Read); // 创建Halcon图像 HOperatorSet.GenImage1(out HObject halconImage, "byte", width, height, ptr); ``` *注意事项:* - 彩色图像需处理通道顺序,VisionPro的$CogImage24PlanarColor$采用Planar格式,而Halcon默认需要Interleaved格式 - 内存对齐需满足Halcon要求(通常4字节对齐) ##### 方法2:通过中间文件转换 ```csharp // VisionPro保存为临时文件 greyImage.Save(@"temp.bmp", CogImageFileFormatConstants.BMP); // Halcon读取文件 HOperatorSet.ReadImage(out HObject halconImage, "temp.bmp"); ``` *适用场景:* 非实时处理场景,测试验证阶段 #### 三、关键问题处理 1. **彩色图像转换**:VisionPro的Planar格式需转换为Interleaved格式 $$ \text{Planar: RRR...GGG...BBB...} \rightarrow \text{Interleaved: RGBRGB...} $$ 转换算法复杂度:$O(n)$,需逐像素重组通道 2. **内存对齐处理**:当图像宽度不是4的倍数时,需添加填充字节 ```csharp int stride = ((width * 8 + 31) / 32) * 4; // 计算实际内存跨度 ``` 3. **像素深度匹配**:VisionPro的16位图像需转换为Halcon支持的$uint2$类型 #### 四、性能优化建议 1. 使用内存映射文件共享数据(适用于进程间通信) 2. 预分配Halcon图像缓冲区 3. 使用指针操作代替中间复制(需unsafe代码块) 4. 对彩色图像转换使用并处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值