(computer graphics) radial image distortion - graphics

I need to create an effect, that radially distorts a bitmap, by stretching or shrinking its "layers of pixels" radially (as shown on the image):
http://i.stack.imgur.com/V6Voo.png
by colored circles (their thickness) is shown the transform, that is applied to the image
What approach should I take? I have a bitmap (array of pixels) and an another bitmap, that should be the result of such a filter applied (as a result, there should be some kind of a round water ripple on the bitmap).
Where could I read about creating such effects?
Thank you.

Try to look here
http://www.jhlabs.com/ip/blurring.html
Zoom and Spin Blur
it is Java but nevertheless it could be fit to your request.

Well, the most accurate results would come from mapping the euclidean coordinates to a polar matrix. Then you would very easily be able to stretch them out. Then just translate them back to a euclidean representation and save. I'll write and edit with some code in a second.
Alright I got a bit carried away but here's my code. It will take a bitmap, convert it to and from polar coordinates and save it. now, radial based distortion should be a breeze.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define PI 3.141592654
#define C_R 1000
#define C_S 1000
#define C_M 2000
typedef struct{ int r,g,b; } color;
typedef struct{ int t; color* data; int w, h; } bitmap;
typedef struct{ int t; color* data; int r, s, w, h; } r_bitmap;
bitmap* bmp_load_from_file( const char* fname ){
FILE* b = fopen( fname, "rb" );
if( b <= 0 ) return 0;
int num;
fscanf( b, "BM%n", &num );
if( num < 2 ) return 0;
struct{ int size, reserved, offset;
int hsize, wid, hig, planes:16, bpp:16, comp, bmpsize, hres, vres, colors, important; } head;
fread( &head, 13, 4, b );
bitmap* bmp = malloc( sizeof( bitmap ) );
bmp->data = malloc( head.wid * head.hig * sizeof( color ) );
bmp->w = head.wid;
bmp->h = head.hig;
for( int y = head.hig - 1; y >= 0; --y ){
int x;
for( x = 0; x < head.wid; ++x ){
color t;
t.r = fgetc( b );
t.g = fgetc( b );
t.b = fgetc( b );
bmp->data[x+y*bmp->w] = t;
}
x*=3;
while( x%4 != 0 ){
++x;
fgetc( b );
}
}
bmp->t = 0;
fclose( b );
return bmp;
}
void bmp_save( const char* fname, bitmap* bmp ){
FILE* b = fopen( fname, "wb" );
if( b <= 0 ) return 0;
struct{ int size, reserved, offset;
int hsize, wid, hig, planes:16, bpp:16, comp, bmpsize, hres, vres, colors, important; } head;
fprintf( b, "BM" );
head.size = 3 * (bmp->w+4)/4*4 * bmp->h + 54;
head.offset = 54;
head.hsize = 40;
head.wid = bmp->w;
head.hig = bmp->h;
head.planes = 1;
head.bpp = 24;
head.comp = 0;
head.bmpsize = 3 * (bmp->w+4)/4*4 * bmp->h;
head.hres = 72;
head.vres = 72;
head.colors = 0;
head.important = 0;
fwrite( &head, 13, 4, b );
for( int y = bmp->h - 1; y >= 0; --y ){
int x;
for( x = 0; x < bmp->w; ++x ){
fputc( bmp->data[x + y * bmp->w].r, b );
fputc( bmp->data[x + y * bmp->w].g, b );
fputc( bmp->data[x + y * bmp->w].b, b );
}
x*=3;
while( x % 4 != 0 ){
++x;
fputc(0, b);
}
}
fclose( b );
}
color color_mix( color a, color b, int offset ){ /*offset is a value between 0 and 255 to determine the weight. the lower it is the more color a gets*/
//if( offset > 255 || offset < 0)
//printf("%i\t", offset);
a.r += ( b.r - a.r ) * offset / 255;
a.g += ( b.g - a.g ) * offset / 255;
a.b += ( b.b - a.b ) * offset / 255;
return a;
}
r_bitmap* bmp_to_r( bitmap* b ){
r_bitmap* r = malloc( sizeof( r_bitmap ) );
r->t = 1;
int radius = sqrt( b->w * b->w + b->h * b->h ) / 2 * C_R / C_M + 2;
int step = C_S * ( b->w + b->h ) / C_M;
r->data = malloc( radius * step * sizeof( color ) );
r->r = radius;
r->s = step;
r->w = b->w;
r->h = b->h;
color black = {0, 0, 0};
for( double i = 0; i < radius; ++ i ){
for( double j = 0; j < step; ++j ){
double x = i * C_M * cos( 2 * PI * j / step ) / C_R + b->w / 2;
double y = i * C_M * sin( 2 * PI * j / step ) / C_R + b->h / 2;
int ix = x;
int iy = y;
if( x < 0 || x >= b->w || y < 0 || y >= b->h )
r->data[(int)(j + i * step)] = black;
else{
color tmp = b->data[ix + iy * b->w];
if( iy < b->h - 1 ){
int off = 255 * (y - iy);
tmp = color_mix( tmp, b->data[ix + (iy+1) * b->w], off );
}
if( ix < b->w - 1 ){
int off = 255 * ( x - ix );
tmp = color_mix( tmp, b->data[ix +1 + iy * b->w], off );
}
r->data[(int)(j + i * step)] = tmp;
}
}
}
return r;
}
bitmap* bmp_from_r( r_bitmap* r ){
bitmap* b = malloc( sizeof( bitmap ) );
b->t = 0;
b->data = malloc( r->w * r->h * sizeof( color ) );
b->w = r->w;
b->h = r->h;
for( int y = 0; y < b->h; ++y ){
for( int x = 0; x < b->w; ++x ){
int tx = x - b->w/2;
int ty = y - b->h/2;
double rad = sqrt( tx*tx+ty*ty ) * C_R / C_M;
double s = atan2( ty, tx );
if( s < 0 ) s += 2 * PI;
s *= r->s / ( 2 * PI );
int is = s;
int irad = rad;
color tmp = r->data[(int)(is + irad * r->s)];
/*if( x > 0 && x < r->w - 1 && y > 0 && y < r->h - 1 ){
tmp = color_mix(tmp, r->data[((int)(is+1)%r->s + irad * r->s)], abs(255* rad - floor(rad)));
tmp = color_mix(tmp, r->data[(is + (irad + 1) * r->s)], abs(255* s - floor(s)));
}*/
b->data[x+y*b->w] = tmp;
}
}
return b;
}
int main( ) {
bitmap* b = bmp_load_from_file( "foo.bmp" );
r_bitmap* r = bmp_to_r( b );
bitmap* c = bmp_from_r( r );
bmp_save( "lol.bmp", c );
}

