12- and 16-bit Grayscale Format used by LEADTOOLS

DirectShow and Windows do not support 12- and 16-bit grayscale bitmaps. LEAD has defined the LGRY video format to enable the use of such bitmaps using the DirectShow architecture. This is used in the DICOM filters to generate grayscale video with more than 8 bits per pixel.

When describing compressed 12/16-bit data, indicate the media type format is using the LGRYVideoInfo structure by setting the media subtype to FORMAT_LGRYVideoInfo. When describing uncompressed 12/16-bit data, indicate the media type format is using the LGRYVideoInfo structure by setting the biCompression to LGRY. But even in this case, it is better to also set the media subtype to FORMAT_LGRYVideoInfo.

The following define statements and structures can be found in <INSTDIR>\Include\LGRYType.H:

Constants

static GUID FORMAT_LGRYVideoInfo = { 0x48799704, 0x2735, 0x4be6, { 0xa0, 0xce, 0xdd, 0xc6, 0x2c, 0x25, 0xa4, 0xf2 } }; 

The formattype member of the media type must be set to FORMAT_LGRYVideoInfo (or ltmmFORMAT_LGRYVideoInfo) to indicate the use of the LGRYVIDEOINFO structure to describe 12- or 16-bit compressed data. It is not necessary to set the formattype to indicate uncompressed 12/16-bit data, but it is recommended to do so even for uncompressed data.

Note: FORMAT_LGRYVideoInfo is defined in LGRYType.h, while ltmmFORMAT_LGRYVideoInfo is defined in ltmm.h.

Data Types

LGRYVIDEOINFO

typedef struct 
{ 
   RECT rcSource; 
   RECT rcTarget; 
   DWORD dwBitRate; 
   DWORD dwBitErrorRate; 
   REFERENCE_TIME AvgTimePerFrame; 
   LGRYINFOHEADER bmiHeader; 
   RGBQUAD bmiColors[65536]; 
} LGRYVIDEOINFO, FAR*pLGRYVIDEOINFO; 

Describes the format of a grayscale video format:

Member

Description

rcSource

The image portion to use

rcTarget

Target location for the video

dwBitRate

Approximate bit data rate

dwBitErrorRate

Bit error rate for this stream

AvgTimePerFrame

Average time per frame (100ns units)

bmiHeader

Structure containing grayscale image information.

bmiColors

Remapping lookup table (LUT). This is optional. This field is ignored unless bmiHeader. biClrUsed is non-zero.

LGRYINFOHEADER

typedef struct tagLGRYINFOHEADER 
{ 
   /* BITMAPINFOHEADER fields */ 
   DWORD biSize; 
   LONG biWidth; 
   LONG biHeight; 
   WORD biPlanes; 
   WORD biBitCount; 
   DWORD biCompression; 
   DWORD biSizeImage; 
   LONG biXPelsPerMeter; 
   LONG biYPelsPerMeter; 
   DWORD biClrUsed; 
   DWORD biClrImportant; 
   /* Fields specific only to the LGRY format */ 
   LONG biLowBit; 
   LONG biHighBit; 
   LONG biMinVal; 
   LONG biMaxVal; 
   LONG biWindowWidth; 
   LONG biWindowCenter; 
   double biRescaleIntercept; 
   double biRescaleSlope; 
   DWORD biFlags; 
   LONG nReserved1; 
   LONG nReserved2; 
   LONG nReserved3; 
} LGRYINFOHEADER, FAR*pLGRYINFOHEADER; 

Describes the grayscale image.

Member

Description

biSize

Size of this structure. Should be sizeof(LGRYINFOHEADER).

biWidth

Video width.

biHeight

Use positive value to specify a top-down image. This is the opposite of the Windows convention for uncompressed RGB images.

biPlanes

Should be 1

biBitCount

Should be 12 or 16:
If 16, the data is in Intel order
If 12, the data is in LEAD packing with 3 bytes for every 2 pixels.

biCompression

Should be mmioFOURCC('L','G','R','Y') to indicate uncompressed data.

Should be mmioFOURCC('L','j','p','g') to indicate lossless JPEG data.

Should be mmioFOURCC('J','P','E','G') or mmioFOURCC('M','J','P','G') to indicate lossy JPEG data.

When using JPEG data, set the formattype to FORMAT_LGRYVideoInfo or ltmmFORMAT_LGRYVideoInfo.

biSizeImage

Size of the image in bytes. The size of each line needs to be a multiple of 4 bytes, so padding might be required. The formula for calculating this field properly is: biSizeImage = ((((biWidth * biBitCount) + 31) & ~31) / 8) * abs(biHeight)

biXPelsPerMeter

Specifies the horizontal resolution, in pixels per meter.

biYPelsPerMeter

Specifies the vertical resolution, in pixels per meter.

biClrUsed

0 if the LUT is not present. In this case, the bmiColors field is not used/needed.

!= 0 if there is a LUT. In this case, bmiColors contains the LUT. biClrUsed should be equal to 1<<(biHighBit - biLowBit + 1)

biClrImportant

Not currently used. Set this value to 0

biLowBit

Low bit for the pixel data (0 <= biLowBit <= biHighBit <= biBitCount-1).

biHighBit

High bit for pixel data.

biMinVal

Minimum value of the pixel data only (ignores the non-pixel bits).

