RGB565和RGB555位图显示

 RGB565

  The RGB565 color format is the same as the RGB555 color format, except that 6 bits are used for the green value instead of 5. Therefore, all 16 bits are in use. The organization of the pixels in the image buffer is from left to right and bottom up.

  Memory Layout

  图1

 

  As illustrated above, the 5 least significant bits of the WORD correspond to the blue value, bits 5 - 10 correspond to the green value and bits 11 to 15 correspond to the red value. Please note that on the x86 architecture WORDs are stored in little-endian order, which means the LOW BYTE is saved first. This is important when accessing the image data with a byte pointer.

  How to read and write pixel data

  A video capture device, video format, FrameHandlerSink with a MemBufferCollection, which defines the image data color format must first have been setup. The following code fragments show step-by-step how to access and manipulate the pixel data of RGB555.

  First of all, we have to capture an image. Otherwise, the image buffer would be empty. To do so, we start live mode and call Grabber::snapImages.

  Accessing the buffer

  The following code retrieves a pointer to the image data. Please note, that getPtr() returns a BYTE pointer, which will be type-casted to a WORD pointer. This makes it much easier to access the pixel data since RGB565 is a 16 bit color format.

  WORD* pwImgData = (WORD*) pActiveBuf->getPtr();

  In this example, we want to output the first (upper left hand) pixel of the image and manipulate the first 3. As previously mentioned, the image data is stored bottom up. Therefore, pwImgData points to the first byte of the first pixel of the last line in the buffer. To get access to this first byte, the following calculation has to be performed:

  // Calculate the index of the upper left pixel

  // Images are stored upside down in the image buffer

  // * 1: a pixel is 2 byte, but since we have a WORD pointer (which is also 2 bytes)

  // we count in pixel not in bytes

  SIZE dim = pActiveBuf->getFrameType().dim;

  int iOffsUpperLeft = (dim.cy-1) * dim.cx * 1;

  At first, we retrieve the width and height of the image in terms of pixels. Then, the offset to the upper left pixel is calculated. Please note that we multiply with Width * 1 and not Width * 2. This is because we use a WORD pointer to access the image data. Of course, the multiplication by 1 is just for illustration and can be left out.

  (Height-1) * Width

  Now that we have the offset to the the first pixel, we can read it out:

  // Please note: RGB values are stored within a WORD in the following order: R,G,B

  // A binary AND operation is done with the color mask to extract the specific color.

  // After the AND operation, a right shift is done so that the output is displayed correctly.

  printf( "/nImage buffer pixel format is eRGB565/n" );

  printf( "Pixel 1(RGB): %d %d %d/n", ( pwImgData[iOffsUpperLeft] & eRGB565_R ) >> 11,

  ( pwImgData[iOffsUpperLeft] & eRGB565_G ) >> 5,

  ( pwImgData[iOffsUpperLeft] & eRGB565_B ) );

  printf( "Pixel 2(RGB): %d %d %d/n", ( pwImgData[iOffsUpperLeft+1] & eRGB565_R ) >> 11 ,

  ( pwImgData[iOffsUpperLeft+1] & eRGB565_G ) >> 5,

  ( pwImgData[iOffsUpperLeft+1] & eRGB565_B ) );

  As seen in the code above, we perform a binary AND operation with the appropriate pixel mask on the current pixel to extract the color value. After that, the values for red and green must be shifted to the right to get the correct value (otherwise the value would be 2048 (32 times too big)).

  Manipulating Image Data

  Shifting is also important when assigning values. For example, if 7 is assigned to the red value, it must be shifted 11 times to the left. Instead of writing:

  // Assign 7 to the red value

  pwImgData[iOffsUpperLeft] = 7; // this is WRONG

  which assigns 7 to the blue value, the following code should be used:

  // Assign 7 to the red value

  pwImgData[iOffsUpperLeft] = 7 << 11;

  Another important thing to note is that the assignment above will overwrite the values for green and blue. To prevent this, the value must be ORed to the pixel data as the following code will show:

  // Clear the red value (set all bits to 0)

  pwImgData[iOffsUpperLeft] &= ~eRGB565_R;

  // Assign 7 to the red value without overwriting green and blue values

  pwImgData[iOffsUpperLeft] |= 7 << 11;

  Please note that all bits of the appropriate color should be set to 0, as the code above does. Consider, for example, that the previous red value could have been 16 (or 10000 binary). If we then perform a binary OR operation with 7 (or 111 binary), the result will be 23 (or 10111 binary). Therefore, it is better to set all bits of the appropriate channel to 0.

  Now we set the upper left hand pixel to red, the next to green and the third to blue.

  // overwrite the first 3 pixels and save image to disk

  // set the first pixel to RED

  pwImgData[iOffsUpperLeft] = 0; // clear the pixel

  pwImgData[iOffsUpperLeft] |= 31 << 11; // Assign the value for red

  // set the second pixel to GREEN

  pwImgData[iOffsUpperLeft+1] = 0; // clear the pixel

  pwImgData[iOffsUpperLeft+1] |= 63 << 5; // Assign the value for green

  // set the third pixel to BLUE

  pwImgData[iOffsUpperLeft+2] = 0; // clear the pixel

  pwImgData[iOffsUpperLeft+2] |= 31; // Assign the value for blue

  pActiveBuf->save( "RGB565.bmp" );

  

 

 

