C++: Modify same pointer using multiple threads - c++

I am attempting an experiment with processing images in which I am modifying the color in each pixel. I tried implementing my code using "buckets", in which I divide the image into smaller regions - each receiving a dedicated thread to process the image.
On my end, I do not really care if multiple threads are attempting to modify the same resource, in fact, that seems to be the point. Theoretically, the threads should be modifying different locations in memory in the form of pixels. When printing my results however, only the first tasks seems to iterate - leading me to think that some kind of race condition is occurring.
The function below is what manages the creation of each task, and
supplies it with starting coordinates and span to operate on. I
believe this is working fine, but it's here just for context:
Image*
CCManager::CCAsync(uint8_t bucketSize, Image* source,
const std::vector<float>& correction)
{
Image* newImg = new Image(); // This will contain our end result
newImg->resize(source->width(), source->height());
assert(buckets > 0);
// Now compute the width and height each bucket will render.
uint32_t width;
uint32_t height;
if(buckets == 2) // Each bucket takes a vertical rectangle
{
width = source->xSize()/2;
height = source->ySize();
}
else
{
// Set width and height to produce square grids (powers of 2)
// *** Not shown for Brevity ***
}
std::vector<std::thread> tasks; // The threads we are managing
// These coordinates will be fed as starting locations for each task
uint32_t startX = 0;
uint32_t startY = 0;
uint8_t tasksFinished = 0;
for(int i = 1; i <= buckets; ++i)
{
// Create a new task with a region for operation
tasks.emplace_back(std::thread(&CCManager::applyCCTask,this, startX, startY,
width, height, source, newImg, correction));
// No iteration is required for 1 bucket, simply paint the whole image
if(buckets == 1){break;}
// **** I REMOVED PART OF THE CODE THAT SHOWS WHERE EXPONENT
// IS DEFINED AND DETERMINED FOR BREVITY
// Reached last column, start a new row
if(i % exponent == 0)
{
startX = 0;
startY+= height;
}
// Keep incrementing horizontally
else
{
startX+= width;
}
}
while(tasksFinished < buckets)
{
// Join with whichever tasks finished
for(int i = 0; i < buckets; ++i)
{
if(tasks[i].joinable())
{
tasks[i].join();
tasksFinished++;
}
}
}
tasks.clear();
return newImg;
}
Having provided the new and source image pointers for each task, here they are in action.
The follow function retrieves the color in each pixel, and calls a
method that applies the correction accordingly.
void
CCManager::applyCCTask(uint32_t x, uint32_t y, uint32_t width, uint32_t height,
Image* source, Image* newImg,
const std::vector<float>& correction)
{
// ** THIS ACTUALLY PRINTS THE CORRECT COORDINATES AND REGION SPAN
// ** FOR EACH THREAD
printf("Task renders # (%i,%i) with %i x %i box\n", x,y,width,height);
assert(source);
assert(newImg);
for (; x < width; ++x )
{
for (; y < height; ++y)
{
Byte4 pixel = source->pixel (x, y);
Color color = pixel.color;
printf("Before correction: Pixel(%i,%i) color [%i,%i,%i]\n",x,y, pixel.color[0], pixel.color[1], pixel.color[2]);
Color correctedColor= addCorrectionToColor( color, correction);
Byte4* newPixel= &newImg->pixel( x, y );
newPixel->color[0] = correctedColor[0];
newPixel->color[1] = correctedColor[1];
newPixel->color[2] = correctedColor[2];
printf("After correction: Pixel(%i,%i) color [%i,%i,%i]\n",x,y, newImg->pixel( x, y ).color[0], newImg->pixel( x, y ).color[1], newImg->pixel( x, y ).color[2]);
}
}
printf("Task Finished!\n");
}
With the code shown, all tasks end up printing the starting message with their area of operation, but inside the nested loop, the "Before" and "After" messages seem to only print from ONE task only.
Why am I not allowed to modify the same image from multiple threads even though the actual pixel data being modified is different for each thread? Can I circumvent that without adding resource locks such as a mutexes, the whole point of this experiment was to allow each thread to run independently without any hindrance.

Related

C++ code for Microsoft Kinect - trying to dynamically allocate array of target positions

