C++ faster execution [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am using a while loop to execute some algorithms and what not, but it's not very fast, how would I allow my program to use more RAM? (Which I assumes is what limits it) It's currently sitting steadily at 504kB.
I am using
C::B 13.12
Windows 7 64bit
mingw32-g++.exe (I don't think I need the 64bit version unless I want to go over 4GB ram right?)
I apologize if this question has been asked and answered before, but I can't seem to find it if it has.
Edit: So this will scan 100 pixels, what is causing this to take 2.2 seconds?
#include <windows.h>
#include <iostream>
#include <wingdi.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
void scan(HDC dc, int x, int y, int &r, int &g, int &b) {
COLORREF color = GetPixel(dc, x, y);
r = GetRValue(color);
g = GetGValue(color);
b = GetBValue(color);
}
int main() {
HDC dc = GetDC(NULL);
int r,g,b;
for(int i = 0; i < 100; i++) {
scan(dc,100,100 + i,r,g,b);
}
ReleaseDC(NULL, dc);
return 0;
}
2:nd edit: Is it possible to reduce this time without editing the code? I mean, it has to be limited by either my RAM or my CPU right?

Your program isn't limited to that small amount of memory. Since it's most likely compiled as a 32 bit application, it will be able to allocate up to 2 GB of ram by default.
So, no, memory is most likely not your issue, unless you constantly request and free it again (but even then it really depends on your code).
If your program is too slow, you might be able to use parallelization to get faster processing, but once again this really depends on your actual code.
You might also be able to use templates and instanziation to optimize your algorithm(s) at compile time, but yet again without knowing the code... no.
Since the edit:
The bottleneck is - as mentioned already - the repeated calls to GetPixel() which in itself is rather expensive, since there's work to be done that isn't cached etc.
Instead, you should copy the window contents to your own memory area and read the pixels (as bytes) directly.
You can follow this MSDN example. They're writing the bitmap contents/pixels to a file, but you'll essentially want to do the same, just read that data directly. Just look for the use of the variable lpbitmap to find the related lines.
In short you'll want to create a screenshot with BitBlt() to a bitmap and then copy those pixels utilizing GetDIBits():
// memory dc for the window
hdcMemDC = CreateCompatibleDC(hdcWindow);
// bitmap for the screenshot
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
// connect both
SelectObject(hdcMemDC,hbmScreen);
// copy the window contents
BitBlt(hdcMemDC, 0,0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, hdcWindow, 0, 0, SRCCOPY);
// get the bitmap object
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
// access the bitmap
HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize);
// lock the bitmap
char *lpbitmap = (char *)GlobalLock(hDIB);
// copy the pixel data
GetDIBits(hdcWindow, hbmScreen, 0, (UINT)bmpScreen.bmHeight, lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
// now access lpbitmap inside your loop and later on clean up everything

The problem is with GetPixel. It is an extremely slow API. An alternate approach is to copy the screen to a memory buffer and then access the memory buffer.

Related

Win32 C++ effective storage or creation of bitmaps used for colour picker background

I am writing an HSV colour picker in plain win32 c++.
I have a Sat/Val box and a Hue slider exactly like the image on the left here:
Up until now I was just generating the background of the Sat-Val box whenever I needed it.
But now that I have a simple prototype and I am circling around to refactor and clean up I have realized that it actually takes a sizeable amount of time to generate the background bitmap for the sat-val box.
Since scrolling the hue slider should update the sat-val box with the appropriate hue, and it should be responsive and fast, I guess I cannot generate the background on the fly because it's too costly.
I have been using a very simple function like this:
HBITMAP ColorPicker::genSVBackground(uint32_t hue)
{
uint32_t width = 256;
uint32_t height = 256;
HDC hDC = GetDC(hwnd);
HDC memDC = CreateCompatibleDC(hDC);
HBITMAP bitmap = CreateCompatibleBitmap(hDC, width, height);
HGDIOBJ oldObj = SelectObject(memDC, bitmap);
for (uint32_t y = 0; y < height; ++y) {
for (uint32_t x = 0; x < width; ++x) {
RGBColor rgbCol = hsv_to_rgb(HSVColor(hue, x, 255 - y));
COLORREF col = (rgbCol.blue << 16) | (rgbCol.green << 8) | (rgbCol.red);
SetPixel(memDC, x, y, col);
}
}
SelectObject(memDC, oldObj);
DeleteDC(memDC);
return bitmap;
}
So the first question is:
Can I make this faster? Fast enough that I can still generate it on the fly? Should I?
And if I cannot make it faster, or if there's really no point and I might as well just use an external resource instead.
What is the best approach to go about storing this in an external resource?
Should I create one giant array that describes a 'cube' of hue x sat x val (my hue, sat and val system is 0-255 each) so I can just load the entire thing into memory and index certain positions to read out an entire background slice?
I know how to do the specifics of the resource storage/loading I'm just not sure if I'm approaching this problem the right way.
Should I store each slice as a separate resource? 256 of them?
Is there a standard way to solving this kind of thing?
I think the source of your slowness is writing one pixel at a time to the memory DC.
Instead of calling SetPixel 256x256 times in a loop, blast an entire matrix of pixels to the DC at once. At the very least, that's 64K function invocations.
I used to do this kind of buffering with GDI+ all the time. I'd create a Bitmap object and then call the LockBits method on it. Do my rendering directly on the returned pointer, and then UnlockBits. It's been a while since I've done the pure Win32 variations of this, but I'm sure it's possible.

GDI Acceleration In Windows 7 / Drawing To Memory Bitmap

My GDI program runs fine on Windows XP but on Windows Vista and 7 it looks pretty terrible due to the lack of GDI hardware acceleration. I recall reading an article a few years back saying that Windows 7 added hardware acceleration to some GDI functions, including BitBlt() function. Supposedly, if you if you draw to a memory bitmap and then use BitBlt() to copy the image to your main window it runs about the same speed as XP. Is that true?
If it is true, how do you do it? I'm terrible at programming and am having a bit of trouble. I created the below class to to try and get it working:
class CMemBmpTest
{
private:
CDC m_dcDeviceContext;
CBitmap m_bmpDrawSurface;
public:
CMemBmpTest();
~CMemBmpTest();
void Init();
void Draw();
};
CMemBmpTest::CMemBmpTest()
{
}
CMemBmpTest::~CMemBmpTest()
{
m_bmpDrawSurface.DeleteObject();
m_dcDeviceContext.DeleteDC();
}
void CMemBmpTest::Init()
{
m_dcDeviceContext.CreateCompatibleDC(NULL);
m_bmpDrawSurface.CreateCompatibleBitmap(&m_dcDeviceContext, 100, 100);
}
void CMemBmpTest::Draw()
{
m_dcDeviceContext.SelectObject(I.m_brshRedBrush);
m_dcDeviceContext.PatBlt(0, 0, 100, 100, BLACKNESS);
}
In the OnPaint() function of the window I added the line:
pDC->BitBlt(2, 2, 100, 100, &m_MemBmp, 0, 0, SRCCOPY);
I was hoping to see a 100x100 black box in the corner of the window but it didn't work. I'm probably doing everything horrifically wrong, so would be grateful if somebody could advise me as to how to do this correctly.
Thanks for any advice you can offer.
AFAIK you get hardware acceleration on GDI functions on all versions of Windows (I'm happy to stand corrected on this if someone can explain it in more detail). But either way, you're correct that double buffering (which is what you're talking about) provides a massive performance boost (and more importantly no flickering) relative to drawing direct to the screen.
I've done quite a lot of this and have come up with a method to allow you to use GDI and GDI+ at the same time in your drawing functions, but benefit from the hardware acceleration of the BitBlt in drawing to screen. GDI+ isn't hardware accelerated AFAIK but can be very useful in many more complex drawing techniques so it can be useful to have the option of.
So, my basic view class will have the following members :
Graphics *m_gr;
CDC *m_pMemDC;
CBitmap *m_pbmpMemBitmap;
Then the class itself will have code something like this
/*======================================================================================*/
CBaseControlPanel::CBaseControlPanel()
/*======================================================================================*/
{
m_pMemDC = NULL;
m_gr = NULL;
m_pbmpMemBitmap = NULL;
}
/*======================================================================================*/
CBaseControlPanel::~CBaseControlPanel()
/*======================================================================================*/
{
// Clean up all the GDI and GDI+ objects we've used
if(m_pMemDC)
{ delete m_pMemDC; m_pMemDC = NULL; }
if(m_pbmpMemBitmap)
{ delete m_pbmpMemBitmap; m_pbmpMemBitmap = NULL; }
if(m_gr)
{ delete m_gr; m_gr = NULL; }
}
/*======================================================================================*/
void CBaseControlPanel::OnPaint()
/*======================================================================================*/
{
pDC->BitBlt(rcUpdate.left, rcUpdate.top, rcUpdate.Width(), rcUpdate.Height(),
m_pMemDC, rcUpdate.left, rcUpdate.top, SRCCOPY);
}
/*======================================================================================*/
void CBaseControlPanel::vCreateScreenBuffer(const CSize szPanel, CDC *pDesktopDC)
// In :
// szPanel = The size that we want the double buffer bitmap to be
// Out : None
/*======================================================================================*/
{
// Delete anything we're already using first
if(m_pMemDC)
{
delete m_gr;
m_gr = NULL;
delete m_pMemDC;
m_pMemDC = NULL;
delete m_pbmpMemBitmap;
m_pbmpMemBitmap = NULL;
}
// Make a compatible DC
m_pMemDC = new CDC;
m_pMemDC->CreateCompatibleDC(pDesktopDC);
// Create a new bitmap
m_pbmpMemBitmap = new CBitmap;
// Create the new bitmap
m_pbmpMemBitmap->CreateCompatibleBitmap(pDesktopDC, szPanel.cx, szPanel.cy);
m_pbmpMemBitmap->SetBitmapDimension(szPanel.cx, szPanel.cy);
// Select the new bitmap into the memory DC
m_pMemDC->SelectObject(m_pbmpMemBitmap);
// Then create a GDI+ Graphics object
m_gr = Graphics::FromHDC(m_pMemDC->m_hDC);
// And update the bitmap
rcUpdateBitmap(rcNewSize, true);
}
/*======================================================================================*/
CRect CBaseControlPanel::rcUpdateBitmap(const CRect &rcInvalid, const bool bInvalidate, const bool bDrawBackground /*=true*/)
// Redraws an area of the double buffered bitmap
// In :
// rcInvalid - The rect to redraw
// bInvalidate - Whether to refresh to the screen when we're done
// bDrawBackground - Whether to draw the background first (can give speed benefits if we don't need to)
// Out : None
/*======================================================================================*/
{
// The memory bitmap is actually updated here
// Then make the screen update
if(bInvalidate)
{ InvalidateRect(rcInvalid); }
}
So, you can then either just draw direct to the memory DC and call InvalidateRect() or put all your drawing code in rcUpdateBitmap() which was more convenient for the way I was using it. You'll need to call vCreateScreenBuffer() in OnSize().
Hopefully that gives you some ideas anyway. Double buffering is definitely the way to go for speed and non-flickering UI. It can take a little bit of effort to get going but it's definitely worth it.
CMemDC:
http://www.codeproject.com/Articles/33/Flicker-Free-Drawing-In-MFC
http://msdn.microsoft.com/en-us/library/cc308997(v=vs.90).aspx

parallel_for function causes memory leaks (sometimes)

I'm making a simple native MFC application and I'm using th Concurrency namespace to perform a simple parallel program (drawing a Mandelbrot set). The program is very very basic so far, clicking one button draws in parallel, the other draws in serial. The serial execution function is very basic and draws the right picture. As does the parallel execution function, however when running the debug build and exiting the program, the output tells me there is a memory leak.
Here's the code:
void CMandelbrotView::DrawSetParallel() {
// Get client area dimension which will be the image size
RECT rect;
GetClientRect(&rect);
//GetClientRect(pDC, &rect);
int imageHeight(rect.bottom);
int imageWidth(rect.right);
const double realMin(-2.1); // Minimum real value
double imaginaryMin(-1.3); // Minimum imaginary value
double imaginaryMax(+1.3); // Maximum imaginary value
// Set maximum imaginary so axes are the same scale
double realMax(realMin+(imaginaryMax-imaginaryMin)*imageWidth/imageHeight);
// Get scale factors to convert pixel coordinates
double realScale((realMax-realMin)/(imageWidth-1));
double imaginaryScale((imaginaryMax-imaginaryMin)/(imageHeight-1));
CClientDC hdc(this); // DC is for this view
OnPrepareDC(&hdc); // Get origin adjusted
critical_section cs; // Mutex for BitBlt() operation
parallel_for(0, imageHeight, [&](int y) // Iterate parallel over image rows
{
cs.lock(); // Lock for access to client DC
// Create bitmap for one row of pixels in image
HDC memDC = CreateCompatibleDC(hdc); // Get device context to draw pixels
HBITMAP bmp = CreateCompatibleBitmap(hdc, imageWidth, 1);
cs.unlock(); // We are done with hdc here so unlock
HGDIOBJ oldBmp = SelectObject(memDC, bmp); // Select bitmap into DC
double cReal(0.0), cImaginary(0.0); // Stores c components
double zReal(0.0), zImaginary(0.0); // Stores z components
zImaginary = cImaginary = imaginaryMax - y*imaginaryScale;
for(int x = 0; x < imageWidth; x++) // Iterate over pixels in a row
{
zReal = cReal = realMin + x*realScale;
// Set current pixel color based on n
SetPixel(memDC, x, 0, Color(IteratePoint(zReal, zImaginary, cReal, cImaginary)));
}
cs.lock(); // Lock to write to hdc
// Transfer pixel row to client area device context
BitBlt(hdc, 0, y, imageWidth, 1, memDC, 0, 0, SRCCOPY);
cs.unlock(); // Release the lock
SelectObject(memDC, oldBmp);
DeleteObject(bmp); // Delete bmp
DeleteDC(memDC); // and our working DC
});}
The code for parallel execution is different from the serial execution code that it creates separate rows of the Mandelbrot image in parallel, and uses a critical section lock to make sure the threads don't fight over the same device context handle.
Now the reason I said there is memory leak reported sometimes is because running the release build does not cause a memory leak to be reported. Also, when running parallel execution function multiple times I don't really notice more memory being being used up, I have 6GB of RAM in case anyone is wondering.
As far as the performance goes, my quad-core machine does actually present a roughly 4x increase in calculation+drawing speed from serial execution.
I've also seen similar questions asks on the msdn website, but not of much use, because this may be a VS bug. Anyway, I'd like a parallel programmer's opinion.
This problem is documented in the fix-list for VS2010 SP1. The feedback article is here. Beware that SP1 is still in beta right now so avoid installing it on important production machines. Download is here.
What I would say is, write a quick deleter function for unique_ptr and use that for your resources. The only way I could see this code leaking is by throwing, but I don't see any places that throw. Once you remove that vulnerability, I don't see any leaks at all.
You have mentioned that the leak occurs 'some times' and not always. However, there is no branching in your code (specifically: branching with memory allocations) so either it should always cause the leak or never cause the leak. Moreover, as already mentioned in my comment, Memory is being allocated only at two place for memDc and bmp and you are properly cleaning up the resources for both the variables.
In simple words, I want to say that there is no leak in the above code :)
If there is actually a leak in your application, that would be in some other code path probably.

how to rotate a bitmap image in c++ using MFC?

how to rotate a bitmap image in c++ using MFC? i dont wanna use GDI. is it possible by only changing x and y values in this code?
CBitmap img;
CDC dc;
BITMAP bmp;
img.LoadBitmapW(IDB_BITMAP1);
img.GetBitmap(&bmp);
CDC* pDC = this->GetDC();
dc.CreateCompatibleDC(pDC);
CBitmap* pOld = dc.SelectObject(&img);
for(int y = 0; y < bmp.bmHeight; y++)
{
for(int x = 0; x < bmp.bmWidth; x++)
{
COLORREF rgb = dc.GetPixel(x, y);
BYTE r = GetRValue(rgb);
BYTE g = GetGValue(rgb);
BYTE b = GetBValue(rgb);
dc.SetPixel(x, y, RGB(r,g,b));
}
}
pDC->BitBlt(200, 200, bmp.bmWidth, bmp.bmHeight, &dc, 0, 0, SRCCOPY);
dc.SelectObject(pOld);
please someone reply soon, as this is the last day to work on project, tommorrow is its submission.
Asking about doing drawing with MFC but not using GDI is a bit like asking about how to go swimming without getting wet. As far as drawing goes, MFC is a thin wrapper around GDI, so anything you do with MFC gets translated quite directly to GDI with just a bit of syntactic sugar added (and in this area, the amount of syntactic sugar was based on a diabetic's diet).
That said, yes, exchanging x and y in your loops could do roughly the right thing (depending on the direction of rotation you want, for one thing) -- though in all honesty you should think really hard about scrapping that code completely. You're using SetPixel (i.e., GDI) to do the drawing in any case; there are lots better ways to do it than this (from the looks of things, you could benefit immensely from CreateDIBSection).

Reading an image file in C/C++ [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I need to read an image file in C/C++. It would be very great, if some one can post the code for me.
I work on gray scale images and the images are JPEG. I would like to read the images into a 2D array which will make my work easy.
If you decide to go for a minimal approach, without libpng/libjpeg dependencies, I suggest using stb_image and stb_image_write, found here.
It's as simple as it gets, you just need to place the header files stb_image.h and stb_image_write.h in your folder.
Here's the code that you need to read images:
#include <stdint.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
int main() {
int width, height, bpp;
uint8_t* rgb_image = stbi_load("image.png", &width, &height, &bpp, 3);
stbi_image_free(rgb_image);
return 0;
}
And here's the code to write an image:
#include <stdint.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define CHANNEL_NUM 3
int main() {
int width = 800;
int height = 800;
uint8_t* rgb_image;
rgb_image = malloc(width*height*CHANNEL_NUM);
// Write your code to populate rgb_image here
stbi_write_png("image.png", width, height, CHANNEL_NUM, rgb_image, width*CHANNEL_NUM);
return 0;
}
You can compile without flags or dependencies:
g++ main.cpp
Other lightweight alternatives include:
lodepng to read and write png files
jpeg-compressor to read and write jpeg files
You could write your own by looking at the JPEG format.
That said, try a pre-existing library like CImg, or Boost's GIL. Or for strictly JPEG's, libjpeg. There is also the CxImage class on CodeProject.
Here's a big list.
Check out Intel Open CV library ...
Check this thread out: read and write image file.
Also, have a look at this other question at Stackoverflow.
corona is nice. From the tutorial:
corona::Image* image = corona::OpenImage("img.jpg", corona::PF_R8G8B8A8);
if (!image) {
// error!
}
int width = image->getWidth();
int height = image->getHeight();
void* pixels = image->getPixels();
// we're guaranteed that the first eight bits of every pixel is red,
// the next eight bits is green, and so on...
typedef unsigned char byte;
byte* p = (byte*)pixels;
for (int i = 0; i < width * height; ++i) {
byte red = *p++;
byte green = *p++;
byte blue = *p++;
byte alpha = *p++;
}
pixels would be a one dimensional array, but you could easily convert a given x and y position to a position in a 1D array. Something like pos = (y * width) + x
Try out the CImg library. The tutorial will help you get familiarized. Once you have a CImg object, the data() function will give you access to the 2D pixel buffer array.
Check out the Magick++ API to ImageMagick.