Fractal or Perlin noise is coherent and self-similar at different scales.
"Coherency" means that nearby pixels have similar values. "Self-similarity" means the image looks similar at different scales.
A different method for a similar effect would be to create an image entirely of noise, blur this a few times, then add the results. This would be computationally expensive.
This implementation uses Laplacian pyramids, as shown in Multi-scale pyramids.
One example on this page uses process modules. See my Process Modules page.
The script fractNoise.bat constructs and executes a magick command. This creates a number of images that each represent noise at different frequencies, then adds them together.
This creates and collapses a Laplacian pyramid (see Multi-scale pyramids) within a single magick. When used for individual images, the pyramid is not usually saved, though it can be if desired. When the fractal noise is animated, (see Fractal noise animations) the pyramid is created and saved at frame zero, and re-read for each other frame.
Each image is sometimes called an octave, because the noise frequency often doubles between them. In this implementation, any frequency multiplier greater than one may be used.
At each octave, noise is generated not for each separate pixel but instead in a grid pattern, and values at each pixel are interpolated from these.
To generate the final image, the corresponding pixels from all the enlarged grids are added, with appropriate weighting.
For example, one octave for a 600x400 pixel image might have 24x16 grid points. Each block is therefore 600/24 = 400/16 = 25 pixels square. We will magnify the noise grid by a factor of 25. With ImageMagick, we create a small noise grid with the required aspect ratio, and resize it to exactly the required dimensions.
In this implementation, blocks are always square, so grid points are equally spaced in the full-size image (which need not be square) in both the x- and y-directions.
%IMG7%magick ^ -size 24x16 xc:rgb(50%%,50%%,50%%) ^ +noise Gaussian ^ +write fn_m1.png ^ -resize "600x400^!" ^ -auto-level ^ fn_m2.png |
This process is repeated for noise grids of 600x400, 300x200, ... perhaps down to 3x2 or even 1x1. As each resized noise image is generated, it is multiplied by an amplitude factor, and added to the previous result. This gives a weighted average. There are two purposes to the weighting:
For these fractal noise Laplacian pyramids, weighting is scaled so the sum of the weights is 1.0, ie 100%. This is different to those on Multi-scale pyramids, where scaling makes the maximum 1.0, ie 100%. Pixel values are offset, so values of 50% represent zero. Hence, multiplication by a weight is performed by +level, not -evaluate Multiply.
Some implementations have a feature of recognising when an octave's amplitude insignificant, so they save time by not processing that octave. This implementation currently doesn't have that feature.
Above, we interpolate with "-resize". An alternative method uses "+distort SRT", which respects the "-virtual-pixel" setting.
%IMG7%magick ^ fn_m1.png ^ -virtual-pixel Tile ^ +distort SRT "25,0" ^ -auto-level ^ fn_m3.png |
The result fn_m3.png is slightly different to fn_m3.png, mostly around the edges. Importantly, it is now tilable, as we can see:
%IMG7%magick ^ fn_m3.png ^ ( +clone ) +append +repage ^ ( +clone ) -append +repage ^ fn_m4.png
In general, the magnification may not be an integer, and may be different in the x and y directions.
%IMG7%magick ^ fn_m1.png ^ -virtual-pixel Tile ^ +distort SRT "0,0,25,25,10,20,10" ^ +repage ^ -crop 600x400+0+0 +repage ^ -auto-level ^ fn_m5.png |
Each octave resembles blurred noise. Fractal noise where the block size is restricted to a narrow band closely resembles blurred noise.
This implementation should be usable with any Q-number ImageMagick, either integer or HDRI. When used to create displacement maps, higher Q-numbers (such as 32) may be beneficial. See Straightening horizons: How much precision? where I conclude that: "for images of a few thousand pixels in each dimension, displacement maps should be created and used with Q32 or better".
By default, the script uses ImageMagick programs found at %IMG7%. This can be overridden by setting %fnIM% to a different location.
The main controls are specified by giving parameters to the script. Each may be left to default by giving a single dot "." in its place.
%1 | Required image width, pixels. Default: 600 |
%2 | Required image height, pixels. Default: 400 |
%3 | The minimum block size. Small blocks give high-frequency noise. Default: 1 |
%4 | The maximum block size. Large blocks give low-frequency noise. Default: min(height,width)/2 |
%5 | The block factor. Should be >=1. Default: 2 |
%6 | The power factor. Default: 0 |
%7 | Output file. Default: fn.png |
Parameters %3, %4, %5 and %6 correspond exactly to the same parameters of Multi-scale pyramids.
The script starts at block size %3 x %3. This is the smallest block size, which creates the highest frequency noise. Successive blocks are %5 times as large, at increasing sizes so at lower frequencies. It stops when the block size would be greater than or equal to %4.
Block sizes correspond to wavelengths, the inverse of frequencies.
Amplitudes are normalised so they sum to 1.0. Each is then multiplied by %fnCONST_FAC%, which defaults to 1.0. If %fnCONST_FAC% is set to a value greater then 1.0, the result is likely to be clipped at 100%. If a lower value is used, auto-levelling should usually be turned off.
See below for Examples of script arguments.
In addition, there are a large number of optional environment variables, all starting with "fn". Variables currently available are: fnSEED fnGRAY fnNOISE_TYPE fnABS_NSE fnFILTER fnIM fnPREFIX fnNG_EXT fnLINEAR fnAUTO_LEVEL_EACH fnAUTO_LEVEL_END fnAUTO_GAM_END fnRD_PYR fnWR_PYR fnPROC_EACH fnTXT_OUT fnA_FRM_NUM fnA_COL fnA_DX fnA_DY fnA_ZM fnA_POW_FAC fnA_COLCYCMETH . See the script, and text on this page. Variables that start with "fnA_" are for animation; see the page Fractal noise animations.
If desired, the script will echo some text. This includes some statistics about each octave, including the minimum and maximum values generated. See the script for details. If text is wanted, set fnTXT_OUT=1.
call %PICTBAT%fn_zeroEnvVar set fnPREFIX=fn_txtout_ set fnTXT_OUT=1 set fnWR_PYR=1 call %PICTBAT%fractNoise ^ . . . . . . fn_examp.png >fn_fractnoise.lis set fnWR_PYR= set fnTXT_OUT= set fnPREFIX=
Here is fn_fractnoise.lis, the text output from the fractNoise.bat script. Lines beginning "levels" are written by the IM magick command.
C:\prose\pictures>rem Make fractal noise. C:\pictures\fnInit: 600 400 1 300 2 0 levels 0: %[fx:minima] %[fx:maxima] levels 1: %[fx:minima] %[fx:maxima] levels 1: %[fx:minima] %[fx:maxima] levels 2: %[fx:minima] %[fx:maxima] levels 2: %[fx:minima] %[fx:maxima] levels 3: %[fx:minima] %[fx:maxima] levels 3: %[fx:minima] %[fx:maxima] levels 4: %[fx:minima] %[fx:maxima] levels 4: %[fx:minima] %[fx:maxima] levels 5: %[fx:minima] %[fx:maxima] levels 5: %[fx:minima] %[fx:maxima] levels 6: %[fx:minima] %[fx:maxima] levels 6: %[fx:minima] %[fx:maxima] levels 7: %[fx:minima] %[fx:maxima] levels 7: %[fx:minima] %[fx:maxima] levels 8: %[fx:minima] %[fx:maxima] levels 8: %[fx:minima] %[fx:maxima] levels before AL: %[fx:minima] %[fx:maxima] Created fn_examp.png ... and fn_txtout_fnpyr.tiff
Here is fn_txtout_fn.bat, the IM magick command created and run by the fractNoise.bat script.
C:\im\ImageMagick-7.1.1-20-Q16-HDRI\magick ^ -compose Plus -virtual-pixel Tile -precision 15 ^ -script fn_txtout_fn.scr
Here is fn_txtout_fn.scr, the script that is run within the magick command.
( -size 600x400 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD0 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 0: %%[fx:minima] %%[fx:maxima]\n" +write info: ( -size 300x200 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD1 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 1: %%[fx:minima] %%[fx:maxima]\n" +write info: -compose Mathematics -define compose:args=0,1,1,-0.5 -composite ( -size 150x100 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD2 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 2: %%[fx:minima] %%[fx:maxima]\n" +write info: -compose Mathematics -define compose:args=0,1,1,-0.5 -composite ( -size 75x50 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD3 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 3: %%[fx:minima] %%[fx:maxima]\n" +write info: -compose Mathematics -define compose:args=0,1,1,-0.5 -composite ( -size 38x25 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD4 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 4: %%[fx:minima] %%[fx:maxima]\n" +write info: -compose Mathematics -define compose:args=0,1,1,-0.5 -composite ( -size 19x13 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD5 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 5: %%[fx:minima] %%[fx:maxima]\n" +write info: -compose Mathematics -define compose:args=0,1,1,-0.5 -composite ( -size 9x6 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD6 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 6: %%[fx:minima] %%[fx:maxima]\n" +write info: -compose Mathematics -define compose:args=0,1,1,-0.5 -composite ( -size 5x3 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD7 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 7: %%[fx:minima] %%[fx:maxima]\n" +write info: -compose Mathematics -define compose:args=0,1,1,-0.5 -composite ( -size 2x2 xc:rgb(50%%,50%%,50%%) +noise Random +write mpr:GRD8 -virtual-pixel tile -distort SRT 0,0,1,0,0,0 -resize "600x400^!" +level 44.4444444444444%,55.5555555555556% ) -format "levels 8: %%[fx:minima] %%[fx:maxima]\n" +write info: -compose Mathematics -define compose:args=0,1,1,-0.5 -composite -format "levels before AL: %%[fx:minima] %%[fx:maxima]\n" +write info: -auto-level -auto-gamma +depth +write fn_examp.png +delete mpr:GRD0 mpr:GRD1 mpr:GRD2 mpr:GRD3 mpr:GRD4 mpr:GRD5 mpr:GRD6 mpr:GRD7 mpr:GRD8 -write fn_txtout_fnpyr.tiff -exit
The previous section, Text output, created a pyramid of noise grid images. We can extract each grid and show it with a version enlarged to the final image size.
Octave | Noise grid | Enlarged noise grid |
---|---|---|
8 | ||
7 | ||
6 | ||
5 | ||
4 | ||
3 | ||
2 | ||
1 | ||
0 |
The image that was created from these noise grids is:
fn_examp.png |
The following shows examples of the six basic parameters, listed above in Script controls.
Ensure fractNoise environment variable are not set:
call %PICTBAT%fn_zeroEnvVar
Create a different example each time:
set fnSEED=
call %PICTBAT%fractNoise ^ . . . . . . fn_1.png |
|
call %PICTBAT%fractNoise ^ . . . . . . fn_2.png |
|
call %PICTBAT%fractNoise ^ . . . . . . fn_3.png |
All following examples use the same seed.
set fnSEED=1234
call %PICTBAT%fractNoise ^ 75 50 . . . . fn_sz1.png |
|
call %PICTBAT%fractNoise ^ 150 100 . . . . fn_sz2.png |
|
call %PICTBAT%fractNoise ^ 300 200 . . . . fn_sz3.png |
|
call %PICTBAT%fractNoise ^ 600 400 . . . . fn_sz4.png |
|
call %PICTBAT%fractNoise ^ 75 50 . . . 1 fn_sz1w.png |
|
call %PICTBAT%fractNoise ^ 150 100 . . . 1 fn_sz2w.png |
|
call %PICTBAT%fractNoise ^ 300 200 . . . 1 fn_sz3w.png |
|
call %PICTBAT%fractNoise ^ 600 400 . . . 1 fn_sz4w.png |
%IMG7%magick ^ fn_sz4.png -resize "75x50^!" ^ fn_sz1.png ^ -metric RMSE -compare -format %%[distortion] ^ info:
0.0578859
%IMG7%magick ^ fn_sz4w.png -resize "75x50^!" ^ fn_sz1w.png ^ -metric RMSE -compare -format %%[distortion] ^ info:
0.00590417
Provided the same seed is used, images made at different sizes are remarkably similar.
call %PICTBAT%fractNoise ^ . . . . . . fn_s1.png |
|
Omit highest frequencies. call %PICTBAT%fractNoise ^ . . 10 . . . fn_s2.png |
|
Omit lowest frequencies. call %PICTBAT%fractNoise ^ . . . 64 . . fn_s3.png |
|
Blocks at only one size. call %PICTBAT%fractNoise ^ . . 64 64 . . fn_s4.png |
Small factors give a large variety of noise frequencies. call %PICTBAT%fractNoise ^ . . . . 1.1 . fn_bf1.png echo %fnNUM_OCTAVES% 60 With so much added noise, the result is muddy. |
|
As previous, with auto-levelling. set fnAUTO_LEVEL_EACH=2 call %PICTBAT%fractNoise ^ . . . . 1.1 . fn_bf1a.png set fnAUTO_LEVEL_EACH= |
|
As previous, also auto-levelling at end. set fnAUTO_LEVEL_EACH=2 set fnAUTO_LEVEL_END=2 call %PICTBAT%fractNoise ^ . . . . 1.1 . fn_bf1b.png set fnAUTO_LEVEL_END= set fnAUTO_LEVEL_EACH= |
|
Large factors give little variety of noise frequencies.
call %PICTBAT%fractNoise ^ . . . . 10 . fn_bf2.png Perhaps a mottled-glass effect. |
Positive power factors emphasise low-frequency noise. call %PICTBAT%fractNoise ^ . . . . . 2 fn_pf1.png |
|
"1.5". call %PICTBAT%fractNoise ^ . . . . . 1.5 fn_pf2.png |
|
"1" gives the classic halving of amplitude per doubling of frequency. call %PICTBAT%fractNoise ^ . . . . . 1 fn_pf3.png |
|
"0.5". call %PICTBAT%fractNoise ^ . . . . . 0.5 fn_pf4.png |
|
"0" gives equal weight to all frequencies. call %PICTBAT%fractNoise ^ . . . . . 0 fn_pf5.png |
|
"-0.5". Negative factors emphasise high-frequency noise. call %PICTBAT%fractNoise ^ . . . . . -0.5 fn_pf6.png |
|
"-1" doubles the amplitude with each doubling of frequency. call %PICTBAT%fractNoise ^ . . . . . -1 fn_pf7.png Low-frequency noise is almost swamped. |
Many parameters are set by environment variables. Some are illustrated here.
call %PICTBAT%fn_zeroEnvVar set fnSEED=1234 set fnAUTO_LEVEL_EACH=0 call %PICTBAT%fractNoise ^ . . . . . . fn_al1.png |
|
set fnAUTO_LEVEL_EACH=1 call %PICTBAT%fractNoise ^ . . . . . . fn_al2.png |
|
set fnAUTO_LEVEL_EACH=2 call %PICTBAT%fractNoise ^ . . . . . . fn_al3.png set fnAUTO_LEVEL_EACH= |
With the default parameters, auto-levelling each octave makes very little difference (about 1% RMSE). For some settings, it can make a larger difference.
When used with animations, auto-levelling can result in flicker, so should generally not be used.
See also the Noise page.
When used for animation that includes changing colours, noise types other than "Random" (the default) are not recommended. Other distributions can be created by using fnPROC_EACH.
set fnNOISE_TYPE=Gaussian call %PICTBAT%fractNoise ^ . . . . . . fn_nt1.png |
|
set fnNOISE_TYPE=Gaussian set fnABS_NSE=1 call %PICTBAT%fractNoise ^ . . . . . . fn_nt1a.png set fnABS_NSE= set fnNOISE_TYPE= |
|
set fnNOISE_TYPE=Gaussian set fnABS_NSE=1 call %PICTBAT%fractNoise ^ . . . . . 1 fn_nt1b.png set fnABS_NSE= set fnNOISE_TYPE= Oil in water? Corny science-fiction movie? |
|
set fnNOISE_TYPE=Poisson call %PICTBAT%fractNoise ^ . . . . . . fn_nt2.png set fnNOISE_TYPE= |
|
set fnNOISE_TYPE=Uniform call %PICTBAT%fractNoise ^ . . . . . . fn_nt3.png set fnNOISE_TYPE= |
|
set fnNOISE_TYPE=Impulse call %PICTBAT%fractNoise ^ . . . . . . fn_nt4.png set fnNOISE_TYPE= |
"+noise Impulse" makes an image mostly 50%, with a few pixels at 0 or 100%. fractNoise.bat transforms values so that 50% values become 100%, and both 0 and 100% become 0. Hence, this result is very light.
Similarly, "+noise Gaussian" creates most values around 50%, and these are transformed to be just under 100%. This is also true of other noise types. See the page on Noise.
Why does fractNoise.bat do this transformation? So that pixel colours can be animated while retaining fractal properties, and values after modulus addition such as 99.99% and 0.01% are very similar visually.
This transformation is also done for stills, so we can pick a still we like, and use the same parameters for animation.
Sadly, the transformation is not reversible.
set fnFILTER=Box call %PICTBAT%fractNoise ^ . . . . . . fn_f1.png |
|
set fnFILTER=Box call %PICTBAT%fractNoise ^ . . . . . 1 fn_f2.png |
|
set fnFILTER=Point call %PICTBAT%fractNoise ^ . . . . . . fn_f3.png Point is identical to Box. |
|
set fnFILTER=Cubic call %PICTBAT%fractNoise ^ . . . . . . fn_f4.png |
|
set fnFILTER=Triangle call %PICTBAT%fractNoise ^ . . . . . . fn_f5.png set fnFILTER= |
When a grayscale image is wanted, the script takes the value from the red channel.
set fnGRAY=1 call %PICTBAT%fractNoise ^ . . . . . . fn_g1.png |
|
call %PICTBAT%fractNoise ^ . . 10 40 1.1 . fn_g2.png set fnGRAY= |
For static images, there is no colour cycling. However, the variable fnA_COLCYCMETH may have an effect on the output.
(For detail of the methods, see Colour cycling.)
When fnA_COLCYCMETH has no value, it takes a default value, which is:
set fnA_COLCYCMETH=null call %PICTBAT%fractNoise ^ . . . . . . fn_cm1.png |
|
set fnA_COLCYCMETH=sinarc2o call %PICTBAT%fractNoise ^ . . . . . . fn_cm2.png %IMG7%magick compare -metric RMSE ^ fn_cm1.png fn_cm2.png NULL: 0.0473902 (7.23128e-07) |
|
set fnA_COLCYCMETH=amsol call %PICTBAT%fractNoise ^ . . . . . . fn_cm3.png %IMG7%magick compare -metric RMSE ^ fn_cm1.png fn_cm3.png NULL: set fnA_COLCYCMETH= 8256.34 (0.125984) |
For a static image, results from null and sinarc2o are visually the same. But other methods such as amsol are very different.
A fractal noise image is a mathematical construct with the mean near 50%, written to an image file that IM declares to be in non-linear sRGB colorspace.
We can readily declare the result to be in linear RGB colorspace, and convert to sRGB so the mean is around 72%.
Or we can insert processing that linearizes the generated noise, and delinearizes the result.
call %PICTBAT%fractNoise ^ . . . . . . fn_lin1.png %IMG7%magick ^ fn_lin1.png ^ -format "mean=%%[fx:mean]" ^ info: mean=0.50303 |
|
%IMG7%magick ^ fn_lin1.png ^ -format "mean=%%[fx:mean]" ^ -set colorspace RGB ^ -colorspace sRGB ^ +write info: ^ fn_lin2.png mean=0.733041 |
|
set fnLINEAR=1 call %PICTBAT%fractNoise ^ . . . . . . fn_lin3.png %IMG7%magick ^ fn_lin3.png ^ -format "mean=%%[fx:mean]" ^ info: set fnLINEAR= mean=0.505775 |
How much difference does fnLINEAR make?
%IMG7%magick compare -metric RMSE ^ fn_lin1.png fn_lin3.png NULL:
2252.38 (0.0343691)
Despite the reasonably large difference, nearly 3%, I can't see any difference with a blink comparison. (Building a GIF blink-comparator doesn't work well here, as the quantisation introduces more differences.)
By default, the largest block size is half the smaller of the width and height, so 200 in this case. We can make it as large as we like.
call %PICTBAT%fn_zeroEnvVar set fnSEED=1234 call %PICTBAT%fractNoise ^ . . . 600 . . fn_lb1.png |
|
With large blocks, and power factor=1,
call %PICTBAT%fractNoise ^ . . . 600 . 1 fn_lb2.png Perhaps a similar texture to murky clouds. |
|
call %PICTBAT%fractNoise ^ . . 250 1000 . . fn_lb3.png |
|
set fnGRAY=1 call %PICTBAT%fractNoise ^ . . 1 10 . . fn_lb4.png set fnGRAY= Resembles magnified silver-halide film grain
|
We can create one-dimensional fractal noise images. As these do not display readily, we use graphLineCol.bat to make graphs.
Output dimension 600x1.
set fnGRAY=1 call %PICTBAT%fractNoise ^ 600 1 1 300 . . fn_c1.png call %PICTBAT%graphLineCol ^ fn_c1.png set fnGRAY= |
|
call %PICTBAT%fractNoise ^ 600 1 1 300 . . fn_c2.png call %PICTBAT%graphLineCol ^ fn_c2.png Why is high-frequency amplitude less than in fn_c1?
|
|
Reduce amplitude of low-frequency noise somewhat. call %PICTBAT%fractNoise ^ 600 1 1 300 . 0.5 fn_c2a.png call %PICTBAT%graphLineCol ^ fn_c2a.png |
|
Reduce amplitude of low-frequency noise more. call %PICTBAT%fractNoise ^ 600 1 1 300 . 1 fn_c2b.png call %PICTBAT%graphLineCol ^ fn_c2b.png These could be cross-sections of a mountain. |
|
call %PICTBAT%fractNoise ^ 600 1 4 300 . . fn_c3.png call %PICTBAT%graphLineCol ^ fn_c3.png |
|
Gaussian noise, without auto-level. set fnNOISE_TYPE=Gaussian set fnAUTO_LEVEL_EACH=0 set fnAUTO_LEVEL_END=0 call %PICTBAT%fractNoise ^ 600 1 4 300 . . fn_c4.png call %PICTBAT%graphLineCol ^ fn_c4.png |
|
Again, but absolute. [blah doesn't work] set fnABS_NSE=1 call %PICTBAT%fractNoise ^ 600 1 4 300 . . fn_c5.png call %PICTBAT%graphLineCol ^ fn_c5.png |
|
Again, but absolute, and power factor 1. call %PICTBAT%fractNoise ^ 600 1 4 300 . 1 fn_c6.png call %PICTBAT%graphLineCol ^ fn_c6.png |
|
Impulse noise, absolute, without auto-level. set fnNOISE_TYPE=Impulse call %PICTBAT%fractNoise ^ 600 1 4 300 . . fn_c7.png call %PICTBAT%graphLineCol ^ fn_c7.png set fnABS_NSE= set fnAUTO_LEVEL_END= set fnAUTO_LEVEL_EACH= set fnNOISE_TYPE= |
Effects can be applied to each octave. Set fnPROC_EACH to the desired processing. The value of this environment variable will be inserted into the appropriate part of the script. It must be valid IM syntax. It will be given a list of exactly one image, the octave at the final size. It should leave one image at the same size.
call %PICTBAT%fn_zeroEnvVar set fnSEED=1234
set fnPROC_EACH=^^^( +clone ^ -colorspace Gray ^ -auto-level -auto-gamma ^ -shade 135x30 ^ -auto-level ^^^) ^ -compose Hard_Light -composite ^ -auto-level -auto-gamma call %PICTBAT%fractNoise ^ . . . . . . fn_po1.png |
|
The same "-shade" process, grey,
set fnGRAY=1 call %PICTBAT%fractNoise ^ . . 3 64 . 0.5 fn_po2.png set fnGRAY= Perhaps weathered stone. |
|
For comparison, as previous but with no processing. set fnPROC_EACH= set fnGRAY=1 call %PICTBAT%fractNoise ^ . . 3 64 . 0.5 fn_po3.png set fnGRAY= |
|
set fnPROC_EACH=-evaluate Pow 2 call %PICTBAT%fractNoise ^ . . . . . . fn_po4.png |
|
set fnPROC_EACH=-threshold 50%%%% call %PICTBAT%fractNoise ^ . . . . . . fn_po5.png |
|
set fnPROC_EACH=-channel RGB -threshold 50%%%% +channel call %PICTBAT%fractNoise ^ . . . . . . fn_po6.png |
|
This uses process modules,
set fnPROC_EACH=^^^( -size 1x10000 gradient: -rotate 90 ^ -function Polynomial -1,2,0 -evaluate Pow 0.5 ^ -process 'cumulhisto norm' ^ -process 'mkhisto cumul norm' ^ ^^^) ^ -clut set fnIM=%IM7DEV% call %PICTBAT%fractNoise ^ . . . . . . fn_po7.png set fnIM= set fnPROC_EACH= |
Aesthetically, shaded images may be improved by increasing mid-tone contrast:
%IMG7%magick ^ fn_po1.png ^ -sigmoidal-contrast 5x50%% ^ fn_po1a.png |
|
%IMG7%magick ^ fn_po2.png ^ -sigmoidal-contrast 5x50%% ^ fn_po2a.png |
After a fractal noise image has been generated, it can be processed in many ways.
call %PICTBAT%fn_zeroEnvVar set fnSEED=1234 call %PICTBAT%fractNoise ^ 600 1200 . . . . fn_v1.png %IMG7%magick ^ fn_v1.png ^ -resize "600x400^!" ^ fn_v1.png |
|
call %PICTBAT%fractNoise ^ 1800 400 . . . . fn_v1a.png %IMG7%magick ^ fn_v1a.png ^ -resize "600x400^!" ^ fn_v1a.png |
|
call %PICTBAT%fractNoise ^ 1200 800 . . . . fn_v1b.png set PERSP=0,0 300,0 ^ 1199,0 899,0 ^ 0,799 0,399 ^ 1199,799 1199,399 %IMG7%magick ^ fn_v1b.png ^ -distort Perspective "%PERSP%" ^ -gravity North ^ -crop 600x400+0+0 +repage ^ fn_v1b.png |
|
Distort horizontally to an ellipse.
set fnGRAY= call %PICTBAT%fractNoise ^ . . . . . . fn_v1c.png %IMG7%magick ^ fn_v1c.png ^ -alpha Opaque ^ -virtual-pixel None ^ -fx ^ JH=(j^>h/2)?h-j-1:j;^ JHM=(h/2-JH)/h;^ FF=(JH==0)?0:1/(sqrt(1-4*JHM*JHM));^ p{((i/w-0.5)*FF+0.5)*w,j} ^ fn_v1ca.png |
|
Distort with the method from Polar distortions: planets. set PL_SC=0,0,#000,^ %%[fx:w-1],0,#f00,^ 0,%%[fx:h-1],#0f0,^ %%[fx:w-1],%%[fx:h-1],#ff0 %IMG7%magick ^ fn_v1c.png ^ -virtual-pixel None ^ -distort depolar 0 ^ ( +clone ^ -sparse-color bilinear "%PL_SC%" ^ -channel G ^ -function ArcSin 2,0,2,0 ^ +channel ^ ) ^ -compose Distort ^ -set option:compose:args 100%%x100%% ^ -composite ^ -distort polar 0 ^ fn_v1cb.png VP=none causes discontinuity. |
|
set fnGRAY=1 call %PICTBAT%fractNoise ^ . . 10 . . . fn_v2.png |
|
set fnGRAY=1 set fnNOISE_TYPE=Impulse set fnTILE=1 call %PICTBAT%fractNoise ^ . . . . . . fn_vpl2.png set fnTILE= set fnNOISE_TYPE= |
|
Polar (roll up) with VP=edge,
%IMG7%magick ^ fn_vpl2.png ^ -distort depolar 0 ^ ( +clone ^ -set colorspace sRGB ^ -sparse-color bilinear "%PL_SC%" ^ -channel G ^ -function ArcSin 2,0,2,0 ^ +channel ^ ) ^ -compose Distort ^ -set option:compose:args 100%%x100%% ^ -composite ^ ( -clone 0 ^ -virtual-pixel Edge ^ -distort polar 0 ^ ) ^ ( -clone 0 ^ -fill Black -colorize 100 ^ -fill White ^ -draw "circle 300,200 300,400" ^ ) ^ -delete 0 ^ -alpha off ^ -compose CopyOpacity -composite ^ fn_vpl2b.png |
|
%IMG7%magick ^ fn_v2.png ^ ( -size 1x500 gradient: -rotate 90 ^ -duplicate 19 +append +repage ) ^ -clut ^ -morphology edgein diamond:1 ^ -threshold 40%% ^ fn_v2a.png set fnGRAY= |
|
set fnGRAY=1 call %PICTBAT%fractNoise ^ . . . . . . fn_vg1.png |
|
Increase local contrast call %PICTBAT%exHvyBlr ^ fn_vg1.png . . fn_vg1b.png |
|
Apply a simple clut %IMG7%magick ^ fn_vg1b.png ^ ( xc:#008 xc:#0f0 +append +repage ) ^ -clut ^ fn_vg1c.png |
|
Colouring for wood set fnGRAY=1 call %PICTBAT%fractNoise ^ 1200 2400 . . . 1 fn_w1.png %IMG7%magick ^ fn_w1.png ^ -resize "600x400^!" ^ ( xc:#321 xc:#531 xc:#841 xc:#a52 +append +repage ) ^ -clut ^ fn_w1a.png set fnGRAY= |
|
The same fractal noise provides grain for wood %IMG7%magick ^ fn_w1.png ^ -resize "600x400^!" ^ ( -size 1x500 gradient: -rotate 90 ^ -evaluate sin 8 ^ -sigmoidal-contrast 5,10%% ^ +append +repage ) ^ -clut ^ fn_w1b.png |
|
Wood = Colouring * Grain %IMG7%magick ^ fn_w1a.png ^ fn_w1b.png ^ -compose Multiply -composite ^ fn_w1c.png |
|
Camouflage pattern. Integer interpolation. %IMG7%magick ^ fn_g2.png ^ -auto-level -auto-gamma ^ ( xc:#131 xc:#882 xc:#481 +append +repage ) ^ -interpolate Integer ^ -clut ^ fn_cam1.png |
|
Tweaked camouflage pattern. %IMG7%magick ^ fn_g2.png ^ -auto-level -auto-gamma ^ ( +clone ^ -sparse-color bilinear ^ "0,0,White 0,%%[fx:h-1],Black" ^ ) ^ -compose Hard_Light -composite ^ ( xc:#131 xc:#882 xc:#481 +append +repage ) ^ -interpolate Integer ^ -clut ^ fn_cam2.png |
|
Tweaked camouflage pattern, default interpolation. %IMG7%magick ^ fn_g2.png ^ -auto-level -auto-gamma ^ ( +clone ^ -sparse-color bilinear ^ "0,0,White 0,%%[fx:h-1],Black" ^ ) ^ -compose Hard_Light -composite ^ ( xc:#131 xc:#882 xc:#481 +append +repage ) ^ -clut ^ fn_cam3.png |
Film grain can be applied with "-compose Hard_Light".
When the grain image is sufficiently large: %IMG7%magick ^ toes.png ^ fn_lb4.png ^ -compose Hard_Light -composite ^ fn_grn1.png |
|
When the grain image is small, and needs to be tiled up: %IMG7%magick ^ fn_lb4.png -resize 10%% ^ +write mpr:TGRAIN +delete ^ toes.png ^ ( +clone ^ -tile mpr:TGRAIN -draw "color 0,0 reset" ^ ) ^ -compose Hard_Light -composite ^ fn_grn2.png |
To make fractal noise images that are tilable, set fnTILE to 1. This slows processing and may create a noticable edge effect, so I leave it off unless I really want it.
call %PICTBAT%fn_zeroEnvVar set fnSEED=1234 set fnTILE=1 call %PICTBAT%fractNoise ^ 300 200 . . . . fn_t1.png %IMG7%magick ^ fn_t1.png ^ ( +clone ) +append +repage ^ ( +clone ) -append +repage ^ fn_t1t.png |
|
call %PICTBAT%fractNoise ^ 300 200 . 300 . 1 fn_t2.png %IMG7%magick ^ fn_t2.png ^ ( +clone ) +append +repage ^ ( +clone ) -append +repage ^ fn_t2t.png |
|
set fnGRAY=1 call %PICTBAT%fractNoise ^ 300 200 . . . . fn_t3.png %IMG7%magick ^ fn_t3.png ^ ( +clone ) +append +repage ^ ( +clone ) -append +repage ^ fn_t3t.png set fnGRAY= set fnTILE= |
Note: it appears that "-virtual-pixel Tile" needs to be repeated within each parenthesis.
A tilable image that is tiled an integer number of times results in another tilable image.
Tilable images can be rolled up. The following are made from 2x2 tiles, so they also have symmetry.
%IMG7%magick ^ fn_t1t.png ^ -distort polar -1,0 ^ fn_t1tp1.png |
|
%IMG7%magick ^ fn_t1t.png ^ -distort polar 0,0 ^ fn_t1tp2.png |
|
%IMG7%magick ^ fn_t1t.png ^ -virtual-pixel None ^ -distort polar 0,0,300,200,-90,90 ^ -flip ^ -crop x50%%+0+0 +repage ^ fn_t1tp3.png |
|
%IMG7%magick ^ fn_t3t.png ^ -distort polar -1,0 ^ fn_t3tp1.png |
|
%IMG7%magick ^ fn_t3t.png ^ ( +clone ^ -sparse-color bilinear ^ "0,0,White 0,%%[fx:h-1],Black" ^ ) ^ -compose Hard_Light -composite ^ -distort polar -1,0 ^ -evaluate Pow 1.5 ^ fn_t3tp2.png |
|
%IMG7%magick ^ fn_t3tp2.png ^ +dither -posterize 4 ^ fn_t3tp3.png |
|
call %PICTBAT%lgstConnComp ^ fn_t3tp3.png ^ fn_t3tp3c.png |
|
Level, and quarter-circle clut
%IMG7%magick ^ fn_t3tp2.png ^ -level 50%%,100%% ^ ( -size 1x100 gradient: -rotate 90 ^ -function Polynomial -1,2,0 ^ -evaluate Pow 0.5 ^ ) ^ -clut ^ fn_t3tp2b.png |
|
Add 20% of height at top, resize up vertically,
pi/2 = 1.5708 = 1/0.6366 set SP=^ 0,0,#000,^ %%[fx:w-1],0,#f00,^ 0,%%[fx:h-1],#0f0,^ %%[fx:w-1],%%[fx:h-1],#ff0 %IMG7%magick ^ fn_t3tp2b.png ^ ( +clone ^ -scale x20%% ^ -fill Black -colorize 100 ^ ) ^ +swap -append +repage ^ -resize "100%%x157.08%%^!" ^ ( +clone ^ -sparse-color bilinear "%SP%" ^ -channel G ^ -function Polynomial -1,0,1 ^ -evaluate Pow 0.5 ^ -negate ^ +channel ^ ) ^ -compose Distort ^ -set option:compose:args 100%%x100%% ^ -composite ^ -resize "100%%x63.66%%^!" ^ -trim +repage ^ fn_t3tp2c.png |
|
%IMG7%magick ^ fn_t3tp2c.png ^ -shade 135x30 ^ fn_t3tp2d.png |
Tiling can have unexpected side-effects:
Without tiling. call %PICTBAT%fn_zeroEnvVar set fnSEED=1234 set fnFILTER=Box set fnTILE=0 call %PICTBAT%fractNoise ^ . . . . . 1 fn_to1.png |
|
With tiling. set fnTILE=1 call %PICTBAT%fractNoise ^ . . . . . 1 fn_to2.png set fnTILE= |
When creating a still image that will be animated, auto-levelling at each frame should be turned off, as any automatic change of tone for individual frames will generally result in flickering. The script exHvyBlr.bat may be useful for boosting local contrast.
As this image will be rolled up, we use fnTILE=1 to avoid disconinuity from the top-centre downwards.
The magick command processes the fractal noise image, following the steps shown above. It also saves intermediate images, which is helpful during development of the script.
call %PICTBAT%fn_zeroEnvVarAnim set fnSEED=1234 set fnGRAY=1 set fnTILE=1 call %PICTBAT%fractNoise ^ 600 600 . . . . fn_cld_a.png call %PICTBAT%exHvyBlr ^ fn_cld_a.png . . fn_cld_a.png set SP=^ 0,0,#000,^ %%[fx:w-1],0,#f00,^ 0,%%[fx:h-1],#0f0,^ %%[fx:w-1],%%[fx:h-1],#ff0 %IMG7%magick ^ fn_cld_a.png ^ ^( +clone ^ -sparse-color bilinear ^ "0,0,White 0,%%[fx:h-1],Black" ^ ^) ^ -compose Hard_Light -composite ^ -distort polar -1,0 ^ -level 50%%,100%% ^ +write fn_cld_b.png ^ ^( -size 1x100 gradient: -rotate 90 ^ -evaluate Pow 0.5 ^ -function Polynomial -1,2,0 ^ -evaluate Pow 0.5 ^ ^) ^ -clut ^ +write fn_cld_c.png ^ ^( +clone ^ -scale x20%% ^ -fill Black -colorize 100 ^ ^) ^ +swap -append +repage ^ -resize "100%%x157.08%%^!" ^ ^( +clone ^ -sparse-color bilinear "%SP%" ^ -channel G ^ -function Polynomial -1,0,1 ^ -evaluate Pow 0.5 ^ -negate ^ +channel ^ ^) ^ -compose Distort ^ -set option:compose:args 100%%x100%% ^ -composite ^ -resize "100%%x63.66%%^!" ^ -gravity South -crop 600x600+0+0 ^ +repage ^ fn_cld_d.png set fnTILE= set fnA_COLCYCMETH= set fnGRAY= set fnAUTO_GAM_END= set fnAUTO_LEVEL_END= |
Fractal noise images can be used as (relative) displacement maps for other images, which might also be fractal noise images.
set SRC1=fn_1.png set SRC2=fn_2.png set SRC3=fn_vg1.png %IMG7%magick ^ %SRC3% ^ -channel R -evaluate sin 1 ^ -channel G -evaluate cos 1 ^ +channel ^ fn_disp1.png |
|
%IMG7%magick ^ %SRC2% ^ %SRC1% ^ -compose Displace ^ -set option:compose:args 3%%x3%% ^ -composite ^ fn_disp2.png |
|
%IMG7%magick ^ %SRC2% ^ fn_disp1.png ^ -compose Displace ^ -set option:compose:args 3%%x3%% ^ -composite ^ fn_disp3.png |
|
%IMG7%magick ^ %SRC2% ^ ( fn_g1.png ^ -channel R -evaluate sin 1 ^ -channel G -evaluate cos 1 ^ +channel ^ ) ^ -compose Displace ^ -set option:compose:args 3%%x3%% ^ -composite ^ fn_disp4.png A "swirl" effect. |
|
As previous, but with 3 cycles of sin & cos. %IMG7%magick ^ %SRC2% ^ ( fn_g1.png ^ -channel R -evaluate sin 3 ^ -channel G -evaluate cos 3 ^ +channel ^ ) ^ -compose Displace ^ -set option:compose:args 3%%x3%% ^ -composite ^ fn_disp5.png |
|
Dispacing with narrow-band fractal noise. %IMG7%magick ^ %SRC2% ^ ( fn_g2.png ^ -channel R -evaluate sin 1 ^ -channel G -evaluate cos 1 ^ +channel ^ ) ^ -compose Displace ^ -set option:compose:args 3%%x3%% ^ -composite ^ fn_disp6.png |
|
As previous, but with 3 cycles of sin & cos. %IMG7%magick ^ %SRC2% ^ ( fn_g2.png ^ -channel R -evaluate sin 3 ^ -channel G -evaluate cos 3 ^ +channel ^ ) ^ -compose Displace ^ -set option:compose:args 3%%x3%% ^ -composite ^ fn_disp7.png |
|
As previous, but displacing a photograph. %IMG7%magick ^ toes.png ^ ( fn_g2.png ^ -channel R -evaluate sin 3 ^ -channel G -evaluate cos 3 ^ +channel ^ ) ^ -compose Displace ^ -set option:compose:args 3%%x3%% ^ -composite ^ fn_disp8.png This has introduced a false sharpness,
|
|
Supersampling is more accurate. %IMG7%magick ^ toes.png ^ -resize 400%% ^ ( fn_g2.png ^ -resize 400%% ^ -channel R -evaluate sin 3 ^ -channel G -evaluate cos 3 ^ +channel ^ ) ^ -compose Displace ^ -set option:compose:args 3%%x3%% ^ -composite ^ -resize 25%% ^ fn_disp9.png |
|
Fire. We make a base image,
%IMG7%magick ^ xc:#000 xc:#840 xc:#ff8 xc:#ff0 ^ xc:#f80 xc:#f00 xc:#a00 xc:#800 ^ xc:#000 ^ -append +repage ^ -resize "600x400^!" ^ +write fn_fire_base.png ^ ( fn_g2.png ^ -auto-gamma ^ -sigmoidal-contrast 10x50%% ^ ) ^ -compose Displace ^ -set option:compose:args 0%%x50%% ^ -composite ^ fn_fire.png |
The fractNoise.bat script contains features for animation. See Fractal noise animations for explanations and a variety of examples.
The method shown on this page synthesises an image from noise grid images and weighting factors. It constructs a Laplacian pyramid of noise, then collapses the pyramid to create an image. Multi-scale pyramids showed a method for constructing a Laplacian pyramid from an image, then collapsing the pyramid (possibly modified) to re-form the image (or a variation).
From fractal noise image fn_examp.png made above in section Text output, we use a script from Multi-scale pyramids to construct a pyramid.
call %PICTBAT%fn_zeroEnvVar set fnSEED=1234 set mkpDEBUG=1 set mkpHTM=1 set pyPREFIX=fn_rfn_ set pyIM=%IM7DEV% call %PICTBAT%mkLapPyr fn_examp.png fn_rfn.tiff set pyPREFIX=
Here is the pyramid created by the script:
%IMG7%magick identify fn_rfn.tiff
fn_rfn.tiff[0] TIFF 600x400 600x400+0+0 32-bit sRGB 4.58068MiB 0.001u 0:00.000 fn_rfn.tiff[1] TIFF 300x200 300x200+0+0 32-bit sRGB 0.001u 0:00.000 fn_rfn.tiff[2] TIFF 150x100 150x100+0+0 32-bit sRGB 0.001u 0:00.000 fn_rfn.tiff[3] TIFF 75x50 75x50+0+0 32-bit sRGB 0.001u 0:00.000 fn_rfn.tiff[4] TIFF 38x25 38x25+0+0 32-bit sRGB 0.001u 0:00.000 fn_rfn.tiff[5] TIFF 19x13 19x13+0+0 32-bit sRGB 0.001u 0:00.000 fn_rfn.tiff[6] TIFF 9x6 9x6+0+0 32-bit sRGB 0.001u 0:00.000 fn_rfn.tiff[7] TIFF 5x3 5x3+0+0 32-bit sRGB 0.001u 0:00.000 fn_rfn.tiff[8] TIFF 600x400 600x400+0+0 32-bit Grayscale Gray 0.001u 0:00.000
Octave | Grid | Grid, resized up | Histogram of resized grid | Difference |
---|---|---|---|---|
7 | ||||
6 | ||||
5 | ||||
4 | ||||
3 | ||||
2 | ||||
1 | ||||
0 |
The pyramid created by mkLapPyr.bat is clearly different to the more colourful pyramid that was used to create the image, as shown above in Grid images. The enlarged grids approach a Laplacian distribution, except for the last, which is more Gaussian. (To my naked eye, the final enlarged grid appears a smooth gray. With a magnifying glass, I clearly see the noise.)
However, the final difference for this new pyramid is zero:
%IMG7%magick identify -format "min=%%[fx:minima] max=%%[fx:maxima]" fn_rfn.tiff[%mklpNUM_OCTAVES%]
min=0.5 max=0.5
And from this new pyramid file, we can attempt to reconstruct the original image. Then we compare the reconstruction with the original.
%pyIM%magick ^ -script fn_rfn_mklp_recon.scr if ERRORLEVEL 1 exit /B 1 %pyIM%magick ^ fn_rfn_mklp_recon.miff ^ fn_rfn_recon.png if ERRORLEVEL 1 exit /B 1 %pyIM%magick ^ -metric RMSE ^ fn_examp.png ^ fn_rfn_recon.png ^ NULL: >fn_rfn_comp.lis 2^>^&1 magick: no images found for operation `-metric' at CLI arg 1 @ error/operation.c/CLIOption/5479. |
It is the same.
Fractal noise pyramids are built with the sum method of weighting. The script mkLapPyr.bat by default uses the max method of weighting, but we can tell it to use the sum method. However, this is less successful.
set mkpDEBUG=1 set mkpHTM=1 set pyPREFIX=fn_rfn_sum_ set pyWEIGHTING=sum call %PICTBAT%mkLapPyr fn_examp.png fn_rfn_sum.tiff set pyWEIGHTING= set pyPREFIX=
Here is the pyramid created by the script:
Octave | Grid | Grid, resized up | Histogram of resized grid | Difference |
---|---|---|---|---|
7 | ||||
6 | ||||
5 | ||||
4 | ||||
3 | ||||
2 | ||||
1 | ||||
0 |
This pyramid is less successful. Because the weighting is less. each grid doesn't reduce the difference by much, so that doesn't remove much data, so the next grid still retains low-frequency data. The final grid clearly contains both high and low frequency data. This more closely resembles a Gaussian pyramid.
The final difference for this new pyramid is not zero. Visually, it looks like the input image with reduced saturation.
%IMG7%magick identify -format "min=%%[fx:minima] max=%%[fx:maxima]" fn_rfn_sum.tiff[%mklpNUM_OCTAVES%]
min=0.201641 max=0.793014
We can attempt to reconstruct the original image. Then we compare the reconstruction with the original.
%pyIM%magick ^ -script fn_rfn_sum_mklp_recon.scr %IMG7%magick ^ fn_rfn_sum_mklp_recon.miff ^ fn_rfn_sum_recon.png %pyIM%magick compare ^ -metric RMSE ^ fn_examp.png ^ fn_rfn_sum_recon.png ^ NULL: >fn_rfn_sum_comp.lis 2^>^&1 0 (0) |
It is the same. The reconstruction does work, but only because we have used the final difference.
On my laptop, the script fractNoise.bat takes about 1.6 seconds to make a 600x400 pixel image, of which 1.1s is in fnInit.bat. Of the 0.5s in fnOne.bat, 0.3s is in the magick command.
For a 7500x5000 image, it takes 33.5s, of which 31.5s is in the magick command.
Translating the script to C (or a faster script language) could result in a five-fold performance improvement for small images.
A sequence of animated fractal noise makes one call to fnInit.bat, then one call to fnOne.bat per frame. There is further scope for improving animations within a compiled program, as the noise pyramid files would not need to be re-read for every frame.
A process module could be written for IM, or code might be implemented as a separate command. However, fractNoise.bat accepts up to about 26 arguments, and implementing each as a "-define" would be messy.
Does round-trip create fractal noise image from pyramid, then pyramid from the image, work? blah.
Currently, the amplitudes of octaves are weighted by their frequency, using a power factor. This can weight them all the same, or emphasise either the lower or the higher frequencies. It cannot, for example, weight the middle frequencies more than high and low frequencies. This feature may be desirable.
A possible mechanism is to use a clut, which could be Gaussian or any other shape. (See the Clut cookbook.) Then each frequency would use the appropriate look-up from the clut, perhaps using Process modules: interppix.
del fn_*0000*.png call %PICTBAT%fn_zeroEnvVar set fnWW= set fnHH=
For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.
This script removes environment variables that are used by fractNoise.bat. It is automatically generated from fractNoise.bat when this page is built.
set fnSEED= set fnGRAY= set fnNOISE_TYPE= set fnABS_NSE= set fnFILTER= set fnIM= set fnPREFIX= set fnNG_EXT= set fnLINEAR= set fnAUTO_LEVEL_EACH= set fnAUTO_LEVEL_END= set fnAUTO_GAM_END= set fnRD_PYR= set fnWR_PYR= set fnPROC_EACH= set fnTXT_OUT= set fnA_FRM_NUM= set fnA_COL= set fnA_DX= set fnA_DY= set fnA_ZM= set fnA_POW_FAC= set fnA_COLCYCMETH=
rem Set fractNoise environment variables for animation. call %PICTBAT%fn_zeroEnvVar set fnAUTO_LEVEL_EACH=0 set fnAUTO_LEVEL_END=0 set fnAUTO_GAM_END=0 set fnA_COLCYCMETH=sinarc2o
This is a simple wrapper for the two scripts below, fnInit.bat and fnOne.bat, that do the real work.
rem Make fractal noise. @rem %1 %2 Width, height in pixels. @rem %3 minimum block size in pixels. [1] @rem %4 maximum block size in pixels. [min(w,h)/2] @rem %5 block factor: Block size is increased by this factor from min to max. >=1 [2] @rem %6 power factor for amplitude proportional to frequency. [Default 0.0] @rem 0 for all frequencies have same amplitude; @rem > 0 (eg 1, 1.5) for highest frequencies have lowest amplitude. @rem %7 output file. [fn.png] @rem Returns fnNUM_OCTAVES number of octaves. @rem Also uses: @rem @rem fnSEED Seed for pseudo-random generator. [Default: no seed] @rem fnGRAY if 1, creates grayscale output, otherwise RGB. @rem fnNOISE_TYPE Noise type: random, gaussian, uniform, etc. @rem fnABS_NSE if 1, takes absolute value of noise. @rem fnFILTER Resize filter. @rem fnIM location of IM's "magick" to be used. @rem fnPREFIX prefix for working files (but not output file). [fn_] @rem fnNG_EXT extension for noise grid files. [.miff] @rem fnLINEAR if 1, converts noise to linear, the result to non-linear. @rem fnAUTO_LEVEL_EACH whether to apply auto-levelling to each octave. [0] @rem fnAUTO_LEVEL_END whether to apply auto-levelling at the end. [1] @rem 0 no auto-levelling, @rem 1 synchronised auto-levelling, @rem 2 unsynchronised (more colouful) auto-levelling. @rem ? Equalize @rem ? Gaussianise @rem fnAUTO_GAM_END whether to apply auto-gamma at the end. [1] @rem fnRD_PYR 0 or 1, override automatic choice about reading pyramid files instead of creating them. @rem fnWR_PYR 0 or 1, override automatic choice about writing pyramid files. @rem fnPROC_EACH a process to be applied to each octave. @rem fnTXT_OUT if 1, writes some text data. @rem @rem fnA_FRM_NUM frame number, typically an integer. If blank, no animation. @rem Animation control. @rem fnA_COL percentage colour change per frame. 100%==0%. [0] @rem fnA_DX horizontal displacement per frame, pixels, positive=pan right (image moves left). [0] @rem fnA_DY vertical displacement per frame, pixels, positive=pan down (image moves up). [0] @rem fnA_ZM zoom factor per frame, eg 0.998. <1 zooms out, shrinks image. [1] @rem fnA_POW_FAC power factor for animation. [0] @rem fnA_COLCYCMETH colour cycling method. [null or sinarc2o] @rem @rem @rem First release: 28 September 2015. @rem @rem Updated: @rem 24-September-2022 for IM v7. @rem @rem TODO: power defined by clut image file, so we can emphasise middle frequencies. @setlocal enabledelayedexpansion @call echoOffSave set pyGRAPHIC=0 set pyWEIGHTING=sum set OUTFILE=%7 if "%OUTFILE%"=="." set OUTFILE= if "%OUTFILE%"=="" set OUTFILE=fn.png call %PICTBAT%fnInit %1 %2 %3 %4 %5 %6 if ERRORLEVEL 1 exit /B 1 call %PICTBAT%fnOne %OUTFILE% if ERRORLEVEL 1 exit /B 1 call echoRestore @endlocal & set fnOUTFILE=%OUTFILE%&set fnPYR_FILE=%fnPYR_FILE%& set fnWW=%fnWW%& set fnHH=%fnHH%& set fnNUM_OCTAVES=%NUM_OCTAVES%& set fnPOW_FAC=%POW_FAC%
rem Fractal noise initialisation: sets environment variables @rem %1 %2 Width, height in pixels. @rem %3 minimum block size in pixels. [1] @rem %4 maximum block size in pixels. [min(w,h)/2] @rem %5 block factor: Block size is increased by this factor from min to max. >=1 [2] @rem %6 power factor for amplitude proportional to frequency. [Default 0.0] @rem 0 for all frequencies have same amplitude; @rem > 0 (eg 1, 1.5) for highest frequencies have lowest amplitude. @rem @rem Updated: @rem 24-September-2022 for IM v7 @rem @rem No compulsory parameters @rem No setlocal set fix=99 if not "!fix!"=="99" ( echo %0: must be run in enabledelayedexpansion exit /B 1 ) set fix= set fnWW=%1 if "%fnWW%"=="." set fnWW= if "%fnWW%"=="" set fnWW=600 set fnHH=%2 if "%fnHH%"=="." set fnHH= if "%fnHH%"=="" set fnHH=400 set BLK_MIN=%3 if "%BLK_MIN%"=="." set BLK_MIN= if "%BLK_MIN%"=="" set BLK_MIN=1 set BLK_MAX=%4 if "%BLK_MAX%"=="." set BLK_MAX= if "%BLK_MAX%"=="" ( for /F "usebackq" %%L in (`%IMG7%magick identify ^ -format "BLK_MAX=%%[fx:max(%fnWW%,%fnHH%)/2]" ^ xc:`) do set %%L ) set BLK_FAC=%5 if "%BLK_FAC%"=="." set BLK_FAC= if "%BLK_FAC%"=="" set BLK_FAC=2 set POW_FAC=%6 if "%POW_FAC%"=="." set POW_FAC= if "%POW_FAC%"=="" set POW_FAC=0 echo %0: %fnWW% %fnHH% %BLK_MIN% %BLK_MAX% %BLK_FAC% %POW_FAC% if "%fnIM%"=="" set fnIM=%IMG7% if "%fnPREFIX%"=="" set fnPREFIX=fn_ if "%fnNG_EXT%"=="" set fnNG_EXT=.tiff set pyIM=%fnIM% set pyPREFIX=%fnPREFIX% set pyLINEAR=%fnLINEAR% set pyWEIGHTING=sum set BLK_LIS=%fnPREFIX%blk.lis set NUM_OCTAVES= rem call %PICTBAT%mkpVar %fnWW% %fnHH% %3 %4 %5 %6 call %PICTBAT%mkpVar %fnWW% %fnHH% %BLK_MIN% %BLK_MAX% %BLK_FAC% %POW_FAC% if ERRORLEVEL 1 ( echo %0: mkpVar failed exit /B 1 ) rem if not exist %BLK_LIS% ( rem echo %0: Can't find BLK_LIS [%BLK_LIS%] rem exit /B 1 rem ) rem rem rem for /F "tokens=*" %%L in (%BLK_LIS%) do set "%%L" if "%NUM_OCTAVES%"=="" ( echo %0: NUM_OCTAVES has no value exit /B 1 ) if not "%fnA_FRM_NUM%"=="" call %PICTBAT%mkpAnimVar if "%fnNOISE_TYPE%"=="" ( set NSE=+noise Random ) else ( set NSE=+noise %fnNOISE_TYPE% ) if "%fnGRAY%"=="1" ( set "sBASE_COL=gray^^^(50%%%%^^^)" set sONE_CHAN=-channel R -separate +channel ) else ( set "sBASE_COL=rgb^^^(50%%%%,50%%%%,50%%%%^^^)" set sONE_CHAN= ) if "%fnAUTO_LEVEL_EACH%"=="1" ( set sAUTO_EACH=-auto-level ) else if "%fnAUTO_LEVEL_EACH%"=="2" ( set sAUTO_EACH=-channel RGB -auto-level +channel ) else ( set sAUTO_EACH= ) if "%fnAUTO_LEVEL_END%"=="" set fnAUTO_LEVEL_END=1 if "%fnAUTO_LEVEL_END%"=="1" ( set sAUTO_END=-auto-level ) else if "%fnAUTO_LEVEL_END%"=="2" ( set sAUTO_END=-channel RGB -auto-level +channel ) else ( set sAUTO_END= ) if "%fnAUTO_GAM_END%"=="" set fnAUTO_GAM_END=1 if "%fnAUTO_GAM_END%"=="1" ( set sAUTO_END=%sAUTO_END% -auto-gamma ) if "%fnABS_NSE%"=="1" ( set sABS=-solarize 50%%%% -negate ) else ( set sABS= ) if "%fnA_FRM_NUM%"=="" ( set RD_PYR= set WR_PYR= if "%fnA_COLCYCMETH%"=="" set fnA_COLCYCMETH=null call %PICTBAT%colCyclStr !fnA_COLCYCMETH! 0 ) else ( if "%fnA_COLCYCMETH%"=="" set fnA_COLCYCMETH=sinarc2o if "%fnA_FRM_NUM%"=="0" ( set RD_PYR= set WR_PYR=1 set ZM_F=1 set DX_F=0 set DY_F=0 rem ) else ( rem Wrong place! fnInit is run _before_ we know an actual frame number. rem But it may be called with fnA_FRM_NUM=0, to initialise for an animation. rem set RD_PYR=1 rem set WR_PYR= rem rem call xyCoord %fnWW% %fnHH% %fnA_DX% %fnA_DY% rem rem for /F "usebackq" %%L in (`%IMG7%magick identify ^ rem %PREC% ^ rem -format "ZM_F=%%[fx:pow(%fnA_ZM%,%fnA_FRM_NUM%)]\nDX_F=%%[fx:!xycX!*%fnA_FRM_NUM%]\nDY_F=%%[fx:!xycY!*%fnA_FRM_NUM%]" ^ rem xc:`) do set %%L rem rem if "%fnTXT_OUT%"=="1" echo fnA_FRM_NUM=%fnA_FRM_NUM% ZM_F=!ZM_F! DX_F=!DX_F! DY_F=!DY_F! ) ) if not "%fnRD_PYR%"=="" set RD_NG=%fnRD_PYR% if not "%fnWR_PYR%"=="" set WR_PYR=%fnWR_PYR% if not "%fnTXT_OUT%"=="" set pyTXT_OUT=%fnTXT_OUT% rem No endlocal
rem Makes one fractal noise image. rem Assumes fnInit.bat has been called. @rem %1 output file. [fn.png] @rem No compulsory parameters @rem @rem Updated: @rem 24-September-2022 for IM v7 @rem @setlocal enabledelayedexpansion @call echoOffSave rem call %PICTBAT%setInOut %1 fno set TMP_BAT=%fnPREFIX%fn.bat set TMP_SCR=%fnPREFIX%fn.scr del %TMP_SCR% 2>nul set OUTFILE=%1 if "%OUTFILE%"=="." set OUTFILE= if "%OUTFILE%"=="" set OUTFILE=fn.png set PREC=-precision 15 ( echo %fnIM%magick rem echo -compose Mathematics -define compose:args=0,1,1,-0.5 REM echo -compose Mathematics -define compose:args=0,0.5,0.5,0 if not "%fnFILTER%"=="" echo -filter %fnFILTER% if not "%fnSEED%"=="" echo -seed %fnSEED% echo -compose Plus -virtual-pixel Tile %PREC% ) >%TMP_BAT% if "%NUM_OCTAVES%"=="" ( echo %0: NUM_OCTAVES has no value exit /B 1 ) :: ------------------ Loop through octaves------------------ set sWR_PYR= set sRD_PYR= set sTILE= set PYR_FILE=%fnPREFIX%fnpyr%fnNG_EXT% rem echo PYR_FILE=!PYR_FILE! RD_PYR=%RD_PYR% WR_PYR=%WR_PYR% set sDBG_GRD= set sDBG_FULL= set BLK_SZ=%BLK_MIN% set /A Nm1=%NUM_OCTAVES%-1 set ERROR=0 rem FIXME?: we auto-each both in sRD_PYR and after PROC_EACH. for /L %%N in (0,1,%Nm1%) do ( if "%RD_PYR%"=="1" ( set sRD_PYR=%PYR_FILE%[%%N] ) else ( set sRD_PYR=-size !N_BLK_W.%%N!x!N_BLK_H.%%N! xc:%sBASE_COL% %NSE% %sLIN% %sAUTO_EACH% if "%WR_PYR%"=="1" set sWR_PYR=+write mpr:GRD%%N ) rem echo sRD_PYR=!sRD_PYR! sWR_PYR=!sWR_PYR! if "%fnTILE%"=="1" ( set FWi= for /F "usebackq" %%L in (`%IMG7%magick identify ^ %PREC% ^ -format "FWi=%%[fx:%fnWW%/!N_BLK_W.%%N!]\nFHt=%%[fx:%fnHH%/!N_BLK_H.%%N!]" ^ xc:`) do set %%L if "!FWi!"=="" set ERROR=1 set sTILE=-virtual-pixel Tile +distort SRT "0,0,!FWi!,!FHt!,0,0,0" +repage rem FIXME: when we get two distort SRTs, we should merge. rem echo sTILE=!sTILE! ) set sANIM=!ccsImStr! -virtual-pixel tile -distort SRT 0,0,1,0,0,0 if not "%fnA_FRM_NUM%"=="" ( call xyCoord %fnWW% %fnHH% %fnA_DX% %fnA_DY% for /F "usebackq" %%L in (`%IMG7%magick identify ^ %PREC% ^ -format "ZM_F=%%[fx:pow^(%fnA_ZM%,%fnA_FRM_NUM%^)]\nDX_F=%%[fx:!xycX!*%fnA_FRM_NUM%]\nDY_F=%%[fx:!xycY!*%fnA_FRM_NUM%]" ^ xc:`) do set %%L if "%fnTXT_OUT%"=="1" echo fnA_FRM_NUM=%fnA_FRM_NUM% ZM_F=!ZM_F! DX_F=!DX_F! DY_F=!DY_F! for /F "usebackq" %%L in (`%IMG7%magick identify ^ %PREC% ^ -format "COL=%%[fx:%fnA_COL%*%fnA_FRM_NUM%*!AN_AMP.%%N!]\nDX=%%[fx:!DX_F!*!AN_AMP.%%N!*!N_BLK_W.%%N!/%fnWW%]\nDY=%%[fx:!DY_F!*!AN_AMP.%%N!*!N_BLK_H.%%N!/%fnHH%]" ^ xc:`) do set %%L rem echo %0: N=%%N AN_AMP.%%N=!AN_AMP.%%N! COL=!COL! DX=!DX! DY=!DY! call %PICTBAT%colCyclStr %fnA_COLCYCMETH% !COL! if ERRORLEVEL 1 echo %0: Bad colCyclStr && exit /B 1 set sANIM=!ccsImStr! -virtual-pixel tile -distort SRT !DX!,!DY!,1,0,0,0 if "%fnTXT_OUT%"=="1" echo . AN_AMP.%%N=!AN_AMP.%%N! sANIM=!sANIM! ) if "%fnDEBUG%"=="1" ( set sDBG_GRD=+write %fnPREFIX%grd_%%N.png set sDBG_FULL=+write %fnPREFIX%full_%%N.png ) echo ^( !sRD_PYR! !sWR_PYR! !sDBG_GRD! !sANIM! !sTILE! -resize "%fnWW%x%fnHH%^^^!" !sDBG_FULL! %fnPROC_EACH% %sAUTO_EACH% %sABS% !sLEVEL.%%N! ^) >>%TMP_SCR% if "%fnTXT_OUT%"=="1" echo -format "levels %%N: %%%%[fx:minima] %%%%[fx:maxima]\n" +write info: >>%TMP_SCR% if %%N GTR 0 echo -compose Mathematics -define compose:args=0,1,1,-0.5 -composite >>%TMP_SCR% for /F "usebackq" %%L in (`%IMG7%magick identify ^ %PREC% ^ -format "BLK_SZ=%%[fx:!BLK_SZ!*%BLK_FAC%]" ^ xc:`) do set %%L ) ( if "%fnTXT_OUT%"=="1" echo -format "levels before AL: %%%%[fx:minima] %%%%[fx:maxima]\n" +write info: if not "%sONE_CHAN%"=="" echo %sONE_CHAN% if not "%sDELIN%"=="" echo %sDELIN% if not "%sAUTO_END%"=="" echo %sAUTO_END% echo +depth echo +write %OUTFILE% if "%WR_PYR%"=="1" ( echo +delete for /L %%N in (0,1,%Nm1%) do @( @echo mpr:GRD%%N ) echo -write %PYR_FILE% echo -exit ) ) >>%TMP_SCR% if %ERROR%==1 ( echo %0: ERROR is 1 exit /B 1 ) cPrefix /p0 /i%TMP_BAT% /r" ^" echo -script %TMP_SCR% >>%TMP_BAT% rem type %TMP_BAT% rem type %TMP_SCR% call %TMP_BAT% if ERRORLEVEL 1 exit /B 1 >>%TMP_BAT% if "%fnTXT_OUT%"=="1" ( echo Created %OUTFILE% if "%WR_PYR%"=="1" echo ... and %PYR_FILE% ) call echoRestore @endlocal & set fnOUTFILE=%OUTFILE%&set fnPYR_FILE=%PYR_FILE%& set fnWW=%fnWW%& set fnHH=%fnHH%& set fnNUM_OCTAVES=%NUM_OCTAVES%& set fnPOW_FAC=%POW_FAC%
@rem %1 is image width @rem %2 is image height @rem %3 is an x-coord, @rem possibly fractional, possibly negative, possibly suffixed with c or % or p @rem %4 is an y-coord, likewise @rem Returns actual pixel coords, possibly fractional, as xycX and xycY @rem and as rounded integers in xycXi and xycYi. @rem @rem Updated: @rem 15-July-2022 for IM v7. @setlocal enabledelayedexpansion @call echoOffSave set WW=%1 set HH=%2 set X=%3 set chX=%X:~-1% set vX=%X:~0,-1% set Y=%4 set chY=%Y:~-1% set vY=%Y:~0,-1% if "%chX%"=="%%" set chX=c if "%chY%"=="%%" set chY=c if "%chX%"=="c" ( set vX=%vX%*%1/100 ) else if "%chX%"=="p" ( set vX=%vX%*%1 ) else ( set vX=%X% ) if "%chY%"=="c" ( set vY=%vY%*%2/100 ) else if "%chY%"=="p" ( set vY=%vY%*%2 ) else ( set vY=%Y% ) for /F "usebackq" %%L in (`%IMG7%magick identify ^ -precision 16 ^ -format "vX=%%[fx:%vX%]\nvY=%%[fx:%vY%]\nvXi=%%[fx:int(%vX%+0.5)]\nvYi=%%[fx:int(%vY%+0.5)]" ^ xc:`) do set %%L if ERRORLEVEL 1 ( echo %0: vX=[%vX%] vY=[%vY%] exit /B 1 ) call echoRestore @endlocal & set xycX=%vX%& set xycY=%vY%& set xycXi=%vXi%& set xycYi=%vYi%
rem Extrapolate away from heavy blur. Increases local contrast. rem A bit like tone-mapping, HDR, High Dynamic Range. @rem @rem %2 is resize amount (inverse of blur radius) as percentage of image size. @rem Small amounts (0.1-5) spread impact over large area. [0.5] @rem Large amounts (25-100) give unsharp mask. @rem %3 is extrapolation as percentage. @rem 0 is blur; 100 is no effect (unchanged image), 150 is subtle, 15000 is massive. @rem %4, if given, is output filename. @rem @rem See also hvyBlrDiff.bat @rem @rem Updated: @rem 26-July-2022 for IM v7. @rem @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal @call echoOffSave call %PICTBAT%setInOut %1 ehb set BLUR_PC=%2 if "%BLUR_PC%"=="." set BLUR_PC= if "%BLUR_PC%"=="" set BLUR_PC=0.5 set BLEND_PC=%3 if "%BLEND_PC%"=="." set BLEND_PC= if "%BLEND_PC%"=="" set BLEND_PC=200 if not "%4"=="" set OUTFILE=%4 FOR /F "usebackq" %%L IN (`%IMG7%magick identify -format "WW=%%w\nHH=%%h" %INFILE%`) DO set %%L %IMG7%magick ^ %INFILE% ^ ^( +clone ^ -resize %BLUR_PC%%% -resize "%WW%x%HH%^!" ^ ^) ^ +swap ^ -compose Blend -define compose:args=%BLEND_PC% -composite ^ %OUTFILE% call echoRestore @endlocal & set ehbOUTFILE=%OUTFILE%
All images on this page were created by the commands shown, using:
%IMG7%magick -version
Version: ImageMagick 7.1.1-20 Q16-HDRI x86 98bb1d4:20231008 https://imagemagick.org Copyright: (C) 1999 ImageMagick Studio LLC License: https://imagemagick.org/script/license.php Features: Cipher DPC HDRI OpenCL OpenMP(2.0) Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib Compiler: Visual Studio 2022 (193532217)
To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG or TIFF or MIFF to JPG.
Source file for this web page is fracnse.h1. To re-create this web page, run "procH1 fracnse".
This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.
Anyone is permitted to re-publish this page, but only for non-commercial use.
Anyone is permitted to link to this page, including for commercial use.
Page version v1.0 28-August-2015.
Page created 02-Mar-2024 17:19:49.
Copyright © 2024 Alan Gibson.