1

I'm using Microsoft Visual Studio 2010.

The formula is y = 1/(1+exp(-e))

Over the range of values where bih.biWidth is the range to iterate.

Yet when i try implementing in the codes it does not work, why? Can any experts please guide me along, thank you.

for(int y=0; y<bih.biHeight; y++) 
{ 
   for(int x=0; x<bih.biWidth; x++) 
   {   
      SetPixel(hdc, (double)1/((double)1+exp(double(-x)))*bih.biWidth, 
               bih.biHeight-x, red); 
   } 
} 

The lines start from nearly at the bottom right hand of the image, and ends it at the end with a slight curve on the top right hand of the image. Why is that so?

Mark Wilkins
  • 40,729
  • 5
  • 57
  • 110
Newbie
  • 145
  • 2
  • 7
  • 23
  • 1
    Why are you iterating over both x and y? – Steve C Jan 31 '12 at 01:00
  • 1
    and it looks like you've got the coords mixed up - you're iterating x over biWidth but subtracting it from biHeight? – Rup Jan 31 '12 at 01:02
  • Because i needed to draw a graph inside the image itself, and the pixels are retrieved from each and every loop that i run. – Newbie Jan 31 '12 at 01:02
  • for the bih.biHeight-x, that one certainly works because for the other functions that i did (Gaussian Blur, Linear Tone Curve, etc). Just couldn't figure out why for Sigmoid curve it doesn't. – Newbie Jan 31 '12 at 01:03
  • And i am running an image which have the same width and height, so i figured it shouldn't be such an issue for now. – Newbie Jan 31 '12 at 01:04
  • 1
    possible duplicate of [Implementing Sigmoid Curves in C++](http://stackoverflow.com/questions/9065607/implementing-sigmoid-curves-in-c) – ruakh Jan 31 '12 at 01:06
  • In regards to that question is before i implement the formula with the range of values inside. This one is after i implement the formula after the range of values, which indicates the problem i have now, it is not a duplicate. – Newbie Jan 31 '12 at 01:09
  • @Cnoob: You already posted [the same question](http://stackoverflow.com/questions/9065607/implementing-sigmoid-curves-in-c) ~10 hours ago. Please do not post multiple copies of your question - if you don't like the answers in the other copy, please edit or comment on that question to explain why. – Mac Jan 31 '12 at 01:22

2 Answers2

2

Because 0 is the center of the sigmoid curve. Your x starts at 0; if you want your curve to be plotted symmetrically, you need to compute an argument that is symmetric about 0:

for(int x=0; x<bih.biWidth; x++)
{
    double a= x - 0.5*bih.biWidth;
    SetPixel(hdc, bih.biWidth-x, 1.0/(1.0+exp(-a)) * bih.biHeight, red);
}

Scaling a by a constant factor will adjust the slope of the sigmoid function.

(I also suspect that your original code has switched the scaling factors used in the SetPixel() arguments, so I have fixed that. It doesn't make sense to subtract x from bih.biHeight when it ranges from 0 to bih.biWidth instead...)

[additional edit: I have additionally switched the arguments, so that biWidth and biHeight are in the x- and y-coordinates, respectively. This is the conventional way to plot functions, anyway -- so if you had wanted to flip the plot, you will need to switch it back]

comingstorm
  • 25,557
  • 3
  • 43
  • 67
  • I have edited the answer; please let me know if there is anything left unclear. – comingstorm Jan 31 '12 at 01:19
  • Aannd, I have re-edited the answer, so that the sigmoid is plotted in the conventional orientation... – comingstorm Jan 31 '12 at 01:25
  • Hi comingstorm, the function does work, but when curving down or up, it comes up as little dots, not as a line, why is that so? Thank you! – Newbie Jan 31 '12 at 01:35
  • Because you're drawing little dots (i.e., pixels, using `SetPixel()`). Look at Ben Voight's answer: he's using `MoveToEx()` and `LineTo()` instead. – comingstorm Jan 31 '12 at 01:45
  • Hi ben and comingstorm, does that mean i change my code to as such? double a= x - 0.5*bih.biWidth; LineTo(hdc, bih.biWidth-x, 1.0/(1.0+exp(-a)) * bih.biHeight); – Newbie Jan 31 '12 at 01:50
  • Yes. Using `SetPixel()` to draw lines between your sample points is possible, but it would also be more complicated than using `LineTo()`. – comingstorm Jan 31 '12 at 01:58
  • Hi comingstorm, i'm really sorry for my lack of knowledge, I do not get it by what you mean about SetPixel is harder, Shouldn't LineTo be harder? – Newbie Jan 31 '12 at 02:01
  • Sorry to bother you, my LineTo function did not work despite changing to double a= x - 0.5*bih.biWidth; LineTo(hdc, bih.biWidth-x, 1.0/(1.0+exp(-a)) * bih.biHeight) as mentioned in SetPixel function – Newbie Jan 31 '12 at 02:07
  • I think you may need to create and select a pen: please read the documentation for `CreatePen()` and `SelectObject()`. This may all seem complicated to you, but you should probably learn it anyway -- ultimately, it's the right way to do it, since poking individual pixels for everything can be very inefficient. – comingstorm Jan 31 '12 at 19:37
1

Here's idiomatic code for what you're trying to do:

double f(double x) { return 1.0 / (1.0 + exp(-x)); }

void draw_graph(HDC hdc, BITMAPINFOHEADER bih, RECTF graph_bounds)
{
    double graph_x, graph_y = f(graph_bounds.left);
    MoveToEx(hdc, 0, bih.biHeight * (1 - (graph_y - graph_bounds.bottom) / (graph_bounds.top - graph_bounds.bottom), NULL);
    for(int x=1; x<bih.biWidth; x++) {
       graph_x = graph_bounds.left + (graph_bounds.right - graph_bounds.left) * x / bih.biWidth;
       graph_y = f(graph_x);
       LineTo(hdc, x, bih.biHeight * (1 - (graph_y - graph_bounds.bottom) / (graph_bounds.top - graph_bounds.bottom));
    }
} 
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Hi ben, i'm sorry, is there any simpler way to do it with just purely SetPixel? – Newbie Jan 31 '12 at 01:36
  • 1
    @Cnoob: You don't want to use purely `SetPixel`, that's what's causing the "disconnected dots" problem you observed in the other answer. `LineTo` fixes that. – Ben Voigt Jan 31 '12 at 01:38