Related

Multithreaded Nagel–Schreckenberg model (traffic simulation) with OpenMP

I'm trying to write a multithreaded Nagel–Schreckenberg model simulation in c language and have some problems when a thread accesses the data which wasn't calculated yet.
Here is a working code which only parallelizes velocity calculation per line:
#define L 3000 // number of cells in row
#define num_iters 3000 // number of iterations
#define density 0.48 // how many positives
#define vmax 2
#define p 0.2
for (int i = 0; i < num_iters - 1; i++)
{
int temp[L] = {0};
#pragma omp parallel for
for (int x = 0; x < L; x++)
{
if (iterations[i][x] > -1)
{
int vi = iterations[i][x]; // velocity of previews iteration
int d = 1; // index of the next vehicle
while (iterations[i][(x + d) % L] < 0)
d++;
int vtemp = min(min(vi + 1, d - 1), vmax); // increase speed, but avoid hitting the next car
int v = r2() < p ? max(vtemp - 1, 0) : vtemp; // stop the vehicle with probability p
temp[x] = v;
}
}
for (int x = 0; x < L; x++) // write the velocities to the next line
{
if (iterations[i][x] > -1)
{
int v = temp[x];
iterations[i + 1][(x + v) % L] = v;
}
}
}
This works fine, but it's not fast enough. I'm trying to use convolution to increase the performance, but it can't read neighbor thread's data half of the time because it wasn't calculated yet. Here is the code I used:
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <sys/time.h>
#define L 4000 // number of cells in row
#define num_iters 4000 // number of iterations
#define density 0.48 // how many positives
#define vmax 2
#define p 0.2
#define BLOCKS_Y 4
#define BLOCKS_X 4
#define BLOCKSIZEY (L / BLOCKS_Y)
#define BLOCKSIZEX (L / BLOCKS_X)
time_t t;
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
#endif
void shuffle(int *array, size_t n)
{
if (n > 1)
{
size_t i;
for (i = 0; i < n - 1; i++)
{
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
double r2()
{
return (double)rand() / (double)RAND_MAX;
}
void writeImage(int *iterations[], char filename[])
{
int h = L;
int w = num_iters;
FILE *f;
unsigned char *img = NULL;
int filesize = 54 + 3 * w * h;
img = (unsigned char *)malloc(3 * w * h);
memset(img, 0, 3 * w * h);
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
int x = i;
int y = (h - 1) - j;
int color = iterations[i][j] == 0 ? 0 : 255;
img[(x + y * w) * 3 + 2] = (unsigned char)(color);
img[(x + y * w) * 3 + 1] = (unsigned char)(color);
img[(x + y * w) * 3 + 0] = (unsigned char)(color);
}
}
unsigned char bmpfileheader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0};
unsigned char bmpinfoheader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0};
unsigned char bmppad[3] = {0, 0, 0};
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
bmpinfoheader[4] = (unsigned char)(w);
bmpinfoheader[5] = (unsigned char)(w >> 8);
bmpinfoheader[6] = (unsigned char)(w >> 16);
bmpinfoheader[7] = (unsigned char)(w >> 24);
bmpinfoheader[8] = (unsigned char)(h);
bmpinfoheader[9] = (unsigned char)(h >> 8);
bmpinfoheader[10] = (unsigned char)(h >> 16);
bmpinfoheader[11] = (unsigned char)(h >> 24);
f = fopen(filename, "wb");
fwrite(bmpfileheader, 1, 14, f);
fwrite(bmpinfoheader, 1, 40, f);
for (int i = 0; i < h; i++)
{
fwrite(img + (w * (h - i - 1) * 3), 3, w, f);
fwrite(bmppad, 1, (4 - (w * 3) % 4) % 4, f);
}
free(img);
fclose(f);
}
void simulation()
{
printf("L=%d, num_iters=%d\n", L, num_iters);
int z = 0;
z++;
int current_index = 0;
int success_moves = 0;
const int cars_num = (int)(density * L);
int **iterations = (int **)malloc(num_iters * sizeof(int *));
for (int i = 0; i < num_iters; i++)
iterations[i] = (int *)malloc(L * sizeof(int));
for (int i = 0; i < L; i++)
{
iterations[0][i] = i <= cars_num ? 0 : -1;
}
shuffle(iterations[0], L);
for (int i = 0; i < num_iters - 1; i++)
for (int x = 0; x < L; x++)
iterations[i + 1][x] = -1;
double *randoms = (double *)malloc(L * num_iters * sizeof(double));
for (int i = 0; i < L * num_iters; i++) {
randoms[i] = r2();
}
#pragma omp parallel for collapse(2)
for (int blocky = 0; blocky < BLOCKS_Y; blocky++)
{
for (int blockx = 0; blockx < BLOCKS_X; blockx++)
{
int ystart = blocky * BLOCKSIZEY;
int yend = ystart + BLOCKSIZEY;
int xstart = blockx * BLOCKSIZEX;
int xend = xstart + BLOCKSIZEX;
for (int y = ystart; y < yend; y++)
{
for (int x = xstart; x < xend; x++)
{
if (iterations[y][x] > -1)
{
int vi = iterations[y][x];
int d = 1;
int start = (x + d) % L;
int i;
for (i = start; i < L && iterations[y][i] < 0; ++i);
d += i - start;
if (i == L)
{
for (i = 0; i < start && iterations[y][i] < 0; ++i);
d += i;
}
int vtemp = min(min(vi + 1, d - 1), vmax);
int v = randoms[x * y] < p ? max(vtemp - 1, 0) : vtemp;
iterations[y + 1][(x + v) % L] = v;
}
}
}
}
}
if (L <= 4000)
writeImage(iterations, "img.bmp");
free(iterations);
}
void main() {
srand((unsigned)time(&t));
simulation();
}
As you can see, as the second block gets calculated the first one didn't probably calculate yet which produces that empty space.
I think it's possible to solve this with the convolution, but I'm just doing something wrong and I'm not sure what. If you could give any advice on how to fix this problem, I would really appreciate it.
There is a race condition in the second code because iterations can be read by a thread and written by another. More specifically, iterations[y + 1][(x + v) % L] = v set a value that another thread should read when checking iterations[y][x] or iterations[y][(x + d) % L] when two threads are working on consecutive y values (of two consecutive blocky values).
Moreover, the r2 function have to be thread-safe. It appears to be a random number generator (RNG), but such random function is generally implemented using global variables that are often not thread-safe. One simple and efficient solution is to use thread_local variables instead. An alternative solution is to explicitly pass in parameter a mutable state to the random function. The latter is a good practice when you design parallel applications since it makes visible the mutation of an internal state and it provides way to better control the determinism of the RNG.
Besides this, please note that modulus are generally expensive, especially if L is not a compile-time constant. You can remove some of them by pre-computing the remainder before a loop or splitting a loop so to perform checks only near the boundaries. Here is an (untested) example for the while:
int start = (x + d) % L;
int i;
for(i=start ; i < L && iterations[y][i] < 0 ; ++i);
d += i - start;
if(i == L) {
for(i=0 ; i < start && iterations[y][i] < 0 ; ++i);
d += i;
}
Finally, please note that the blocks should be divisible by 4. Otherwise, the current code is not valid (a min/max clamping is likely needed).

