Reptillian Posted February 27, 2021 Share Posted February 27, 2021 (edited) 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. Spoiler // 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 #endregion 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; switch(f){ 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)));} default: switch(altern){ 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);} default: if(use_chaos_mode){ if(axis) {return a/cfb;} else {return b/cfa;} } else{ if(axis) {return a;} else {return b;} } } } } void PreRender(Surface dst, Surface src) { } void Render(Surface dst, Surface src, Rectangle rect) { int ff; altern=0; 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++) { v_sum=0; 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++){ a=vx; b=vy; vx=vf(a,b,vf_choice,0); vy=vf(a,b,vf_choice,1); vx+=dx; vy+=dy; if (use_altern){altern++;if(altern>ff){altern=0;}} if ((vx*vx+vy*vy)>d_escape){break;} } v = zx!=0&&zy!=0?v:0; v_sum+=v; } } ev = (float)(v_sum)/(float)(windows); i_ev = (int)(Math.Round(ev)); dst[x,y]=ColorBgra.FromBgr((byte)(i_ev),(byte)(i_ev),(byte)(i_ev)); } } } Edited February 27, 2021 by Reptillian Swapped src to dst. Quote G'MIC Filter Developer Link to comment Share on other sites More sharing options...
midora Posted February 27, 2021 Share Posted February 27, 2021 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 . Quote Link to comment Share on other sites More sharing options...
Reptillian Posted February 27, 2021 Author Share Posted February 27, 2021 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. Quote G'MIC Filter Developer Link to comment Share on other sites More sharing options...
MJW Posted February 27, 2021 Share Posted February 27, 2021 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.