snibgo's ImageMagick pages

Reverse fractal noise

An image can be represented by a multi-scale pyramid.

blah.

A multi-scale pyramid is an image represented by the addition of a series images, each smaller then the previous, each representing a different level of detail. As the image in the series are of different sizes, they can be said to be a "pyramid" of images, and we can talk about "building" the pyramid from an image, or "collapsing" the pyramid to make an image. If we build a pyramid then immediately collapse it, we should reconstruct the original image.

Images at the top of the pyramid are the smallest, perhaps 1x1 pixel. They carry information about low-frequency data. Images at the bottom are the largest, perhaps the same size as the original image. High-frequency data is stored in those lower, larger images.

Each level of the pyramid might be a down-sized version of the input image; this is called a Gaussian pyramid. In a Gaussian pyramid, each layer is made by a lowpass filter: higher frequencies have been removed. Alternatively it may be a down-sized version of the difference between the upsized previous level and its input; this is called a Laplacian pyramid. Each layer in a Laplacian pyramid is formed by a bandpass filter: it records data about a narrow band of frequencies, with both higher and lower frequencies removed.

In the literature, multi-scale pyramids:

This implementation relaxes those restrictions. This means that a pyramid may not exactly represent an input image, so a final difference image is also created. When a pyramid is collaped, adding in this final difference may be required to reconstruct the original.

Because the frequencies often double at each level, levels are commonly referred to as octaves (by analogy with music).

I use the word grid to describe the image at a level in the pyramid.

Literature describes two operations required to make each grid: convolution (blurring), followed by sub-sampling. I combine these into one, using IM's -resize operator.

Applications for multi-scale pyramids include:

Scripts on this page assume that the version of ImageMagick in %IMDEV% has been built with various process modules. See Process modules.

References and further reading

recon could start with smallest, resizing to next level and adding, then resize that and so on. More accurate roundtrip? Less accurate?

The method

The method shown on Fractal noise synthesises an image from noise grid images and weighting factors. The reverse is possible: an image can be analysed into grid images of predetermined sizes and weights. This might be called "reverse fractal noise", although the images are not fractals (as they are not necessarily self-similar or coherent), and the grid images are not noise. A better name might be "analyse into grids", so the script is analGrids.bat.

A fractal noise image is defined entirely by the noise grid images, and the weight to be applied to each. Once these are defined, nothing else is needed to generate the fractal image.

Can we define any image at all as "fractal noise" under this scheme? Yes. We simply create one noise grid image, the same size as the input image, with the same pixels. This is the only octave in the fractal, with block size of one. This is clearly trivial.

For a given set of grid image sizes, each with an assigned weight, some images cannot be deconstructed into those grids. For example, suppose we weight all grids equally, and the image to be deconstructed is a single white pixel in the centre of a large black background. Then we certainly need a block size of 1 to be included in the set. The other, larger, block sizes will blur the single white pixel with the black, so none of them will contain white. But for equal-weighted grids to sum to white, corresponding pixels in every resized grid must be white. So the image of a single white pixel in the centre of black cannot be represented by a set of two or more grids with non-zero weights.

More interestingly, I think an arbitrary image (such as a photograph) could easily be converted to a fractal noise image. For example, suppose we want only three octaves, and we know the required sizes of the three noise grid images, and equal weighting is to be give to each frequency.

  1. Resize the input image to the smallest grid (largest frequency). This is the largest-frequency grid.
  2. Resize that grid to the full size. Divide this by 3. Subtract it from the input image. This remainder needs putting in the other grid images.
  3. Resize the remainder to the next grid size, and this is the next grid.
  4. Resize that grid to the full size. Divide by 2, and subtract from the remainder. This new remainder needs putting in the final grid image.
  5. Resize the remainder to the final grid size, and this is the final grid.

Weights shown are correct for power factor = zero. Would be adjusted for other power factors.