How to make function call other like callback

Heres what I want (image):
Main Idea is:
InputField is a function that calls something if input value changed.
For example: you have text input field in game and you add text to it, when value doesnt change until like 1 second it will call code like g_Engine.ChangeName()
Heres also callback class, but I dont know how to do it still please help
Code:
typedef void (*fn_callback)(void);
class pCallback
{
public:
pCallback(fn_callback callback);
fn_callback callback_void{ nullptr };
};
class CMenu
{
private:
void InputField(int x, int y, char* text, int maxLen, int& out, ...);
};
extern CMenu g_Menu;
void CMenu::InputField(int x, int y, char* text, int maxLen, int& out, ...)
{
unsigned int w = 220;
unsigned int h = 16;
g_pISurface->DrawSetColor(cvar.cheat_global_color_r, cvar.cheat_global_color_g, cvar.cheat_global_color_b, 255);
g_pISurface->DrawOutlinedRect(x - 2, y - 2, x + w + 2, y + h + 2);
bool clicked = false;
static DWORD dwTemporaryBlockTimer = 0;
static std::string value;
if (GetTickCount() - dwPaletteBlockedTime > 200 && GetTickCount() - dwListBlockedTime > 200 && !bCursorInPalette && !bCursorInList && keys[VK_LBUTTON] && !IsDragging && CursorX >= x && CursorX <= x + w && CursorY >= y && CursorY <= y + h)
{
if (GetTickCount() - dwTemporaryBlockTimer > 200)
{
clicked = true;
dwTemporaryBlockTimer = GetTickCount();
}
}
if (clicked || CursorX >= x && CursorX <= x + w && CursorY >= y && CursorY <= y + h)
{
g_pISurface->DrawSetColor(cvar.cheat_global_color_r, cvar.cheat_global_color_g, cvar.cheat_global_color_b, 255);
g_pISurface->DrawOutlinedRect(x - 1, y - 1, x + w + 1, y + h + 1);
}
if (text)
g_Drawing.DrawString(MENU, x + 1, y - 10, 215, 215, 215, 255, FONT_LEFT, text);
if (GetTickCount() - dwInputfieldBlockedTime > 200 && !bCursorInPalette && !bCursorInList && !IsDragging && CursorX >= x && CursorX <= x + w && CursorY >= y && CursorY <= y + h)
{
if (maxLen != 0)
{
if (!(value.length() > maxLen))
value.append(GetPressedNumKeyString());
}
if (keys[VK_BACK])
{
if (!value.empty())
value.erase(std::prev(value.end()));
}
dwInputfieldBlockedTime = GetTickCount();
}
int iVal = std::atoi(value.c_str());
if (out != iVal)
out = iVal;
if (!value.empty())
g_Drawing.DrawString(MENU, x + w / 2, y + (h / 2), 220, 220, 220, 255, FONT_CENTER, value.c_str());
else
g_Drawing.DrawString(MENU, x + w / 2, y + (h / 2), 81, 81, 81, 255, FONT_CENTER, "N/A");
}
I think I did it
void CMenu::InputField(int x, int y, char* text, int maxLen, int& out, std::function<void()>&& Callback)
{
if (out != iVal)
{
out = iVal;
Callback();
}
}
InputField(x + box_indent_x, y + line_y, "SteamID", 31, SID, []() { g_SteamID.Apply(SID); });

