|
If you read the other answers, you'll see someone refers to bitfields. That's the important clue - you can look that up in your c++ book, as the full answer is too long for me to bother typing here!
Iain.
|
|
|
|
|
Hi,
We are getting ready to start developing a new windows application interface for our research application. The current version was written in MFC (Dialog box version) where there is a main dialog box which covers the whole screen and then several small dialog boxes are defined in it each one performing certain action and currently everything runs in serialized fashion. With this application we are getting closed loop frequencies of not more than 3Hz. For the next generation application we are intending to improve this atleast to 15Hz by implementing multi threading environment.
Here is how the program flow goes in current application.. you capture an image (at certain exposure settings, the longer the exposure time, the more delay you have in capturing the image) and is shown on one of the dialog boxes (say dailog1), do some analysis on that image and comeup with some data that should be shows in graphical format on the image in dialog1 and then using the same data and doing some more calculations you have to draw some graphics on three more dialog boxes and then compute the resultant data that is to be fed to the system and update another graphical dialog box to reflect the final result. At the end update some parameters(values) on the main dialog box.
Before you capture next image for next iteration, you should be done by sending the new values calculated in previous iteration. Currently, this goes one after the other (including graphic dialog boxes update). As far as I can see, updating these graphic dialog boxes is taking lots of time compared to actual data computation.
I am looking forward for some better ideas on implementing this to higher speeds.
thanks in advance.
|
|
|
|
|
Pavan Berkeley wrote: updating these graphic dialog boxes is taking lots of time compared to actual data computation
Screen drawing on modern PCs should be pretty fast.
Are you sure the bottleneck isn't somewhere else?
What exposure time is typical?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I think I am sure... but anyway here are the timings that I measured while running the closed loop..
Camera function started 40:48:961.054
Camera function done 40:49:4.228 >> ~43msec (for capturing the image at 20msec exposure time, subtracting the background)
Calculations done 40:49:17.848 (entire calculations are done by this point ~13msec)
Updated displays 40:49:259.003 (entire displays are updated by this point ~242msec)
one iteration completed
Here are the timings that I recorded from the current application. From the above, we cant get rid of 20msec delay from camera (which sometimes changes to even more, but 20msec is the min). This comes out to be 3.37Hz which is very slow comparatively.
PKNT
|
|
|
|
|
Focusing on the display updates, then, what kind of (and how many) operations
are you doing?
Drawing bitmaps? Graphs? Using GDI? GDI+?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
The way its implemented currently is just using SetPixel, so its GDI. This is done for 5 dialog windows (including drawing over camera image) after each iteration of calculation. Among these 5 dilaog boxes, two graphical dialog boxes are being updated in the main dialog box file.
PKNT
|
|
|
|
|
Kiran Satish wrote: ...just using SetPixel...
ouch!
I don't know the format of the data you need to display, but I bet you can
shave 100-200 ms off your display time.
If the data is in a bitmap form (rows and columns of pixels) then I would start
with using a DIBSection(). This gives you a DIB that you can select into a
device context AND you have a pointer to the pixel bits. You can directly
set pixels in memory, probably way faster than SetPixel().
The DIBSection can remain selected into a memory DC.
Then you can blt the entire bitmap to the screen in one shot.
What format is the pixel data in? Dimensions, bits-per-pixel, etc.??
Does this sound like something you can benefit from?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Yeh, sure DIBSection will be definitely faster than drawing pixel by pixel. But the problem is I am not sure how to convert the data that I use into usable format for this function. I will do some research and some testing to see if I can somehow change or redefine the data to go in this way. Anyway here is how the function is implemented for repainting one of the dialog boxes..
void ResImageDlg::color_AllBoxes(CWnd *ResDisp)<br />
{<br />
double resval;<br />
int i,j,x,y;<br />
RECT ResRect;<br />
COLORREF color;<br />
<br />
CDC *ResCDC = ResDisp->GetDC();<br />
for(i=0; i < GRID; i++)
{<br />
for(j=0; j < GRID; j++)<br />
{<br />
if( (j == 0 || j == (GRID-1)) && (i == 0 || i == (GRID-1)) )<br />
;
else<br />
{<br />
resval = (parent->calcfile)->FetchResData(i,j); <br />
ResRect.left = X_OFFSET + (i*(RES_BOX_SIZE+BOX_GAP));<br />
ResRect.right = ResRect.left + RES_BOX_SIZE;<br />
ResRect.top = Y_OFFSET + (j*(RES_BOX_SIZE+BOX_GAP));<br />
ResRect.bottom = ResRect.top + RES_BOX_SIZE;<br />
color = check_ColorLimits(resval); <br />
for(x=ResRect.left; x < ResRect.right; x++)<br />
for(y=ResRect.top; y < ResRect.bottom; y++)<br />
ResCDC->SetPixelV(x,y,color);<br />
}<br />
}<br />
}<br />
ResDisp->ReleaseDC(ResCDC);<br />
}
The actual data is nothing but some real numbers between 0 and 2.0; two other dialog boxes are also drawn in the same fashion, but since they are 8bit graphic type, the data is scaled to be in between 0 and 255 and uses SetPixelV to draw that pixel.
Hope I am not confusing...
PKNT
|
|
|
|
|
I can't read your code for the loops - can you modify your post so
HTML tags are ignored?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
what about the SetPixel loop?
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Heh cool, thanks
You can optimize this alot.
Move any code that calculates rects, positions, etc. to a more appropriate
place - the place where it changes (e.g. WM_SIZE). Usually that stuff stays the
same between draws so there's no reason to recalculate it every time you draw.
Same goes for any variables that don't change or don't change often.
Change the SetPixel loop to write directly to the pixel memory of a DIBSection.
SetPixel has to calculate the width of the destination bitmap(DC) in bytes and
calculate the offset in the destination pixel memory every time you call it.
In your own loop, most of this can be calculated once and you can increment your
way through the pixel data.
I'm still not clear on your data format...how do the 8-bit values relate to an RGB color?
Is it grayscale?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: I'm still not clear on your data format...how do the 8-bit values relate to an RGB color?
Is it grayscale?
Yes, among 5 graphic dialog boxes two are grayscale while other 3 are color. The loop that I have shown you above is of a color graphic dialog box. Even for grayscale values, they use the same 8bit value (that they calculate according to the data value) for all three channels of RGB.
PKNT
|
|
|
|
|
The grayscale will be way faster if you stop using SetPixel().
And what about the color....is that 8-bit too? If so, how do you map 8-bit to RGB?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
For color values, its not 8 bits. RGB value is calculated using the following function.
<br />
double mid = get_MidVal();
double max = get_MaxVal() - mid;<br />
double min = get_MinVal() - mid;<br />
val -= mid;
int blueval=0;<br />
int redval=(int)(MID_RGB_VALUE + ((val/max)*MID_RGB_VALUE));<br />
int greenval=(int)(MID_RGB_VALUE - ((val/max)*MID_RGB_VALUE));<br />
if ((val <= min)||(val >= max)) <br />
{redval=255;blueval=255;greenval=0;}<br />
<br />
return RGB(redval,greenval,blueval);
then that RGB value is used to color all the pixels in that particular box of the loop in earlier post.
PKNT
|
|
|
|
|
Well that's cool....you have RGB covered for two data types. What did you need SetPixelV for then?
SetPixelV would be your slowest API call.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Honestly, I donnno why they used it. Its written like 4 years ago by two people and they are not here now .
Will see wht I can do to modify this using DIBSection. I haven't used it in any of my applications till now, so have to do some research/reading on it and also the way to implement in my case.
thanks for all your help, I really appreciate it.
PKNT
|
|
|
|
|
Kiran Satish wrote: so have to do some research/reading on it and also the way to implement in my case.
Hopefully this will help a bit...
<code>
LONG DIBSecWidth = ...;
LONG DIBSecHeight = ...;
LONG BitsPerPixel = 24;
LONG Stride = ((DIBSecWidth * BitsPerPixel + 31L) & (~31L)) / 8L;
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = DIBSecWidth;
bmi.bmiHeader.biHeight = DIBSecHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = (WORD)BitsPerPixel;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = Stride * abs(DIBSecHeight);
BYTE *pDIBSectionBits;
HBITMAP hbm = ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pDIBSectionBits, NULL, 0);
<code>
int x = ...;
int y = ...;
RGBTRIPLE *pPixel = (RGBTRIPLE *)(pDIBSectionBits + ((y * Stride) + (x * sizeof(RGBTRIPLE))));
<code>
pPixel[0].rgbtBlue = 0;
pPixel[0].rgbtGreen = 0;
pPixel[0].rgbtRed = 0;
<code>
RECT rect;
rect.left = 10;
rect.top = 10;
rect.right = 20;
rect.bottom = 20;
RGBTRIPLE *pCurRowPixel = (RGBTRIPLE *)(pDIBSectionBits + ((rect.top * Stride) + (rect.left * sizeof(RGBTRIPLE))));
for (int y = 0; y < rect.bottom - rect.top; ++y)
{
for (int x = 0; x < rect.right - rect.left; ++x)
{
pCurRowPixel[x].rgbtBlue = 0;
pCurRowPixel[x].rgbtGreen = 0;
pCurRowPixel[x].rgbtRed = 0;
}
pCurRowPixel = (RGBTRIPLE *)((BYTE*)pCurRowPixel + Stride);
}
You can probably optimize that stuff even further for specific implementations
but that generic code should be much faster than a SetPixel loop
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Thanks for the info, will help me in understanding it more easily. Just done with matlab, will start going thru this now.
PKNT
|
|
|
|
|
I found very little help on DIBSection while found many examples on using CBitmap class. Anyway I started off routine of my application where I color boxes in a window.
My window (with 12x12 grid) is 513x513 and the grid's horizontal and vertical offset is 20 (this would be the width of the border of the grid) and box width (each box in the grid) is 15 and box gap is 2(this would be the width of grid lines inside). These are constants and they stay the same all the time.
So while creating this window object I have to do the following--
LONG DIBSecWidth = 513;
LONG DIBSecHeight = 513;
LONG BitsPerPixel = 24;
CDC *ResCDC = ResDisp->GetDC();/*ResDisp is handle of this window and ResCDC need not be changed while redrawing so I dont need to call it everytime I call the above routine.*/
LONG Stride = ((DIBSecWidth * BitsPerPixel + 31L) & (~31L)) / 8L; /**I didnt understand this step, how can I calculate this in my case*/
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = DIBSecWidth;
bmi.bmiHeader.biHeight = DIBSecHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = (WORD)BitsPerPixel;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = Stride * abs(DIBSecHeight);
BYTE *pDIBSectionBits;
HBITMAP hbm = ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pDIBSectionBits, NULL, 0);/**I have to replace first argument NULL with my ResCDC */
From then I couldnt understand how I can find pixel address for each pixel in my application while considering box sizes and gap.
Now I have to color each box with some color, so is there any way to fill each box in memory with that same color rather going in two for loops, like using fillrect etc?? This way I can eliminate the inner two for loops in my code.
thanks,
PKNT
|
|
|
|
|
Kiran Satish wrote: 513x513 and the grid's horizontal and vertical offset is 20 and box width (each box in the grid) is 15 and box gap is 2.
How do you get 513? 12 cells at 15 pixels each is 180 pixels. 11 2-pixel gaps is 22 pixels. Total == 202 pixels (assuming no border).
Kiran Satish wrote: LONG Stride = ((DIBSecWidth * BitsPerPixel + 31L) & (~31L)) / 8L; /**I didnt understand this step, how can I calculate this in my case*/
Bytes per row in a DIB have to be aligned on a DWORD (4-byte) boundary. That's what this calculation does.
The calculation is always the same - it's always based on DIBSecWidth.
Kiran Satish wrote: HBITMAP hbm = ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pDIBSectionBits, NULL, 0);/**I have to replace first argument NULL with my ResCDC */
You don't need to worry about a DC here since the DIBSection is 24-bits-per-pixel.
You shouldn't be worrying about a DC anywhere here - this is al stuff that can be calculated once,
not every time you redraw - that's part of what will save you alot of CPU cycles
Kiran Satish wrote: From then I couldnt understand how I can find pixel address for each pixel in my application while considering box sizes and gap.
It depends on how you want to loop. If it's always by cell, the upper left corner pixel
coordinates (x,y) for a given cell (CellX,CellY) would be
x = CellX * CellWidthInPixels + CellX * GapWidthInPixels;
y = CellY * CellHeightInPixels + CellY * GapHeightInPixels;
With (x,y) you can use the calculation in my examples to get the byte offset in the pixel data.
Make youreslf a handy utility function to calculate these if you're using them alot.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: How do you get 513? 12 cells at 15 pixels each is 180 pixels. 11 2-pixel gaps is 22 pixels. Total == 202 pixels (assuming no border).
Sorry its 265x250, they are creating this window with these dimensions and while drawing boxes, they add offset of 20 from top and bottom
Here is a snapshot of it. The four corner boxes are always black.
Hope this helps in understanding a lil better.
PKNT
|
|
|
|
|
Kiran Satish wrote: Hope this helps in understanding a lil better.
Yes! Thank you!
In that case the DIBSection can be 202x202.
The calculations I've explained previously will work.
The entire grid bitmap can then be blted to the window at whatever offset you want.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Before I start changing the code to use DIBSection, I started referin at BitBlt on msdn and came accross PatBlt and thought of quickly trying it with the following arguments-
within the loop
CBrush *pcolor,tcolor;<br />
for(i=0; i < GRID; i++)
{<br />
for(j=0; j < GRID; j++)<br />
{<br />
if( (j == 0 || j == (GRID-1)) && (i == 0 || i == (GRID-1)) )<br />
;
else<br />
{<br />
resval = (parent->calcfile)->FetchResData(i,j);<br />
ResRect.left = X_OFFSET + (i*(RES_BOX_SIZE+BOX_GAP));<br />
ResRect.right = ResRect.left + RES_BOX_SIZE;<br />
ResRect.top = Y_OFFSET + (j*(RES_BOX_SIZE+BOX_GAP));<br />
ResRect.bottom = ResRect.top + RES_BOX_SIZE;<br />
color = check_ColorLimits(resval); <br />
tcolor = new CBrush(GetRVal(color),GetGVal(color),GetBVal(color));<br />
pcolor = ResCDC->SelectObject(&tcolor);<br />
PatBlt(ResCDC->m_hDC, ResRECT.left, ResRECT.top, (ResRECT.right-ResRECT.left), (ResRECT.bottom-ResRECT.top), PATCOPY);<br />
}<br />
}<br />
}<br />
ResDisp->ReleaseDC(ResCDC);
The above loop is working fine for one grid location and draws one box filled with color, for the second time when it reaches selectobject statement, it is crashing with an error in wingdi.cpp. It seems like I am reselecting a new object without actually releasing the first color or soething like tht. How can I get rid of this error??
thanks,
PKNT
|
|
|
|
|
Any time you select an object into a DC, you should save the
previously selected object. When you're done with the DC, select the original
object back into the DC.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Yep.... just done that and here you are with your reply, Damn you beat me again . Slowly getting used to these. Now just using PatBlt instead of SetPixel for GRID window increased my application's closed loop freq from 2.84Hz to 8Hz whoa... Now I have to change the way of drawing other two windows with DIBSection as I cant use PatBlt, since each pixel will have different intensity.
PKNT
|
|
|
|