Jump to content

Normalize values?


Recommended Posts


Is there a easy way to normalize value right after you process the image on src? How would one go on making a normalized image within render instead of prerender? I'm working on adding multi-threaded processing on Thorn Fractal PDN plugin. I know I have to process a surface, and then copy the normalized value into dst.


If you look below, the result can be dark.



// Name: Thorn Fractal / Secant Sea
// Submenu: Render
// Author: Reptorian    
// Title: Thorn Fractal / Secant Sea
// Version: 1
// Desc: Render Thorn Fractal / Secant Sea onto canvas. Based off a public code published by Paul Bourke, and a extension of MadJik's code (with permission).
// Keywords: fractal, thorn fractal, secant sea
// URL: https://forums.getpaint.net/profile/85868-reptillian/
// Help:
#region UICode
ListBoxControl vf_choice = 0; // Thorn Fractal|Normal|Normal Inverted|Arctangent|Tangent|Tanh Stroke|Asymphological Vibrato|Asymphological Basic|Asymphological Basic 2|Asymphochaos|Petallian|Semi-Thorny Petallian|Thorny Petal 1|Thorny Petal 2|Inflation|Inflation 2|Chaotic Creation|Earthing|Acrylic Earthing|Unearthing Origami|Cubic Unearthing|Webbing Cubic Unearthing|Chaotic Hooks|Echo Wide|Echo Squircle|Echo Hall|Echo Hall 2|Liquid Parabolic|Chaos-Vibrato|Chaos Deep-Vibrato|Chaos Spacetime|Parabolic|Parabolic Chaos|Cubic-Diamond Chaos|C-Line|Contour Chaos|Spiderweb-Diamond|Acrylica|Refractive Space|Smooth-Artistry|Ferrofluid|Triangular Interweaving|Fabric Chaos|Reverse Tangent Division|Chaotic Tangent|Alternating Chaos 1 (Legacy)|Alternating Chaos 2 (Legacy)|Alternating Chaos 3 (Legacy)|Alternating Chaos 4 (Legacy)|Alternating Chaos 1|Alternating Chaos 2|Alternating Chaos 3|Alternating Chaos 4
IntSliderControl escape = 10000; // [5,3000000] Escape Value
IntSliderControl max_iter = 255; // [1,1024] Loop Limitation
IntSliderControl sublevel = 2; // [1,10] Subsampling Level
DoubleSliderControl dx = 0; // [-50,50] Distortion X
DoubleSliderControl dy = 0; // [-50,50] Distortion Y
DoubleSliderControl r_x = 1; // [0.1,15] Scaling X-Axis
DoubleSliderControl r_y = 1; // [0.1,15] Scaling Y-Axis
DoubleSliderControl r_xy = 1; // [0.1,15] Zoom
CheckboxControl r_pi = true; // PI-Based Scaling
PanSliderControl Offset = Pair.Create(0.0,0.0); // Offset
AngleControl angle = 0; // [-180,180] Angle

float [,] Thorn_Fractal;
float maxnum;
int altern;
bool use_chaos_mode;
double cfa,cfb;