CS50 Pset4 Sepia Filter, where is the bug? The code doesn't pass the CS50 tests

So this is the code I have for Pset4 for the Sepia filter...it's heading in the right direction but I've been trying to figure out why it isn't passing the tests. Cannot filter a simple 3 x 3 image or complex 3 x 3 image or the 4 x 4 image. Trying to figure out where the bug is, any tips would be wonderful!
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// get values of each colour in the image
int red = image[i][j].rgbtRed;
int blue = image[i][j].rgbtBlue;
int green = image[i][j].rgbtGreen;
// find average of the pixel RBG colors
float average = (round(red) + round(blue) + round(green)) / 3;
average = round(average);
//puts the value average into the pixel colors
image[i][j].rgbtRed = average;
image[i][j].rgbtBlue = average;
image[i][j].rgbtGreen = average;
}
}
return;
}
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
//gets the values of each color in the image
int red = image[i][j].rgbtRed;
int blue = image[i][j].rgbtBlue;
int green = image[i][j].rgbtGreen;
// gets the sepia value of the pixels
int sepiaRed = round(0.393 * red + 0.769 * green + 0.189 * blue);
int sepiaGreen = round(0.349 * red + 0.686 * green + 0.168 * blue);
int sepiaBlue = round(0.272 * red + 0.534 * green + 0.131 * blue);
if (sepiaRed >= 256)
{
sepiaRed = 255;
}
if (sepiaGreen >= 256)
{
sepiaGreen = 255;
}
if (sepiaBlue >= 256)
{
sepiaBlue= 255;
}
image[i][j].rgbtRed = sepiaRed;
image[i][j].rgbtBlue = sepiaBlue;
image[i][j].rgbtGreen = sepiaGreen;
}
return;
}
}
I'm not sure, without seeing more of the code. But shouldn't these three ifs at the end be placed before you save their values to the image? Like this:
...
if (sepiaRed >= 256)
{
sepiaRed = 255;
}
if (sepiaGreen >= 256)
{
sepiaGreen = 255;
}
if (sepiaBlue >= 256)
{
sepiaBlue = 255;
}
image[i][j].rgbtRed = sepiaRed;
image[i][j].rgbtBlue = sepiaBlue;
image[i][j].rgbtGreen = sepiaGreen;
...
First You check if calculated values are not higher than 255. Then save these values to the image.
Also you should replace 'else if' with 'if' to check all 3 values not up to one. And then edit value of sepiaRed, sepiaBlue, sepiaGreen not red, blue, green.
I'm not sure if I get right what that function suppose to do.
you have to use the math function round(), mine just working fine.
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
//gets the values of each color in the image
int red = image[i][j].rgbtRed;
int blue = image[i][j].rgbtBlue;
int green = image[i][j].rgbtGreen;
// gets the sepia value of the pixels
int sepiaRed = round(0.393 * red + 0.769 * green + 0.189 * blue) ;
int sepiaGreen = round(0.349 * red + 0.686 * green + 0.168 * blue) ;
int sepiaBlue = round(0.272 * red + 0.534 * green + 0.131 * blue) ;
if (sepiaRed >= 256)
{
sepiaRed = 255;
}
if (sepiaGreen >= 256)
{
sepiaGreen = 255;
}
if (sepiaBlue >= 256)
{
sepiaBlue= 255;
}
image[i][j].rgbtRed = sepiaRed;
image[i][j].rgbtBlue = sepiaBlue;
image[i][j].rgbtGreen = sepiaGreen;
}
}