上面的都是废话,言归正传,要使用DirectDraw显示RGB565:

pixel格式设置是这样的
首先:pixel格式设置是十分重要的,设置不好,离屏面无法建立,以后的工作都是无用的了。像素格式设置

如下:

 

DDPIXELFORMAT   overlayFormat;   
ZeroMemory(&overlayFormat,sizeof(overlayFormat));   

    
  DDPIXELFORMAT   PixelFormat= { sizeof(DDPIXELFORMAT),DDPF_RGB, 0, 16,       0xF800,0x07E0,0x001F, 0 };      
  DDSURFACEDESC   ddsd1;  
  ZeroMemory(&ddsd1,sizeof(ddsd1));  
  ddsd1.dwSize   =   sizeof(ddsd1);  
  ddsd1.dwFlags   =   DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;  
  ddsd1.ddsCaps.dwCaps   =   DDSCAPS_OFFSCREENPLAIN;  
  ddsd1.dwWidth   =   nWidth;  
  ddsd1.dwHeight=   nHeight;  
  ddsd1.ddpfPixelFormat   =  PixelFormat;   
              
   HRESULT   ddral;  
  ddral   =   pDD->CreateSurface(&ddsd1,&pVideoSurface,NULL);  
  if(ddral   !=   DD_OK){  
            MessageBox(NULL,   DXGetErrorString9(ddral),   "     ",   MB_OK);  
  }

其次:由于DirectDraw的显示顺序是从上到下,从左到右的方式,而BMP位图的数据存储方式是像素从下到上,从左到右,

 

所以要在位图数据拷贝到离屏面时要注意,否则显示出的图像是倒过来的。

 

具体如下:

            DDSURFACEDESC ddsd;
    LPWORD lpSurface;
    long Pitch;

    ddsd.dwSize = sizeof(ddsd);

    // 锁定Back Surface,DDraw中的Surface必须先锁定,然后才能访问
    while((ddrval=lpDDSBack->Lock(NULL, &ddsd, 0, NULL))==DDERR_WASSTILLDRAWING);
    if(ddrval == DD_OK)
    {
      // 起始地址指针,注意其类型是指向WORD的指针
      lpSurface = (LPWORD)ddsd.lpSurface;

               
      // 我们关心的Pitch,其值是字节(BYTE)数
      Pitch = ddsd.lPitch;
      Pitch >>= 1; // 为了方便后面的计算,把它换算成字(WORD)数

      // 作了以上处理以后,像素坐标到地址的换算公式为
      // (LPWORD)addr = lpSurface + y*Pitch + x;

      // 拷贝BMP数据到离屏面
      {
         int x, y;

         for(y=0; y         for(x=0; x         {
           *(lpSurface + y*Pitch + x)=*(lpbmpdata +( ScreenH-y-1)*Pitch + x);//  lpbmpdata为字指针,指向的是位图的数据的指针。
         }
      }

 

 

执行一下你的程序吧,如果成功,恭喜你!如何弹出非法错误,通过调试跟踪我们发现问题出现在上面的循环。可能大家都会知道这里的Pitch值在不同的电脑上的值是不一样的,一般情况下大家认为Plitch=ddsd.lPitch/2=ScreenW(当然这只是16位的情况),具体什么含义参考MSDN.如何Pitch的值大于ScreenW那么上面的操作肯定会发生内存溢出。所以修改为*(lpSurface + y*Pitch + x)=*(lpbmpdata +( ScreenH-y-1)*ScreenW + x);//  在什么电脑上都不会有问题了,除非你的显卡支持RGB555,不支持RGB565.

 

 

 

 

以上只介绍关键步骤,如需完整代码学习,请留言。

你可能感兴趣的:(视频处理)