Solved

Display 8bit image data in a window

Posted on 2006-07-21
4
396 Views
Last Modified: 2013-11-20
Hi All,

I need to display some data in the View of an MFC application.

The data i have has come from a camera and is 8 bit data with each bit representing one grey scale pixel value.

I'm having problems display the data at the moment.  With the code i have the image is the correct size but the image within it seems to repeat itself four times.

My current solution involves trying to create a CBitmap object out of the data using CreateCompatibleBitmap and SetBitmapBits.

I have very little experience of palettes and CBitmaps so any help would be appreciated.

This is the code I currently have in OnDraw:  (pImage->GetData returns the raw data)

ImageData* pImage = pDoc->GetImage();

CDC dcMem;
dcMem.CreateCompatibleDC(pDC);

CBitmap bitmap;
bitmap.CreateCompatibleBitmap(pDC, pImage->GetWidth(), pImage->GetHeight());
bitmap.SetBitmapBits(pImage->GetNumberOfBytes(), pImage->GetData());
CBitmap* pOldBitmap = dcMem.SelectObject(&bitmap);
pDC->BitBlt(0, 0, pImage->GetWidth(), pImage->GetHeight(), &dcMem, 0, 0,SRCCOPY);
dcMem.SelectObject(pOldBitmap);

Maybe i need to do something with the palette?

Thanks
0
Comment
Question by:spforeman
  • 3
4 Comments
 
LVL 22

Accepted Solution

by:
mahesh1402 earned 500 total points
Comment Utility
It seems you have 8 bit 'Raw' data obtained from camera..I will suggest you to convert this 8-bit data to bitmap using code something like following :

// Allocate bitmap header structure
BITMAPINFO * BMI = (BITMAPINFO*)new unsigned char[sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * 256)];

// Fill the greyscale palette
for (int GenPal = 0; GenPal < 256; GenPal++)
    *(int*)(&BMI->bmiColors[GenPal]) = GenPal * 0x10101;

// Fill in some information about the image we'll be creating
BMI->bmiHeader.biSize = sizeof(BMI->bmiHeader);
BMI->bmiHeader.biWidth = 128;   // here specify image width
BMI->bmiHeader.biHeight = 128; // here specify image height
BMI->bmiHeader.biPlanes = 1;
BMI->bmiHeader.biBitCount = 8;
BMI->bmiHeader.biCompression = BI_RGB;
BMI->bmiHeader.biXPelsPerMeter = 0;
BMI->bmiHeader.biYPelsPerMeter = 0;
BMI->bmiHeader.biClrUsed = 256;
BMI->bmiHeader.biClrImportant = 256;

// Get the DWord aligned scanline width
int ScanLine = (BMI->bmiHeader.biWidth + 3) & 0xFFFFFFFC;

// Fill in the image data size in the header
BMI->bmiHeader.biSizeImage = ScanLine * BMI->bmiHeader.biHeight;

// Create a New DC
HDC DrawDC = CreateCompatibleDC(NULL);

unsigned char * DataPtr; // <===== This is the pointer to the raw image data

// Create a new DIBSection
HBITMAP DrawBMP = CreateDIBSection(DrawDC, BMI, DIB_RGB_COLORS, (void**)&DataPtr, NULL, NULL);

// Select DIBSection into DC
HBITMAP OldBMP = (HBITMAP)SelectObject(DrawDC, DrawBMP);

if (OldBMP != NULL) { // Write image data (You would just copy your data in here)
    for (int DoY = 0; DoY < BMI->bmiHeader.biHeight; DoY++)
        for (int DoX = 0; DoX < BMI->bmiHeader.biWidth; DoX++)
            DataPtr[(DoY * ScanLine) + DoX] = DoX + DoY;

    // Draw the image to the screen (Assuming "hdc" holds the device context of your viewport)
    BitBlt(hdc, 0, 0, BMI->bmiHeader.biWidth,  BMI->bmiHeader.biHeight, DrawDC, 0, 0, SRCCOPY);

    // De-select DIBSection from the DC
    SelectObject(DrawDC, OldBMP);
 }
 
// Clean up GDI objects
DeleteObject(DrawBMP);
DeleteDC(DrawDC);

// Clean up header structure
delete BMI;

Hope this helps
-MAHESH
0
 
LVL 22

Expert Comment

by:mahesh1402
Comment Utility
you can also use SetDIBitsToDevice for this purpose

   LPBITMAPINFO bitinfo;
    unsigned char image[ImgHeight][ImgWidth];
    FILE *fp;

    fp = fopen("hands.raw", "rb");  // open raw file.. this is your 8 bit raw file received from camera
    if( fp == NULL ) return;

    bitinfo = (LPBITMAPINFO)new char[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
    bitinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitinfo->bmiHeader.biWidth = ImgWidth;
    bitinfo->bmiHeader.biHeight = ImgHeight;
    bitinfo->bmiHeader.biPlanes = 1;
    bitinfo->bmiHeader.biBitCount = 8;                  
    bitinfo->bmiHeader.biCompression = BI_RGB;
    bitinfo->bmiHeader.biSizeImage = 0;
    bitinfo->bmiHeader.biXPelsPerMeter = 0;
    bitinfo->bmiHeader.biYPelsPerMeter = 0;
    bitinfo->bmiHeader.biClrUsed = 256;
    bitinfo->bmiHeader.biClrImportant = 256;

    // gray palette
    for(int i = 0; i < 256; i++)
    {
      bitinfo->bmiColors[i].rgbRed = char(i);
      bitinfo->bmiColors[i].rgbBlue = char(i);
      bitinfo->bmiColors[i].rgbGreen = char(i);
      bitinfo->bmiColors[i].rgbReserved = 0;
    }

    for( int i=0; i<ImgHeight; i++)
    {
        fread( image[i], 1, ImgWidth, fp );
    }

// Create DC goes here

    ::SetDIBitsToDevice( hDC,0,0,ImgWidth,ImgHeight,0,0, 0,ImgHeight,image,bitinfo, DIB_RGB_COLORS);

    fclose( fp );
    delete[] bitinfo;
}
NOTE : If the width of a scanline is not divisible by 4, you must change the code to pad each line.  refer prev src code for ScanLIne calculation

-MAHESH
0
 
LVL 22

Expert Comment

by:mahesh1402
Comment Utility
othewise if you dont want to go as above simply :

1) Get *.raw filesize [file_size]

2) Create an array unsigned char* lpBits = new unsigned char[file_size];

3) Read the data from the file to lpBits

4) Create CBitmap from this data:
    CBitmap bm;
    bm.CreateBitmap( width, height, 1, 8, lpBits ); // you should know width height of raw image, and bits-per-pixel=8

5) Initialize PictureHolder with this bitmap:
    CPictureHolder::CreateFromBitmap((HBITMAP)bm);

6) Display bitmap:
    CPictureHolder::Render(...);

7) Clean up:
    delete [] lpBits;

-MAHESH
0
 

Author Comment

by:spforeman
Comment Utility
Thanks for the help MAHESH

All three solutions were spot on.

I had spent a day trying to do this and was so close.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now