(Above steps are wrong. FractNoise needs grid in range 0..1. Then need to divide by 3 or whatever.)

Subtraction has to be biased, so we can represent negative results.

This algorithm requires the octaves to be contructed with the lowest frequency first.

Under the current scheme, if we have sensible weights for the octaves, I think some images can't be converted exactly to fractal noise images. (Hmm. I dunno.) But we can probably get close.

What would be the point in doing this?

First-cut scheme: use fractNoise to generate grids of required size. Other script overwrites grid data. But other script also needs to know power factor, so fractNoise also exports fnPOW_FAC.

ASIDE: This is another way to segment images: by frequency of "noise". And instead of downsizing, we could take median with a large radius, do the subtraction, use smaller radius for median, and so on.

Example

We start with the toes image:

set SRC=toes.png

for /F "usebackq" %%L in (`%IM%identify ^
  -format "WW=%%w\nHH=%%h" ^
  %SRC%`) do set %%L
toes.png

The difference images are saved and shown purely for illustration.

%IM%convert ^
  %SRC% +write mpr:SRC ^
 ^
  -resize "7x6^!" ^
  +write rfn_grd_2.png ^
  -resize "%WW%x%HH%^!" ^
  +write rfn_full_2.png ^
  -evaluate Divide 1 ^
  mpr:SRC ^
  -compose Mathematics -define compose:args=0,0.5,-0.5,0.5 -composite ^
  +write rfn_diff_2.png ^
 ^
  -resize "49x36^!" ^
  +write rfn_grd_1.png ^
  -resize "%WW%x%HH%^!" ^
  +write rfn_full_1.png ^
  -evaluate Divide 1 ^
  rfn_diff_2.png ^
  -compose Mathematics -define compose:args=0,0.5,-0.5,0.5 -composite ^
  +write rfn_diff_1.png ^
 ^
  -resize "%WW%x%HH%^!" ^
  +write rfn_grd_0.png ^
  -resize "%WW%x%HH%^!" ^
  +write rfn_full_0.png ^
  rfn_diff_1.png ^
  -compose Mathematics -define compose:args=0,0.5,-0.5,0.5 -composite ^
  +write rfn_diff_0.png ^
  NULL:

Blank lines are used to visually separate the procesing of the three octaves.

Octave Grid Grid, resized up Difference after subtracting
resized weighted grid
from previous difference
2 rfn_grd_2.png rfn_full_2.png rfn_diff_2.png
1 rfn_grd_1.png rfn_full_1.png rfn_diff_1.png
0 rfn_grd_0.png rfn_full_0.png rfn_diff_0.png
%IM%convert rfn_diff_0.png -format "min=%%[fx:minima] max=%%[fx:maxima]\n" info: 
min=0.500008 max=0.500008