NAudio 2-channels waves to graphics

Good day, colleagues!
Help, the head has already broken ...
the following code I get a wave from the WAV file and output it in Graphics ... I'm betting on how to split the output of the graph on the left and right channel ... please ...! Tried to taste the manual on NAudio but so did not understand anything about what I need ...
#region draw container
SolidBrush whiteBrush = new SolidBrush(Color.White);
SolidBrush blackBrush = new SolidBrush(Color.Black);
Pen blackPen = new Pen(Color.Black, 1);
e.Graphics.FillRectangle(whiteBrush, 0, 0, this.Width-2, this.Height-2);
e.Graphics.DrawLine(blackPen, 0, 0, this.Width-2, 0);
e.Graphics.DrawLine(blackPen, 0, this.Height / 2, this.Width-2, this.Height / 2);
e.Graphics.DrawLine(blackPen, 0, this.Height - 2, this.Width-2, this.Height-2);
e.Graphics.DrawLine(blackPen, 0, 0, 0, this.Height-2);
e.Graphics.DrawLine(blackPen, this.Width-2, 0, this.Width-2, this.Height-2);
e.Graphics.DrawString("L:", new Font("Arial", 6, FontStyle.Bold), blackBrush, 2, 2);
e.Graphics.DrawString("R:", new Font("Arial", 6, FontStyle.Bold), blackBrush, 2, (this.Height /2) + 2);
#endregion
if (waveStream != null)
{
waveStream.Position = 0;
int bytesRead;
byte[] waveData = new byte[samplesPerPixel * bytesPerSample];
waveStream.Position = startPosition + (e.ClipRectangle.Left * bytesPerSample * samplesPerPixel);
Pen linePen_L = new Pen(PenColor_L, PenWidth);
Pen linePen_R = new Pen(PenColor_R, PenWidth);
//bool _left = true; bool _right = false;
for (float x = e.ClipRectangle.X; x < e.ClipRectangle.Right; x += 1)
{
//_left = !_left;
//_right = !_right;
short low = 0;
short high = 0;
bytesRead = waveStream.Read(waveData, 0, samplesPerPixel * bytesPerSample);
if (bytesRead == 0)
break;
for (int n = 0; n < bytesRead; n += 2)
{
short sample = BitConverter.ToInt16(waveData, n);
if (sample < low) low = sample;
if (sample > high) high = sample;
}
float lowPercent = ((((float)low) - short.MinValue) / ushort.MaxValue);
float highPercent = ((((float)high) - short.MinValue) / ushort.MaxValue);
//if (_left)
e.Graphics.DrawLine(linePen_L, x, (this.Height * lowPercent) /2, x, (this.Height * highPercent)/2);
//if (_right)
//e.Graphics.DrawLine(linePen_R, x, ((this.Height * lowPercent) /2) + this.Height/2, x, ((this.Height * highPercent) /2) + this.Height / 2);
}
}
I found the way :)
if (waveStream != null)
{
waveStream.Position = 0;
int bytesRead;
byte[] waveData = new byte[samplesPerPixel * bytesPerSample];
waveStream.Position = startPosition + (e.ClipRectangle.Left * bytesPerSample * samplesPerPixel);
Pen linePen_L = new Pen(PenColor_L, PenWidth);
Pen linePen_R = new Pen(PenColor_R, PenWidth);
for (float x = e.ClipRectangle.X; x < e.ClipRectangle.Right; x += 1)
{
short low_L = 0;
short high_L = 0;
short low_R = 0;
short high_R = 0;
bytesRead = waveStream.Read(waveData, 0, samplesPerPixel * bytesPerSample);
if (bytesRead == 0)
break;
for (int n = 0; n < bytesRead; n += 2)
{
short sample_L = BitConverter.ToInt16(waveData, n);
if (sample_L < low_L) low_L = sample_L;
if (sample_L > high_L) high_L = sample_L;
n += 2;
short sample_R = BitConverter.ToInt16(waveData, n);
if (sample_R < low_R) low_R = sample_R;
if (sample_R > high_R) high_R = sample_R;
}
float lowPercent_L = ((((float)low_L) - short.MinValue) / ushort.MaxValue);
float highPercent_L = ((((float)high_L) - short.MinValue) / ushort.MaxValue);
float lowPercent_R = ((((float)low_R) - short.MinValue) / ushort.MaxValue);
float highPercent_R = ((((float)high_R) - short.MinValue) / ushort.MaxValue);
e.Graphics.DrawLine(linePen_L, x, (this.Height * lowPercent_L) / 2, x, (this.Height * highPercent_L) / 2);
e.Graphics.DrawLine(linePen_R, x, ((this.Height * lowPercent_R) / 2) + this.Height / 2, x, ((this.Height * highPercent_R) / 2) + this.Height / 2);
}
}