double vf(double a,double b,int f,int c){
    bool axis = c == 0;
        case 0: 
        if(axis) {return a/Math.Cos(b);}
            else     {return b/Math.Sin(a);}
        case 1: 
        if(axis) {return a/Math.Sin(b);}
            else     {return b/Math.Cos(a);}
        case 2: 
        if(axis) {return a/Math.Atan(b);}
            else     {return b/Math.Atan(a);}
        case 3: 
            if(axis) {return a/Math.Tan(b);}
            else     {return b/Math.Tan(a);}
        case 4: 
            if(axis) {return a/Math.Cos(b)*Math.Sin(b);}
            else     {return b/Math.Sin(a)*Math.Cos(a);}
        case 5: 
            if(axis) {return a*Math.Tan(a*b)/Math.Sin(b);}
            else     {return b*Math.Tan(a*b)/Math.Cos(a);}
        case 6:
            if(axis) {return (a+Math.Tan(a*b))/Math.Sin(b);}
            else     {return (b+Math.Tan(a*b))/Math.Cos(a);}
        case 7:
            if(axis) {return (a-Math.Tan(a*b))/Math.Sin(b);}
            else     {return (b-Math.Tan(a*b))/Math.Cos(a);}
        case 8:
            if(axis) {return a/(Math.Cos(b))+a/Math.Sin(b);}
            else     {return b/(Math.Cos(a))+b/Math.Sin(a);}
        case 9:
            if(axis) {return a/(Math.Cos(b)*Math.Sin(b));}
            else     {return b/(Math.Cos(a)*Math.Sin(a));}
        case 10:
            if(axis) {return a/(Math.Cos(Math.Tan(b))*Math.Sin(Math.Tan(b)));}
            else     {return b/(Math.Sin(Math.Tan(a))*Math.Cos(Math.Tan(a)));}
        case 11:
            if(axis) {return (Math.Tan(a)+b)/(Math.Cos(Math.Tan(b))*Math.Sin(Math.Tan(b)));}
            else     {return (Math.Tan(b)+a)/(Math.Sin(Math.Tan(a))*Math.Cos(Math.Tan(a)));}
        case 12:
            if(axis) {return (a+Math.Tan(a)+Math.Tan(b))/(Math.Cos(Math.Tan(b))*Math.Sin(Math.Tan(b)));}
            else     {return (b+Math.Tan(a)+Math.Tan(b))/(Math.Sin(Math.Tan(a))*Math.Cos(Math.Tan(a)));}
        case 13:
            if(axis) {return (a+Math.Tan(a)+Math.Tan(b))/Math.Cos(a);}
            else     {return (b+Math.Tan(a)+Math.Tan(b))/Math.Sin(a);}
        case 14:
            if(axis) {return (a+Math.Tan(a)+Math.Tan(b))/Math.Sin(b);}
            else     {return (b+Math.Tan(a)+Math.Tan(b))/Math.Cos(a);}
        case 15:
            if(axis) {return a/Math.Sin(Math.Cos(b)*Math.Sin(b));}
            else     {return b/Math.Cos(Math.Sin(a)*Math.Cos(a));}
        case 16:
            if(axis) {return (a+Math.Tan(a)/Math.Tan(b))/Math.Cos(a);}
            else     {return (b+Math.Tan(a)/Math.Tan(b))/Math.Sin(b);}
        case 17:
            if(axis) {return (b+Math.Tan(a)/Math.Tan(b))/Math.Cos(a);}
            else     {return (a+Math.Tan(a)/Math.Tan(b))/Math.Sin(b);}
        case 18:
            if(axis) {return (b+Math.Tan(b)/Math.Tan(a))/Math.Cos(a);}
            else     {return (a+Math.Tan(a)/Math.Tan(b))/Math.Sin(b);}
        case 19:
            if(axis) {return (b+Math.Tan(b)/Math.Tan(a))/Math.Cos(a);}
            else     {return (a+Math.Tan(b)/Math.Tan(a))/Math.Sin(b);}
        case 20:
            if(axis) {return (b+Math.Tan(a)/Math.Tan(a))/Math.Cos(a);}
            else     {return (a+Math.Tan(b)/Math.Tan(a))/Math.Sin(b);}
        case 21:
            if(axis) {return b+Math.Tan(a)/(a/(Math.Cos(b)))+(a/(Math.Sin(b)));}
            else     {return a+Math.Tan(b)/(b/(Math.Cos(a)))+(b/(Math.Sin(a)));}
        case 22:
            if(axis) {return a/Math.Sin(a/Math.Sin(b));}
            else     {return b/Math.Cos(b/Math.Cos(a));}
        case 23:
            if(axis) {return a/Math.Cos(a/Math.Sin(b));}
            else     {return b/Math.Sin(b/Math.Cos(a));}
        case 24:
            if(axis) {return a/Math.Cos(a/Math.Atan(Math.Sin(b)));}
            else     {return b/Math.Sin(b/Math.Atan(Math.Cos(a)));}
        case 25:
            if(axis) {return a/Math.Sin(a/Math.Atan(Math.Cos(b)));}
            else     {return b/Math.Cos(b/Math.Atan(Math.Sin(a)));}
        case 26:
            if(axis) {return a/Math.Atan(Math.Cos(b));}
            else     {return b/Math.Atan(Math.Sin(a));}
        case 27:
            if(axis) {return (a+Math.Tanh(a*b))/Math.Cos(b);}
            else     {return (b+Math.Tanh(a*b))/Math.Sin(a);}
        case 28:
            if(axis) {return b+Math.Tan(b)/(a/(Math.Cos(b)))+(a/(Math.Sin(a)));}
            else     {return a+Math.Tan(a)/(b/(Math.Cos(a)))+(b/(Math.Sin(b)));}
        case 29:
            if(axis) {return (a+Math.Tanh(a+b))/Math.Cos(b);}
            else     {return (b+Math.Tanh(a+b))/Math.Sin(a);}
        case 30:
        if(axis) {return (a/Math.Sin(b))/Math.Tan(b);}
            else     {return (b/Math.Cos(a))/Math.Tan(a);}
        case 31:
            if(axis) {return a/(Math.Tan(b)*Math.Cos(b)*Math.Sin(b));}
            else     {return b/(Math.Tan(a)*Math.Cos(a)*Math.Sin(a));}
        case 32:
            if(axis) {return a/Math.Tan(Math.Cos(b));}
            else     {return b/Math.Tan(Math.Sin(a));}
        case 33:
            if(axis) {return (a+Math.Tanh(a*b))/(Math.Cos(b)*Math.Sin(a));}
            else     {return (b+Math.Tanh(a*b))/(Math.Sin(b)*Math.Cos(a));}
        case 34:
            if(axis) {return (a+Math.Tan(Math.Cos(a)*Math.Sin(b)))/Math.Cos(a);}
            else     {return (b+Math.Tan(Math.Sin(a)*Math.Cos(b)))/Math.Sin(b);}
        case 35:
            if(axis) {return (Math.Tan(a+b)*b)/Math.Cos(b);}
            else     {return (Math.Tan(a-b)*a)/Math.Sin(a);}
        case 36:
            if(axis) {return (a/Math.Cos(b))*Math.Sin(a);}
            else     {return (b/Math.Sin(a))*Math.Cos(b);}
        case 37:
            if(axis) {return a/Math.Tan(Math.Cos(b)+Math.Sin(b));}
            else     {return b/Math.Tan(Math.Cos(a)+Math.Sin(a));}
        case 38:
            if(axis) {return a+(Math.Tanh(a+b)/Math.Cos(b));}
            else     {return b+(Math.Tanh(a+b)/Math.Sin(a));}
        case 39:
            if(axis) {return (a/(Math.Cos(b)))/(b/(Math.Sin(a)));}
            else     {return (b/(Math.Cos(a)))/(a/(Math.Sin(b)));}
        case 40:
            if(axis) {return (a*Math.Tan(a+b))/Math.Sin(b);}
            else     {return (b*Math.Tan(a+b))/Math.Cos(a);}
            case 41:
            if(axis) {return a/(Math.Atan2(b*b,a*a)*Math.Tan(b));}
            else     {return b/(Math.Atan2(b*b,a*a)*Math.Tan(a));}
        case 42:
            if(axis) {return Math.Tan(a)/b;}
            else     {return Math.Tan(b)/a;}
        case 43:
            if(axis) {return a/Math.Atan(b/Math.Cos(a/Math.Sin(a)));}
            else     {return b/Math.Atan(a/Math.Sin(b/Math.Cos(b)));}
                case 0:
                    if(axis) {return a/Math.Cos(b);}
                    else     {return b/Math.Sin(a);}
                case 1:
                    if(axis) {return a/Math.Sin(b);}
                    else     {return b/Math.Cos(a);}
                    case 2:
                    if(axis) {return a/Math.Tan(b);}
                    else     {return b/Math.Tan(a);}
                    case 3:
                    if(axis) {return a/Math.Atan(b);}
                    else     {return b/Math.Atan(a);}
                        if(axis) {return a/cfb;}
                        else     {return b/cfa;}
                        if(axis) {return a;}
                        else     {return b;}

void PreRender(Surface dst, Surface src)


void Render(Surface dst, Surface src, Rectangle rect)
    int ff;
    use_chaos_mode = vf_choice > 47;
    if(use_chaos_mode) {ff = vf_choice - 44;}
    else     {ff = vf_choice - 40;}
    bool use_altern = vf_choice > 43;
    double d_escape = (double)(escape);
    int w = src.Width;
    int h = src.Height;
    bool sd_cond = w>h;
    if (Thorn_Fractal == null){Thorn_Fractal = new float [w,h];}
    else     { Array.Clear(Thorn_Fractal, 0, w*h);}
    double dw = (double)(w);
    double dh = (double)(h);
    double sd = Math.Max(w,h)/Math.Min(w,h);
    double sx = w > h ? sd : 1  ;
    double sy = w > h ? 1  : sd ;
    int sub_w=w*sublevel;
    int sub_h=h*sublevel;
    bool resize_sub_w = sub_w%2 == 0;
    bool resize_sub_h = sub_h%2 == 0;
    if (resize_sub_w) {sub_w++;}
    if (resize_sub_h) {sub_h++;}
    int windows=sublevel * sublevel;
    double rpi = r_pi ? Math.PI : 1 ;
    double szx = rpi * r_x * r_xy;
    double szy = rpi * r_y * r_xy;
    double ang = angle / 180 * Math.PI;
    double cos_ang = Math.Cos(ang);
    double sin_ang = Math.Sin(ang);
    double ox = Offset.First * cos_ang - Offset.Second * sin_ang;
    double oy = Offset.First * sin_ang + Offset.Second * cos_ang;
    maxnum = 0;
    float ev;
    int i_ev;
    int nx,ny,v,v_sum;
    double xx,yy,zx,zy,vx,vy,a,b;
    for (int y = rect.Top; y < rect.Bottom; y++)
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
            for(int sub_y=0 ; sub_y < sublevel ; sub_y++){
                yy = (double) (sy * 2 * (((double)(y*sublevel)+(double)(sub_y))/(double)(sub_h)-.5));
                for(int sub_x=0 ; sub_x < sublevel ; sub_x++){
                    xx = (double) (sx * 2 * (((double)(x*sublevel)+(double)(sub_x))/(double)(sub_w)-.5));
                    zx = szx * ((xx*cos_ang-yy*sin_ang)+ox);
                    zy = szy * ((xx*sin_ang+yy*cos_ang)+oy);
                    vx = zx;
                    vy = zy;
                    for (v=0 ; v<max_iter ; v++){
                        if (use_altern){altern++;if(altern>ff){altern=0;}}
                        if ((vx*vx+vy*vy)>d_escape){break;}
                    v = zx!=0&&zy!=0?v:0;
            ev = (float)(v_sum)/(float)(windows);
            i_ev = (int)(Math.Round(ev));



Edited by Reptillian
Swapped src to dst.

G'MIC Filter Developer

Link to comment
Share on other sites

42 minutes ago, midora said:

Normalizing a value typically means that you map an existing range to the range 0.0 to 1.0.

Because paint.net uses 8 bit values in the range 0 to 255 the formula is easy: normalizedValue = value / 255.f .


That's not exactly what I mean by normalize. Normalizing value means taking the min max value of a image, then stretching it to 0 to 255.


For simple example used for clarification:



The left contains random value that ranges from 0-10. The right is the normalized image.


I need a way to normalize the image right after processing the thorn fractal.

G'MIC Filter Developer

Link to comment
Share on other sites

2 hours ago, Reptillian said:

How would one go on making a normalized image within render instead of prerender?


You can normalize the pixels in Render, but you need to find the minimums and maximums in PreRender. I'm almost certain there's no way to do that in Render.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Create New...