The final difference is 50% gray. (So why isn't it exactly 0.500000? See Fifty percent.) Hence the final octave has reproduced all the detail.

We can express this in formulae. If t is the input toes image, g0, g1 and g2 are the grid images, and d0, d1 and d2 are the difference images, then:

d2 = (t-g2+1)/2
2.d2 = t-g2+1
d2 -> g1

d1 = (d2-g1+1)/2
d1 -> g0
d0=(d1-g0+1)/2 = 0

From this, it follows that:

t = g2 + 2.g1 + 4.g0 - 3

The weights are halved at each octave. Or, put another way:

gx = 2.g0 + g1 - 1
t = 2.gx + g2 - 1

Adding the grid images, after resizing and weighting each, should reconstruct the source image:

%IM%convert ^
  ( rfn_grd_0.png -resize "%WW%x%HH%^!" -evaluate Divide 1 ) ^
  ( rfn_grd_1.png -resize "%WW%x%HH%^!" -evaluate Divide 1 ) ^
  -compose Mathematics -define compose:args=0,1,2,-1 -composite ^
  ( rfn_grd_2.png -resize "%WW%x%HH%^!" -evaluate Divide 1 ) ^
  -compose Mathematics -define compose:args=0,1,2,-1 -composite ^
  rfn_recon_toes.png
rfn_recon_toes.png

A different method for the same result:

%IM%convert ^
  rfn_grd_2.png ^
  rfn_grd_1.png ^
  rfn_grd_0.png ^
  -resize "%WW%x%HH%^!" ^
  ( +clone -fill White -colorize 100 ) ^
  -poly "1,1 2,1 4,1 -3,1" ^
  rfn_recon2_toes.png
rfn_recon2_toes.png

Check we ended up where we started, successfully reconstructing the toes image:

%IM%compare -metric RMSE -format "" toes.png rfn_recon_toes.png NULL: >rfn_comp1.lis 2^>^&1
%IM%compare -metric RMSE -format "\n" toes.png rfn_recon2_toes.png NULL: >>rfn_comp1.lis 2^>^&1
1.74696 (2.66569e-005)
1.74696 (2.66569e-005)

Interestingly, the sum of the sizes (in bytes) of the grid files is less than the size of the toes file:

dir /on rfn_grd*.png toes.png |cHead /p0 /i- /h8 /x 
02/10/2015  16:23           283,236 rfn_grd_0.png
02/10/2015  16:23            10,086 rfn_grd_1.png
02/10/2015  16:23               896 rfn_grd_2.png
02/10/2015  15:45               355 rfn_grd2_0.png
02/10/2015  15:45               289 rfn_grd2_0x.png
02/10/2015  15:45               275 rfn_grd2_1.png
02/10/2015  15:45               259 rfn_grd2_2.png
30/01/2014  09:54           320,268 toes.png
               8 File(s)        615,664 bytes
               0 Dir(s)  85,784,711,168 bytes free

fractNoise.bat sums the noise grids, after resizing each to the full size image, like this:

t = w0.g0 + w1.g1 + w2.g2
  = w2.g2 + w1.g1 + w0.g0

where w0 + w1 + w2 = 1
eg w0 = w1 = w2 = 1/3

t - w0.g0 -> d0
d0 = w1.g1 + w2.g2
d0 - w1.g1 -> d1
d1 = w2.g2

Or:

t shrunk -> g2
t - w2.g2 -> d2
d2 shrunk -> g1
d2 = w1.g1 + w0.g0
d2 - w1.g1 -> d1
d1 shrunk -> g0
d1 = w0.g0
d1 - w0.g0 ->d2
d2 == 0?

But this means that t can be zero only where all upsized grids are zero, and can be 100% only where all upsized grids are 100%.

%IM%convert ^
  xc:Black ^
  -bordercolor White -border 140 ^
  rfn_blw.png

%IM%convert ^
  xc:White ^
  -bordercolor Black -border 140 ^
  rfn_blw.png

set SRC=rfn_blw.png

for /F "usebackq" %%L in (`%IM%identify ^
  -format "WW=%%w\nHH=%%h" ^
  %SRC%`) do set %%L

%IM%convert ^
  %SRC% +write mpr:SRC ^
 ^
  -resize "7x6^!" ^
  +write rfn_grd2_2.png ^
  -resize "%WW%x%HH%^!" ^
  +write rfn_full2_2.png ^
  mpr:SRC ^
  -compose Mathematics -define compose:args=0,1,-0.33333333333,0 -composite ^
  +write rfn_diff2_2.png +write mpr:DIFF2 ^
 ^
  -resize "49x36^!" ^
  +write rfn_grd2_1.png ^
  -resize "%WW%x%HH%^!" ^
  +write rfn_full2_1.png ^
  mpr:DIFF2 ^
  -compose Mathematics -define compose:args=0,1,-0.33333333333,0 -composite ^
  +write rfn_diff2_1.png +write mpr:DIFF1 ^
 ^
  +write rfn_grd2_0.png ^
  +write rfn_full2_0.png ^
  mpr:DIFF1 ^
+write info: ^
  -compose Mathematics -define compose:args=0,1,-0.33333333333,0 -composite ^
  +write rfn_diff2_0.png ^
  NULL:

rem DIFF2 = DIFF1 - DIFF1/3
rem       = 2/3 * DIFF1
rem Kludge

rem No, kludge would be to add 3*rfn_diff2_0
%IM%convert ^
  rfn_grd2_0.png ^
  ( rfn_diff2_0.png -evaluate Multiply 2 ) ^
  -compose Plus -composite ^
  rfn_grd2_0x.png

BUG: rfn_diff2_0.png should be zero?

SRC - g2/3 - g1/3 - g0/3

Check: this is r = t - w2.g2 - w1.g1 - w0.g0

Octave Grid Grid, resized up Difference after subtracting
resized weighted grid
from previous difference
2 rfn_grd2_2.png rfn_full2_2.png rfn_diff2_2.png
1 rfn_grd2_1.png rfn_full2_1.png rfn_diff2_1.png
0 rfn_grd2_0.png rfn_full2_0.png rfn_diff2_0.png

Reconstructing with this scheme:

blah:

%IM%convert ^
  ( rfn_grd2_0.png -resize "%WW%x%HH%^!" -evaluate Divide 3 ) ^
  ( rfn_grd2_1.png -resize "%WW%x%HH%^!" -evaluate Divide 3 ) ^
  -compose Plus -composite ^
  ( rfn_grd2_2.png -resize "%WW%x%HH%^!" -evaluate Divide 3 ) ^
  -compose Plus -composite ^
  rfn_diff2_0.png ^
  -compose Plus -composite ^
  rfn_recon3_toes.png
rfn_recon3_toes.png

BUG: Why do we need rfn_diff2_0.png?

Check we ended up where we started, successfully reconstructing the toes image:

%IM%compare -metric RMSE -format "RMSE=" %SRC% rfn_recon3_toes.png NULL: >rfn_comp3.lis 2^>^&1

%IM%compare -metric AE -format "\nAE=" %SRC% rfn_recon3_toes.png NULL: >>rfn_comp3.lis 2^>^&1
RMSE=8.38236 (0.000127907)
AE=84

Currently calculation of final remainder so rem=100% makes nearly white even if sum of ordinary grids is black. Remainder has same weight as sum of ordinary grids. Can we tweak calculation of final remainder so rem=0% makes black even if sum of ordinary grids is white? Yes, if 0 to 100% in rem is taken to mean -100% .. +200%. Then even in worst case, adding rem will restore original. This suggests that in decomposition, the first remainder may not be sufficient. A second remainder may not be black, but the third should be.

We can process each octave differently:

%IM%convert ^
  ( rfn_grd_2.png -sigmoidal-contrast 10,50%% ) ^
  rfn_grd_1.png ^
  rfn_grd_0.png ^
  -resize "%WW%x%HH%^!" ^
  ( +clone -fill White -colorize 100 ) ^
  -poly "1,1 2,1 4,1 -3,1" ^
  rfn_sharper_toes.png
rfn_sharper_toes.png

analGrids.bat script

The script analGrids.bat creates and runs an ImageMagick script that analyses an image into grids, buiding the pyramid. It also creates (but doesn't run) a script that does the opposite: synthesise an image from the grids, collapsing the pyramid.

When we analyse an image into grids, we subtract each levelled grid from the previous difference, and add 50%. As we move through the octaves the differences become closer to zero (which is 50%).

For the opposite process, synthesising grids into an image, we level each grid then add to the previous result, less 50%.

Levelling applies the weights.

for /F "usebackq" %%L in (`%IM%identify ^
  -format "WW=%%w\nHH=%%h" ^
  toes.png`) do set %%L

set fnPREFIX=revtoes_
call %PICTBAT%fractNoise %WW% %HH% . . . 0
set agrDEBUG=1
set agrHTM=1
call %PICTBAT%analGrids toes.png
set agrHTM=
set agrDEBUG=

revtoes_blk.lis:

NUM_OCTAVES=7
IMG_WW=267
IMG_HH=233
N_BLK_W.0=267
N_BLK_H.0=233
AMP.0=0.142857142857143
M1AMP.0=1
sLEVEL.0=
N_BLK_W.1=134
N_BLK_H.1=117
AMP.1=0.142857142857143
M1AMP.1=1
sLEVEL.1=
N_BLK_W.2=67
N_BLK_H.2=58
AMP.2=0.142857142857143
M1AMP.2=1
sLEVEL.2=
N_BLK_W.3=33
N_BLK_H.3=29
AMP.3=0.142857142857143
M1AMP.3=1
sLEVEL.3=
N_BLK_W.4=17
N_BLK_H.4=15
AMP.4=0.142857142857143
M1AMP.4=1
sLEVEL.4=
N_BLK_W.5=8
N_BLK_H.5=7
AMP.5=0.142857142857143
M1AMP.5=1
sLEVEL.5=
N_BLK_W.6=4
N_BLK_H.6=4
AMP.6=0.142857142857143
M1AMP.6=1
sLEVEL.6=

The arguments to Mathematics a,b,c,d: a=0, b>0, c<0, d=0.5. The ratio b/-c should be equal to the ratio of the weights of the previous two grids. Either b=1 and -1<c<=0, or c=-1 and 0<=b<1. Maybe?

Or we "+level" the grid with the lower weight, to match the other weight, and use 0,1,-1,0.5. Yup, this is it. blah.

revtoes_agr_lap.scr:

f:\prose\PICTURES\toes.png +write mpr:SRC 
-resize "4x4!"
+write revtoes_grd_6.miff
+write mpr:GRD6
-resize "267x233!"
+write revtoes_full_6.miff 
mpr:SRC
-compose Mathematics -define compose:args=0,1,-1,0.5 -composite
+write revtoes_diff_6.miff
+write mpr:DIFF6
-resize "8x7!"
+write revtoes_grd_5.miff
+write mpr:GRD5
-resize "267x233!"
+write revtoes_full_5.miff 
mpr:DIFF6
-compose Mathematics -define compose:args=0,1,-1,0.5 -composite
+write revtoes_diff_5.miff
+write mpr:DIFF5
-resize "17x15!"
+write revtoes_grd_4.miff
+write mpr:GRD4
-resize "267x233!"
+write revtoes_full_4.miff 
mpr:DIFF5
-compose Mathematics -define compose:args=0,1,-1,0.5 -composite
+write revtoes_diff_4.miff
+write mpr:DIFF4
-resize "33x29!"
+write revtoes_grd_3.miff
+write mpr:GRD3
-resize "267x233!"
+write revtoes_full_3.miff 
mpr:DIFF4
-compose Mathematics -define compose:args=0,1,-1,0.5 -composite
+write revtoes_diff_3.miff
+write mpr:DIFF3
-resize "67x58!"
+write revtoes_grd_2.miff
+write mpr:GRD2
-resize "267x233!"
+write revtoes_full_2.miff 
mpr:DIFF3
-compose Mathematics -define compose:args=0,1,-1,0.5 -composite
+write revtoes_diff_2.miff
+write mpr:DIFF2
-resize "134x117!"
+write revtoes_grd_1.miff
+write mpr:GRD1
-resize "267x233!"
+write revtoes_full_1.miff 
mpr:DIFF2
-compose Mathematics -define compose:args=0,1,-1,0.5 -composite
+write revtoes_diff_1.miff
+write mpr:DIFF1
+write revtoes_grd_0.miff
+write mpr:GRD0
+write revtoes_full_0.miff 
mpr:DIFF1
-compose Mathematics -define compose:args=0,1,-1,0.5 -composite
+write revtoes_diff_0.miff
+write mpr:DIFF0
+delete
mpr:GRD0
mpr:GRD1
mpr:GRD2
mpr:GRD3
mpr:GRD4
mpr:GRD5
mpr:GRD6
mpr:DIFF0

revtoes_agr_recon.scr:

( revtoes_lap.tiff[6]
-resize "267x233!"
 )
( revtoes_lap.tiff[5]
-resize "267x233!"
 )
-compose Mathematics -define compose:args=0,1,1,-0.5 -composite
( revtoes_lap.tiff[4]
-resize "267x233!"
 )
-compose Mathematics -define compose:args=0,1,1,-0.5 -composite
( revtoes_lap.tiff[3]
-resize "267x233!"
 )
-compose Mathematics -define compose:args=0,1,1,-0.5 -composite
( revtoes_lap.tiff[2]
-resize "267x233!"
 )
-compose Mathematics -define compose:args=0,1,1,-0.5 -composite
( revtoes_lap.tiff[1]
-resize "267x233!"
 )
-compose Mathematics -define compose:args=0,1,1,-0.5 -composite
( revtoes_lap.tiff[0]
 )
-compose Mathematics -define compose:args=0,1,1,-0.5 -composite
revtoes_lap.tiff[7]
-compose Mathematics -define compose:args=0,1,1,-0.5 -composite
Octave Grid Grid, resized up Histogram of resized grid Difference
6 revtoes_grd_6.miffjpg revtoes_full_6.miffjpg revtoes_full_6_h_glc.png revtoes_diff_6.miffjpg
5 revtoes_grd_5.miffjpg revtoes_full_5.miffjpg revtoes_full_5_h_glc.png revtoes_diff_5.miffjpg
4 revtoes_grd_4.miffjpg revtoes_full_4.miffjpg revtoes_full_4_h_glc.png revtoes_diff_4.miffjpg
3 revtoes_grd_3.miffjpg revtoes_full_3.miffjpg revtoes_full_3_h_glc.png revtoes_diff_3.miffjpg
2 revtoes_grd_2.miffjpg revtoes_full_2.miffjpg revtoes_full_2_h_glc.png revtoes_diff_2.miffjpg
1 revtoes_grd_1.miffjpg revtoes_full_1.miffjpg revtoes_full_1_h_glc.png revtoes_diff_1.miffjpg
0 revtoes_grd_0.miffjpg revtoes_full_0.miffjpg revtoes_full_0_h_glc.png revtoes_diff_0.miffjpg
%IM%convert %fnPREFIX%diff_0.miff -format "min=%%[fx:minima] max=%%[fx:maxima]\n" info: 
min=0.500008 max=0.500008

The final difference image is entirely zero. It seems we have a method for equal weights, or any power_factor <= 0.

Attempt to reconstruct the source:

%IMDEV%convert ^
  @%fnPREFIX%agr_recon.scr ^
  +write revtoes_recon_m.png ^
  %fnPREFIX%diff_0.miff ^
  -compose Mathematics -define compose:args=0,1,1,-0.5 -composite ^
  revtoes_recon.png
revtoes_recon_m.pngjpg revtoes_recon.pngjpg

How close is it?

%IM%compare -metric RMSE toes.png revtoes_recon.png NULL: 
67.7151 (0.00103327)

That was good, and no need for a remainder.

Another method, assuming we can fit all resized grids into memory, and they have equal weights: We have 7 octaves, so "-layers merge" does 7 composites. We need to distribute the 0.5 offset required for each addition over 7 composites.

f:\prose\PERSONAL>ccalc = (0.5*6)/7 = exit
0.4285714285714286
%IMDEV%convert ^
  %fnPREFIX%full_*.miff ^
  -compose Mathematics -define compose:args=0,1,1,-0.4285714285714286 ^
  -background Black -layers merge ^
  -format "%[fx:minima] %[fx:maxima]" ^
  +write info: ^
  revtoes_recon_2.png
revtoes_recon_2.png

How close is it?

%IM%compare -metric RMSE toes.png revtoes_recon_2.png NULL: 
compare.exe: image widths or heights differ `toes.png' @ error/compare.c/CompareImageCommand/990.

Scripts

For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.

analGrids.bat

rem Analyses image %1 into grid files, using data from a block list file.

@rem Companion script to fractNoise.bat

@rem Also uses:
@rem
@rem   agrDEBUG if 1, creates other image files (full and diff).
@rem   agrHTM if 1, creates HTM file
@rem
@rem   fnIM location of IM's convert to be used.
@rem   fnPREFIX prefix for working files. [fn_]
@rem   fnNG_EXT extension for noise grid files. [.miff]
@rem   fnTXT_OUT if 1, writes some text data.

if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal enabledelayedexpansion

rem @call echoOffSave

call %PICTBAT%setInOut %1 agr


if "%fnIM%"=="" set fnIM=%IM%

if "%fnPREFIX%"=="" set fnPREFIX=fn_
if "%fnNG_EXT%"=="" set fnNG_EXT=.miff

if "%fnNG_EXT%"==".miff" (
  set EXTEXT=jpg
) else (
  set EXTEXT=
)

if not exist %INFILE% (
  echo %0: Can't find INFILE [%INFILE%]
  exit /B 1
)

set TMP_BAT=%fnPREFIX%agr.bat
set LAP_SCR=%fnPREFIX%agr_lap.scr
set HTM_TAB=%fnPREFIX%agr.htm
set RECON_SCR=%fnPREFIX%agr_recon.scr
set PYR_FILE=%fnPREFIX%lap.tiff
set BLK_LIS=%fnPREFIX%blk.lis

if not exist %BLK_LIS% (
  echo %0: Can't find BLK_LIS [%BLK_LIS%]
  exit /B 1
)

del %RECON_SCR% 2>nul

for /F "tokens=*" %%L in (%BLK_LIS%) do set %%L

if "%NUM_OCTAVES%"=="" (
  echo %0: NUM_OCTAVES has no value
  exit /B 1
)

for /F "usebackq" %%L in (`%IM%identify ^
  -format "WW=%%w\nHH=%%h" ^
  %INFILE%`) do set %%L

set BAD_DIMS=1
if "%WW%"=="%IMG_WW%" if "%HH%"=="%IMG_HH%" set BAD_DIMS=0
if %BAD_DIMS%==1 (
  echo %0: Dimensions don't match: "%WW%" neq "%IMG_WW%" or "%HH%" neq "%IMG_HH%"
  exit /B 1
)

echo %INFILE% +write mpr:SRC >%LAP_SCR%

if "%agrHTM%"=="1" (
  echo ^<table^>
  echo ^<th^>Octave^</th^>^<th^>Grid^</th^>^<th^>Grid, resized up^</th^>^<th^>Histogram of resized grid^</th^>^<th^>Difference^</th^>
)>%HTM_TAB%

set /A LAST_OCT=%NUM_OCTAVES%-1

set DONE_FIRST=0

set PREV_DIFF=SRC

for /L %%N in (%LAST_OCT%,-1,0) do (

  set NG_FILE=%fnPREFIX%grd_%%N%fnNG_EXT%

  rem echo N_BLK_W.%%N=!N_BLK_W.%%N! N_BLK_H.%%N=!N_BLK_H.%%N! AMP.%%N=!AMP.%%N! M1AMP.%%N=!M1AMP.%%N!

  if !M1AMP.%%N!==1 (
    set sLEVEL=
  ) else (
    for /F "usebackq" %%L in (`%IM%identify ^
      -format "LO=%%[fx:50*(1-!M1AMP.%%N!)]\nHI=%%[fx:50*(1+!M1AMP.%%N!)]" ^
      xc:`) do set %%L

    set sLEVEL=+level !LO!%%,!HI!%%
  )

  set DO_RES=1
  if !N_BLK_W.%%N!==%WW% if !N_BLK_H.%%N!==%HH% set DO_RES=0

  set WRDIFF=1
  if not %%N==0 if not "%agrDEBUG%"=="1" set WRDIFF=0

  ( if !DO_RES!==1 echo -resize "!N_BLK_W.%%N!x!N_BLK_H.%%N!^!"
    echo +write !NG_FILE!
    echo +write mpr:GRD%%N
    if !DO_RES!==1 echo -resize "%WW%x%HH%^!"
    if "%agrDEBUG%"=="1" echo +write %fnPREFIX%full_%%N%fnNG_EXT% !sLEVEL!
    echo mpr:!PREV_DIFF!
    echo -compose Mathematics -define compose:args=0,1,-1,0.5 -composite
    set PREV_DIFF=DIFF%%N
    if "!WRDIFF!"=="1" echo +write %fnPREFIX%diff_%%N%fnNG_EXT%
    echo +write mpr:!PREV_DIFF!
  )>>%LAP_SCR%

  ( echo ^( %PYR_FILE%[%%N]
    if !DO_RES!==1 echo -resize "%WW%x%HH%^!"
    echo !sLEVEL! ^)

    if !DONE_FIRST!==0 (
      set DONE_FIRST=1
    ) else (
      echo -compose Mathematics -define compose:args=0,1,1,-0.5 -composite
    )
  )>>%RECON_SCR%

  if "%agrHTM%"=="1" (
    echo ^<tr^>
    echo ^<td^>%%N^</td^>
    echo ^<td^>^<img src="!NG_FILE!%EXTEXT%" /^>^</td^>
    echo ^<td^>^<img src="%fnPREFIX%full_%%N%fnNG_EXT%%EXTEXT%" /^>^</td^>
    echo ^<td^>^<img src="%fnPREFIX%full_%%N_h_glc.png" /^>^</td^>
    echo ^<td^>^<img src="%fnPREFIX%diff_%%N%fnNG_EXT%%EXTEXT%" /^>^</td^>
    echo ^</tr^>
  )>>%HTM_TAB%
)

:: List the MPRs, read to write to a tiff.
( echo +delete
  for /L %%N in (0,1,%LAST_OCT%) do @(
    @echo mpr:GRD%%N
  )
  echo mpr:DIFF0
)>>%LAP_SCR%

:: Add final difference to reconstruction.
(
  echo %PYR_FILE%[%NUM_OCTAVES%]
  echo -compose Mathematics -define compose:args=0,1,1,-0.5 -composite
)>>%RECON_SCR%

if "%agrHTM%"=="1" echo ^</table^> >>%HTM_TAB%

%fnIM%convert ^
  @%LAP_SCR% ^
  %PYR_FILE%

if "%agrHTM%"=="1" (
  for /L %%N in (0,1,%LAST_OCT%) do @(
    %IMDEV%convert ^
      %fnPREFIX%full_%%N%fnNG_EXT% ^
      -process 'mkhisto capnumbuckets 512 norm' ^
      %fnPREFIX%full_%%N_h%fnNG_EXT%

    call %PICTBAT%graphLineCol %fnPREFIX%full_%%N_h%fnNG_EXT% . . 0
  )
)

rem type %LAP_SCR%
rem type %HTM_TAB%
rem type %RECON_SCR%

call echoRestore

@endlocal

All images on this page were created by the commands shown, using:

%IM%identify -version
Version: ImageMagick 6.9.1--6 Q16 x64 2015-06-20 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules OpenMP 
Delegates (built-in): bzlib cairo freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps rsvg tiff webp xml zlib

To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG to JPG.

Source file for this web page is revfracnse.h1. To re-create this web page, run "procH1 revfracnse".


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 17-September-2015.

Page created 02-Oct-2015 15:23:57.

Copyright © 2015 Alan Gibson.