So I'm trying to modify the Kinect BodyBasicsD2D code so that a fixed number of "target positions" appear on the screen (as ellipses) for the user to move his hand toward. I'm having trouble creating the initial target positions.
This is my code in the header file for the allocation of the array of target positions (these are a public field of the CBodyBasics class, already built into the original BodyToBasics program):
D2D1_POINT_2F* targetPositions = NULL;
int numTargets = 3;
Then I have a function "GenerateTargetPositions" which is supposed to generate 3, in this case, target positions to be passed into the "DrawTargetPositions" function.
void CBodyBasics::GenerateTargetPositions(D2D1_POINT_2F * targetPositions, int numTargets)
{
targetPositions = new D2D1_POINT_2F[numTargets];
RECT rct;
GetClientRect(GetDlgItem(m_hWnd, IDC_VIDEOVIEW), &rct);
int width = rct.right;
int height = rct.bottom;
FLOAT x;
FLOAT y;
D2D1_POINT_2F tempPoint;
for (int i = 0; i < numTargets; i++) {
x = 1.0f*i*width / numTargets;
y = 1.0f*i*height / numTargets;
tempPoint = D2D1::Point2F(x, y);
targetPositions[i] = tempPoint;
}
}
My DrawTargetPositions function is:
void CBodyBasics::DrawTargetPositions(D2D1_POINT_2F * targetPositions, int numTargets)
{
D2D1_ELLIPSE ellipse;
for (int i = 0; i < numTargets; i++)
{
ellipse = D2D1::Ellipse(targetPositions[i], 50.f, 50.f);
m_pRenderTarget->FillEllipse(ellipse, m_pSilverBrush);
}
}
When I try to run my code, I get the error that both "targetPositions" and "targetPositions[i]" is NULL (and thus my GenerateTargetPositions function must not be working properly). I believe that targetPositions[i] is a struct (a point with x and y values) so I am wondering if this may be the reason for my errors.
I call GenerateTargetPositions and DrawTargetPositions before the main "while" loop in my code so that each function is not being called on each iteration (there are many iterations of through the while loop because this is an interactive Microsoft Kinect, recording one's movements).
Any suggestions and advice would be greatly appreciated. Thanks so much!

shrink image c++ - 'System.AccessViolationException'

I have a project where we have to develop some image processing functions. One of the functions is shrinking an image.
this is the description of the function
void averageRegions(int blockWidth, int blockHeight)
INPUTS: Integers indicating the width and height of the blocks?to be averaged
OUTPUTS: NONE
When this function is called, you should create a new image that will consist of 1 pixel for every block of size
blockWidth by blockHeight pixels in the original image, with each pixel being the average color of the pixels in that
region in the original image.
Please note that it may be easier if you split this into 2 functions and call your helper function from within this one.
The second function could then just calculate the average value of a block of pixels given to it, and return that
to the original function to be used. However, this implementation is up to you! Complete it as you see fit.
I have completed the code of it however after closing the app I get this error
An unhandled exception of type 'System.AccessViolationException' occurred in MCS2514Pgm2.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
or this one
Heap Corruption Detected: after Normal block (#126) at 0x004cF6c0 CRT detected that the application wrote to memory after end of heap bugger.
This is the function code
void averageRegions(int blockWidth, int blockHeight)
{
//please add the code
int height = inImage.getHeight();
int width = inImage.getWidth();
pixel** myPixels = inImage.getPixels();
pixel* pixelptr;
int Rsum = 0, Gsum = 0, Bsum = 0;
int Ravg, Gavg, Bavg, pcount = 0, m, n;
outImage.createNewImage(width/blockWidth, height/blockHeight);
pixel** outPixels = outImage.getPixels();
//pixelptr = &myPixels[0][4];
for(int x = 0; x < height; x +=blockHeight)
{
for(int y = 0; y < width; y += blockWidth)
{
for(int i = x; i < blockHeight+x; i++)
{
for(int j = y; j < blockWidth+y; j++)
{
Rsum += myPixels[i][j].red;
Gsum += myPixels[i][j].green;
Bsum += myPixels[i][j].blue;
pcount++;
}
}
Ravg = Rsum/pcount;
Gavg = Gsum/pcount;
Bavg = Bsum/pcount;
for(int i = x; i < blockHeight+x; i++)
{
for(int j = y; j < blockWidth+y; j++)
{
myPixels[i][j].red = Ravg;
myPixels[i][j].green = Gavg;
myPixels[i][j].blue = Bavg;
m = x/blockHeight;
n = y/blockWidth;
outPixels[m][n].red = myPixels[i][j].red;
outPixels[m][n].green = myPixels[i][j].green;
outPixels[m][n].blue = myPixels[i][j].blue;
}
}
pcount=0;
Rsum = 0;
Gsum = 0;
Bsum = 0;
}
}
inImage = outImage;
}
this is the image.h
#ifndef IMAGE
#define IMAGE
#include <atlimage.h>
#include <string>
#include <cstdlib>
#include "globals.h"
#include "pixel.h"
using namespace std;
class image {
public:
image(); //the image constructor (initializes everything)
image(string filename); //a image constructor that directly loads an image from disk
~image(); //the image destructor (deletes the dynamically created pixel array)
void createNewImage(int width, int height); //this function deletes any current image data and creates a new blank image
//with the specified width/height and allocates the needed number of pixels
//dynamically.
bool loadImage(string filename); //load an image from the specified file path. Return true if it works, false if it is not a valid image.
//Note that we only accept images of the RGB 8bit colorspace!
void saveImage(string filename); //Save an image to the specified path
pixel** getPixels(); //return the 2-dimensional pixels array
int getWidth(); //return the width of the image
int getHeight(); //return the height of the image
void viewImage(CImage* myImage); //This function is called by the windows GUI. It returns the image in format the GUI understands.
private:
void pixelsToCImage(CImage* myImage); //this function is called internally by the image class.
//it converts our pixel struct array to a standard BGR uchar array with word spacing.
//(Don't worry about what this does)
pixel** pixels; // pixel data array for image
int width, height; // stores the image dimensions
};
#endif
And this is Pixel.h
#ifndef PIXEL_H
#define PIXEL_H
class pixel
{
public:
unsigned char red; //the red component
unsigned char green; //the green component
unsigned char blue; //the blue component
};
#endif
Can any one tell me why I am getting this error
In addition:
the error is taking me to this line in dbgdel.cpp
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
This error occurs because you are accessing outside of memory allocated for an array. There are several places in your code where this can happen.
If height is not a multiple of blockHeight, or width is not a multiple of blockWidth, your i/j loops will access elements outside of the memory allocated for myPixels.
Another possibility is when writing to outPixels if blockHeight and blockWidth are not equal. Your computation of m and n may have the blockHeight and blockWidth swapped (you're dividing x by blockHeight).
In
for (int x = 0; x < height; x += blockHeight)
say height is 100 and blockHeight is 33
x == 0. 0 < 100, so the body is entered and iterates 0 -> 32
x == 33. 33 < 100, so the body is entered and iterates 33 -> 65
x == 66. 66 < 100, so the body is entered and iterates 66 -> 98
x == 99. 99 < 100, so the body is entered and iterates 99 -> 131
Sadly there is no 100 -> 131.

SDL - drawing 'negative' circles (Fog of War)

I have this 800x600square I want to draw to the screen. I want to 'cut' circles in it (where alpha would be 0). Basically I'm drawing this whole rectangle over a map so in these 'circles' I drew, you can see the map, otherwise you see the grey square
So, I assume you're trying to add fog of war to one of you game?
I had a small demo I made for a local University a few weeks ago to show A* pathfinding, so I thought I could add fog of war to it for you. Here's the results:
Initial map
First, you start with a complete map, totally visible
Fog
Then, I added a surface to cover the entire screen (take note that my map is smaller than the screen, so for this case I just added fog of war on the screen, but if you have scrolling, make sure it covers each map pixel 1:1)
mFogOfWar = SDL_CreateRGBSurface(SDL_HWSURFACE, in_Width, in_Height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
SDL_Rect screenRect = {0, 0, in_Width, in_Height};
SDL_FillRect(mFogOfWar, &screenRect, 0xFF202020);
Then, you need to draw it... I added this call after drawing the game objects and before drawing the UI
DrawSurface(mFogOfWar, 0, 0);
Where
void RenderingManager::DrawSurface(SDL_Surface* in_Surface, int in_X, int in_Y)
{
SDL_Rect Dest = { in_X, in_Y, 0, 0 };
SDL_BlitSurface(in_Surface, NULL, mScreen, &Dest);
}
Which should give you the following result:
"Punch Surface"
I then created a 32 bits .png that looks like this (checkerboard shows alpha)
When rendering my main character, I added this call:
gRenderingManager.RemoveFogOfWar(int(mX) + SPRITE_X_OFFSET, int(mY) + SPRITE_Y_OFFSET);
The offset is only there to center the punch with the sprite, basically, what I'm passing to RemoveFogOfWar is the center of my sprite.
Remove Fog Of War
Now the meat of the fog of war. I did two versions, one where Fog of War is removed permanently and one where the fog of war is reset. My fog of war reset relies on my punch surface to have a contour where the alpha is reset to 0 and the fact that my character moves of less pixels than the contour contains per frame, otherwise I would keep the Rect where my punch was applied and I would refill it before drawing again the new punch.
Since I couldn't find a "multiply" blend with SDL, I decided to write a simple function that iterates on the punch surface and updates the alpha on the fog of war surface. The most important part is to make sure you stay within the bounds of your surfaces, so it takes up most of the code... there might be some crop functions but I didn't bother checking:
void RenderingManager::RemoveFogOfWar(int in_X, int in_Y)
{
const int halfWidth = mFogOfWarPunch->w / 2;
const int halfHeight = mFogOfWarPunch->h / 2;
SDL_Rect sourceRect = { 0, 0, mFogOfWarPunch->w, mFogOfWarPunch->h };
SDL_Rect destRect = { in_X - halfWidth, in_Y - halfHeight, mFogOfWarPunch->w, mFogOfWarPunch->h };
// Make sure our rects stays within bounds
if(destRect.x < 0)
{
sourceRect.x -= destRect.x; // remove the pixels outside of the surface
sourceRect.w -= sourceRect.x; // shrink to the surface, not to offset fog
destRect.x = 0;
destRect.w -= sourceRect.x; // shrink the width to stay within bounds
}
if(destRect.y < 0)
{
sourceRect.y -= destRect.y; // remove the pixels outside
sourceRect.h -= sourceRect.y; // shrink to the surface, not to offset fog
destRect.y = 0;
destRect.h -= sourceRect.y; // shrink the height to stay within bounds
}
int xDistanceFromEdge = (destRect.x + destRect.w) - mFogOfWar->w;
if(xDistanceFromEdge > 0) // we're busting
{
sourceRect.w -= xDistanceFromEdge;
destRect.w -= xDistanceFromEdge;
}
int yDistanceFromEdge = (destRect.y + destRect.h) - mFogOfWar->h;
if(yDistanceFromEdge > 0) // we're busting
{
sourceRect.h -= yDistanceFromEdge;
destRect.h -= yDistanceFromEdge;
}
SDL_LockSurface(mFogOfWar);
Uint32* destPixels = (Uint32*)mFogOfWar->pixels;
Uint32* srcPixels = (Uint32*)mFogOfWarPunch->pixels;
static bool keepFogRemoved = false;
for(int x = 0; x < destRect.w; ++x)
{
for(int y = 0; y < destRect.h; ++y)
{
Uint32* destPixel = destPixels + (y + destRect.y) * mFogOfWar->w + destRect.x + x;
Uint32* srcPixel = srcPixels + (y + sourceRect.y) * mFogOfWarPunch->w + sourceRect.x + x;
unsigned char* destAlpha = (unsigned char*)destPixel + 3; // fetch alpha channel
unsigned char* srcAlpha = (unsigned char*)srcPixel + 3; // fetch alpha channel
if(keepFogRemoved == true && *srcAlpha > 0)
{
continue; // skip this pixel
}
*destAlpha = *srcAlpha;
}
}
SDL_UnlockSurface(mFogOfWar);
}
Which then gave me this with keepFogRemoved = false even after the character had moved around
And this with keepFogRemoved = true
Validation
The important part is really to make sure you don't write outside of your pixel buffer, so watch out with negative offsets or offsets that would bring you out of the width or height. To validate my code, I added a simple call to RemoveFogOfWar when the mouse is clicked and tried corners and edges to make sure I didn't have a "off by one" problem
case SDL_MOUSEBUTTONDOWN:
{
if(Event.button.button == SDL_BUTTON_LEFT)
{
gRenderingManager.RemoveFogOfWar(Event.button.x, Event.button.y);
}
break;
}
Notes
Obviously, you don't need a 32 bits texture for the "punch", but it was the clearest way I could think of to show you how to do it. It could be done using as little as 1 bit per pixel (on / off). You can also add some gradient, and change the
if(keepFogRemoved == true && *srcAlpha > 0)
{
continue; // skip this pixel
}
To something like
if(*srcAlpha > *destAlpha)
{
continue;
}
To keep a smooth blend like this:
3 State Fog of War
I thought I should add this... I added a way to create a 3 state fog of war: visible, seen and fogged.
To do this, I simply keep the SDL_Rect of where I last "punched" the fog of war, and if the alpha is lower than a certain value, I clamp it at that value.
So, by simply adding
for(int x = 0; x < mLastFogOfWarPunchPosition.w; ++x)
{
for(int y = 0; y < mLastFogOfWarPunchPosition.h; ++y)
{
Uint32* destPixel = destPixels + (y + mLastFogOfWarPunchPosition.y) * mFogOfWar->w + mLastFogOfWarPunchPosition.x + x;
unsigned char* destAlpha = (unsigned char*)destPixel + 3;
if(*destAlpha < 0x60)
{
*destAlpha = 0x60;
}
}
}
mLastFogOfWarPunchPosition = destRect;
right before the loop where the fog of war is "punched", I get a fog of war similar to what you could have in games like StarCraft:
Now, since the "seen" fog of war is semi transparent, you will need to tweak your rendering method to properly clip "enemies" that would be in the fog, so you don't see them but you still see the terrain.
Hope this helps!

allocating memory per thread in a parallel_for loop

I originally have a single-threaded loop which iterates over all pixels of an image and may do various operation with the data.
The library I am using dictates that retrieving pixels from an image must be done one line at a time. To this end I malloc a block of memory which can host one row of pixels (BMM_Color_fl is a struct containing one pixel's RGBA data as four float values, and GetLinearPixels() copies one row of pixels from a bitmap into a BMM_Color_fl array.)
BMM_Color_fl* line = (BMM_Color_fl*)malloc(width * sizeof(BMM_Color_fl));
for (int y = 0; y < height, y++)
{
bmp->GetLinearPixels(0, y, width, line); //Copy data of row Y from bitmap into line.
BMM_Color_fl* pixel = line; //Get first pixel of line.
for (int x = 0; x < width; x++, pixel++) // For each pixel in the row...
{
//Do stuff with a pixel.
}
}
free(line);
So far so good!
For the sake of reducing execution time of this loop, I have written a concurrent version using parallel_for, which looks like this:
parallel_for(0, height, [&](int y)
{
BMM_Color_fl* line = (BMM_Color_fl*)malloc(width * sizeof(BMM_Color_fl));
bmp->GetLinearPixels(0, y, width, line);
BMM_Color_fl* pixel = line;
for (int x = 0; x < width; x++, pixel++)
{
//Do stuff with a pixel.
}
free(line);
});
While the multithreaded loop is already faster than the original, I realize it is impossible for all threads to use the same memory block, so currently I am allocating and freeing the memory at each loop iteration, which is obviously wasteful as there will never be more threads than loop iterations.
My question is if and how can I have each thread malloc exactly one line buffer and use it repeatedly (and ideally, free it at the end)?
As a disclaimer I must state I am a novice C++ user.
Implementation of suggested solutions:
Concurrency::combinable<std::vector<BMM_Color_fl>> line;
parallel_for(0, height, [&] (int y)
{
std::vector<BMM_Color_fl> lineL = line.local();
if (lineL.capacity() < width) lineL.reserve(width);
bmp->GetLinearPixels(0, y, width, &lineL[0]);
for (int x = 0; x < width; x++)
{
BMM_Color_fl* pixel = &lineL[x];
//Do stuff with a pixel.
}
});
As suggested, I canned the malloc and replaced it with a vector+reserve.
You can use Concurrency::combinable class to achieve this.
I am lazy to post the code, but I am sure it is possible.
Instead of having each thread call parallel_for() have them call another function which allocates the memory, calls parallel_for(), and then frees the memory.

Can someone explain how I am to access this array? (image processing program)

I am working on the implementation of functions for an already written image processing program. I am given explanations of functions, but not sure how they are designating pixels of the image.
In this case, I need to flip the image horizontally, i.e., rotates 180 degrees around the vertical axis
Is this what makes the "image" i am to flip?
void Image::createImage(int width_x, int height_y)
{
width = width_x;
height = height_y;
if (pixelData!=NULL)
freePixelData();
if (width <= 0 || height <= 0) {
return;
}
pixelData = new Color* [width]; // array of Pixel*
for (int x = 0; x < width; x++) {
pixelData[x] = new Color [height]; // this is 2nd dimension of pixelData
}
}
I do not know if all the functions I have written are correct.
Also, the Image class calls on a Color class
So to re-ask: what am I "flipping" here?
Prototype for function is:
void flipLeftRight();
As there is no input into the function, and I am told it modifies pixelData, how do I flip left to right?
A quick in place flip. Untested, but the idea is there.
void flipHorizontal(u8 *image, u32 width, u32 height)
{
for(int i=0; i < height; i++)
{
for(int j=0; j < width/2; j++)
{
int sourceIndex = i * width + j;
int destIndex = (i+1) * width - j - 1;
image[sourceIndex] ^= image[destIndex];
image[destIndex] ^= image[sourceIndex];
image[sourceIndex] ^= image[destIndex];
}
}
}
well, the simplest approach would be to read it 1 row at a time into a temporary buffer the same size as 1 row.
Then you could use something like std::reverse on the temporary buffer and write it back.
You could also do it in place, but this is the simplest approach.
EDIT: what i;ve described is a mirror, not a flip, to mirror you also need to reverse the order of the rows. Nothing too bad, to do that I would create a buffer the same size as the image, copy the image and then write it back with the coordinates adjusted. Something like y = height - x and x = width - x.