Converting OpenMP to TBB

I have some difficulties in converting an OpenMP code to TBB. Can someone help me?
I have the following code in OpenMP, where the results are pretty good
# pragma omp parallel \
shared ( b, count, count_max, g, r, x_max, x_min, y_max, y_min ) \
private ( i, j, k, x, x1, x2, y, y1, y2 )
{
# pragma omp for
for ( i = 0; i < m; i++ )
{
for ( j = 0; j < n; j++ )
{
//cout << omp_get_thread_num() << " thread\n";
x = ( ( double ) ( j - 1 ) * x_max
+ ( double ) ( m - j ) * x_min )
/ ( double ) ( m - 1 );
y = ( ( double ) ( i - 1 ) * y_max
+ ( double ) ( n - i ) * y_min )
/ ( double ) ( n - 1 );
count[i][j] = 0;
x1 = x;
y1 = y;
for ( k = 1; k <= count_max; k++ )
{
x2 = x1 * x1 - y1 * y1 + x;
y2 = 2 * x1 * y1 + y;
if ( x2 < -2.0 || 2.0 < x2 || y2 < -2.0 || 2.0 < y2 )
{
count[i][j] = k;
break;
}
x1 = x2;
y1 = y2;
}
if ( ( count[i][j] % 2 ) == 1 )
{
r[i][j] = 255;
g[i][j] = 255;
b[i][j] = 255;
}
else
{
c = ( int ) ( 255.0 * sqrt ( sqrt ( sqrt (
( ( double ) ( count[i][j] ) / ( double ) ( count_max ) ) ) ) ) );
r[i][j] = 3 * c / 5;
g[i][j] = 3 * c / 5;
b[i][j] = c;
}
}
}
}
And the TBB version is 10 times slower then OpenMP
the code for TBB is:
tbb::parallel_for ( int(0), m, [&](int i)
{
for ( j = 0; j < n; j++)
{
x = ( ( double ) ( j - 1 ) * x_max
+ ( double ) ( m - j ) * x_min )
/ ( double ) ( m - 1 );
y = ( ( double ) ( i - 1 ) * y_max
+ ( double ) ( n - i ) * y_min )
/ ( double ) ( n - 1 );
count[i][j] = 0;
x1 = x;
y1 = y;
for ( k = 1; k <= count_max; k++ )
{
x2 = x1 * x1 - y1 * y1 + x;
y2 = 2 * x1 * y1 + y;
if ( x2 < -2.0 || 2.0 < x2 || y2 < -2.0 || 2.0 < y2 )
{
count[i][j] = k;
break;
}
x1 = x2;
y1 = y2;
}
if ( ( count[i][j] % 2 ) == 1 )
{
r[i][j] = 255;
g[i][j] = 255;
b[i][j] = 255;
}
else
{
c = ( int ) ( 255.0 * sqrt ( sqrt ( sqrt (
( ( double ) ( count[i][j] ) / ( double ) ( count_max ) ) ) ) ) );
r[i][j] = 3 * c / 5;
g[i][j] = 3 * c / 5;
b[i][j] = c;
}
}
});
Pay attention to the private ( i, j, k, x, x1, x2, y, y1, y2 ) clause in OpenMP version of the code. This list of variables specifies private/local variable inside the parallel loop body. However, in TBB version of the code many of these variables are captured by lambda as references ([&]) so the code is incorrect. It has races and, in my opinion, slow down is caused by accessing these variables from multiple threads (cache coherence overhead and mess in loop indices) . So, if you want to fix the code, make these variables local, e.g.
tbb::parallel_for ( int(0), m, [&](int i)
{
double x, y, x1, x2, y1, y2; // !!!!
int j, k; // !!!!
for ( j = 0; j < n; j++)
{
x = ( ( double ) ( j - 1 ) * x_max
+ ( double ) ( m - j ) * x_min )
/ ( double ) ( m - 1 );
...

Resources