biMaxVal

Maximum value of the pixel data only (ignores the non-pixel bits).

biWindowWidth

DICOM window width. This can be used to regenerate the LUT.

biWindowCenter

DICOM window center. This can be used to regenerate the LUT.

biRescaleIntercept

DICOM rescale intercept. This can be used to regenerate the LUT.

biRescaleSlope

DICOM rescale slope. This can be used to regenerate the LUT.

biFlags

Indicates which fields are valid. Possible values are:

LGRY_RESCALE_VALID [0x0001] if set, biRescaleIntercept and biRescaleSlope are valid

LGRY_WINDOW_VALID [0x0002] if set, biWindowSize and biWindowCenter are valid

LGRY_BITRANGE_VALID [0x0004] if set, biLowBit and biHighBit are valid

LGRY_MINMAX_VALID [0x0010] if set, biMinVal and biMaxVal are valid

LGRY_LUT_ISGENERATED [0x0020] If there is a LUT: If set, the LUT is generated from the valid LGRY-specific fields. If not set, the LUT cannot be regenerated from the other LGRY fields. In this case, the LUT needs to be saved in the file.

LGRY_LUT_ISGRAYSCALE [0x0040] If there is a LUT and this flag is set, then the LUT contains only grayscale values. This flag is set to avoid going through the LUT every time to detect whether the LUT contains only grayscale colors.

LGRY_LUT_ISCOLOR [0x0080] If there is a LUT and this flag is set, then the LUT contains non-grayscale values. This flag is set to avoid going through the LUT every time to detect whether the LUT contains only grayscale colors.

LGRY_LUT_COLORMASK [0x00C0] This is NOT a flag. It is a MASK which can be used to detect whether a LUT is color, grayscale or unknown.

nReserved1

Reserved for future use.

nReserved2

Reserved for future use.

nReserved3

Reserved for future use.

Comments

The 12-bit data is packed: every 2 pixels occupy 3 bytes.

For example, if you have (2) 12-bit values and their hex values are 0xABC and 0xDEF, they will be stored in memory like this: 0xBC 0xFA 0xDE

This packing has the advantage that you can get each value on Intel processors with one read and one logical operation ("and" with 0xFFF for first value, shift right 4 bits for the second value).

The following macros can be used to deal with 12-bit packed data (keep in mind that these are C multi-line macros and it is important that they have "\" at the end of the line):

// helper macro for incrementing a pointer 
#define PTR_INC(p) (((BYTE*)p)+1) 
// read first 12-bit value 
#define GET12_0(p) ((*(WORD*)p) & 0xFFF) 
// read second 12-bit value 
#define GET12_1(p) ((*(WORD*)PTR_INC(p)) >> 4) 
// write two 12-bit values 
#define PUT12(p, val0, val1) *(WORD*)p = (((val0) & 0xFFF) |  
((WORD)(val1) << 12)); \ 
((BYTE*)p)[2] = ((DWORD)(val1) >> 4) 
// write the first 12-bit value 
#define PUT12_0(p, val0) *(WORD*)p = ( (*(WORD*)(p) & 0xF000) | \ 
((val0)& 0xFFF)) 
// write the second 12-bit value 
#define PUT12_1(p, val1) *(WORD*)PTR_INC(p) = \ 
((*(WORD*)PTR_INC(p) & 0xF) | \ 
((WORD)(val1) << 4)) 

Example

The following example describes how to set the various fields to describe grayscale 16-bit data in which only the lower 10 bits are to be used: 

LGRYVIDEOINFO info; /* warning: do not put this on stack, as it is very large */ 
info.bmiHeader.biSize = sizeof(LGRYINFOHEADER); 
info.bmiHeader.biWidth = VideoWidth; 
info.bmiHeader.biHeight = VideoHeight; /* should be positive for normal (unflipped video) */ 
info.bmiHeader.biPlanes = 1; 
info.bmiHeader.biBitCount = 16; /* I have 16 bits per pixel, although only the lower 10 bits contain useful data */ 
info.bmiHeader.biCompression = mmioFOURCC('L', 'G', 'R', 'Y'); 
info.bmiHeader.biSizeImage = (((VideoWidth * 2) + 3) & ~3) * VideoHeight; 
info.bmiHeader.biClrUsed = 0; /* there is no LUT */ 
info.bmiHeader.biClrImportant = 0; /* not used right now. Set this value to 0 */ 
/* Fields specific only to the LGRY format */ 
info.bmiHeader.biLowBit = 0; /* low bit for the pixel data (0 <= biLowBit <= biHighBit <= biBitCount-1) */ 
info.bmiHeader.biHighBit = 9; /* 10-1 = 9. high bit for pixel data. */ 
info.bmiHeader.biFlags = LGRY_BITRANGE_VALID; /* only biLowBit and biHighBit are valid */ 
/* Since this case does not use the LUT, it is enough to set only the fields of LGRYVIDEOINFO up to and including bmiHeader. The useful size of the 
LGRYVIDEOINFO structure is offsetof(LGRYVIDEOINFO, bmiColors). */ 

Help Version 21.0.2021.7.2
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2021 LEAD Technologies, Inc. All Rights Reserved.

LEADTOOLS Filters C API Help
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2021 LEAD Technologies, Inc. All Rights Reserved.