(* :Title: Geometry *) (* :Context: ImageProcessing`Geometry` *) (* :Author: Mariusz Jankowski *) (* :Summary: Geometry defines interpolation, decimation, rotation and warping functions and matrix manipulation functions *) (* :Copyright: 2000, Mariusz Jankowski *) (* :Package Version: 1.1 *) (* :Mathematica Version: 4.0 *) (* :History: Version 1.0 by Mariusz Jankowski, January 2000. Version 1.1 by Mariusz Jankowski, March, 2001. fixed Compiler error in ImageWarp added argument to FixedPad *) (* :Keywords: interpolate, decimate, rotate, warp *) (* :Sources: *) (* :Warnings: *) (* :Limitations: *) (* :Requirements: ImageProcessing`ImageData` Developer` *) (* :Discussion: *) (* :Examples: *) (***********************************************************************) BeginPackage["ImageProcessing`Geometry`", { "ImageProcessing`ImageData`" } ] (***********************************************************************) (*----------- usage messages: functions --------------------------------------------------------------------*) ColumnThread::usage = "ColumnThread[mat1,mat2,..] takes a sequence of matrices and threads the elements in the respective columns." Decimate::usage = "Decimate[list, h, k] returns a list smoothed by filter h and reduced in dimension by integer factor k." DownSample::usage = "DownSample[img, k] returns every k-th element of img." FixedPad::usage = "FixedPad[list, dim] is a utility function that pads list by replicating the first and last elements of list." ImageRotate::usage = "ImageRotate[mat, a, pivot] returns mat rotated counterclockwise from horizontal by angle a around the pivot. The default pivot point is (Dimensions[mat]+1)/2." ImageWarp::usage = "ImageWarp[mat, s] performs a general spatial (polynomial) transformation defined by matrix s." Interpolate::usage = "Interpolate[list, h, k] returns a list smoothed by filter h and increased in dimension by integer factor k." MatrixJoin::usage = "MatrixJoin[{{mat1, mat2,..},..}] takes a nested list of matrices and joins them together." MatrixThread::usage = "MatrixThread[{{mat1, mat2,..},..}] takes a nested list of matrices and threads the elements of the matrices." PeriodicPad::usage = "PeriodicPad[list, dim] is a utility function that pads list with periodic extensions of length dim." Reflect::usage = "Reflect[img] returns img with dimensions reversed." Replicate::usage = "Replicate[img, k] magnifies img by integer factor k using zero-order hold interpolation." Resize::usage = "Resize[img, dims] returns an image of dimensions dims by uniformly resampling img." RowThread::usage = "RowThread[mat1, mat2, ..] takes a sequence of matrices and threads the elements in the respective rows." UpSample::usage = "UpSample[img, k, v] threads k-1 elments with value v (default 0) between pixels of img." WarpMatrix::usage = "WarpMatrix[xy, uv, k] returns a general spatial transformation matrix given control points xy and uv and the transformation polynomial order k." ZeroPad::usage = "ZeroPad[list, dim] is a utility function that pads a list of any dimensions with dim zeros." (*--------------------------------------------------------------- usage messages: options ---------------------------------------------------------------*) (*-------------------------------------------------------------------- error messages ---------------------------------------------------------------------*) UpSample::order = "order k must be positive" ; DownSample::order = "order k must be positive" ; DownSample::rank = "TensorRank of argument 1 does not match length of argument 2" ; Interpolate::rank = "TensorRank of argument 1 does not match length of argument 2" ; UpSample::rank = "TensorRank of argument 1 does not match length of argument 2" ; Replicate::rank = "TensorRank of argument 1 does not match length of argument 2" ; Interpolate::order = "order k must be positive" ; Decimate::order = "order k must be positive" ; Replicate::order = "order k must be positive" ; ZeroPad::rank = "TensorRank of argument 1 does not match number of remaining arguments" ; FixedPad::rank = "TensorRank of argument 1 does not match number of remaining arguments" ; PeriodicPad::rank = "TensorRank of argument 1 does not match number of remaining arguments" ; (***********************************************************************) Begin["`Private`"] (***********************************************************************) protected = Unprotect[ UpSample, DownSample, Decimate, Interpolate, Resize, Reflect, Replicate, ZeroPad, PeriodicPad, FixedPad, MatrixJoin, ColumnThread, RowThread, MatrixThread, ImageWarp, WarpMatrix, ImageRotate ] ; Get["Developer`"] (*-------------------------------------------------------------------- Options --------------------------------------------------------------------*) Options[ImageRotate] = {InterpolationOrder -> 1} Options[ImageWarp] = {InterpolationOrder -> 1} Options[Resize] = {InterpolationOrder -> 1} (* --------------- Spatial transformations ----------------------------- *) ImageRotate[m_?ipMatrixQ, a_?ipNumericQ, (opts___)?OptionQ ] := m /; Chop[Cos[a]] == 1 ImageRotate[m_?ipMatrixQ, a_?ipNumericQ, (opts___)?OptionQ ] := Reverse[m] /; Chop[Cos[a]] == -1 ImageRotate[m_?ipMatrixQ, a_?ipNumericQ, (opts___)?OptionQ ] := Transpose[Reverse[m]] /; Chop[Sin[a]] == 1 ImageRotate[m_?ipMatrixQ, a_?ipNumericQ, (opts___)?OptionQ ] := Transpose[m] /; Chop[Sin[a]] == -1 ImageRotate[m_?ipMatrixQ, a_?ipNumericQ, (opts___)?OptionQ ] := ImageRotate[m, a, (Dimensions[m]+1)/2., opts ] ImageRotate[m_?ipMatrixQ, a_?ipNumericQ, {x0_?NumericQ, y0_?NumericQ}, (opts___)?OptionQ] := Module[{rot, nr, nc, k}, {nr, nc} = Dimensions[m]; k = InterpolationOrder /. Flatten[{opts, Options[ImageRotate]}]; rot = N[{{Cos[a], -Sin[a], -x0*Cos[a] + x0*Cos[a]^2 + y0*Sin[a] + x0*Sin[a]^2}, {Sin[a], Cos[a], -y0*Cos[a] + y0*Cos[a]^2 - x0*Sin[a] + y0*Sin[a]^2}}]; Switch[k, 0, rot0[N[m], rot, nr, nc], 1, rot1[N[m], rot, nr, nc], _, rotN[ ListInterpolation[N[m], {{1, nr}, {1, nc}}, InterpolationOrder -> k ]][rot, nr, nc]]]; ImageRotate[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, etc__] := ImageData[ImageRotate[img[[1]], etc], opts] ; ImageRotate[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, etc__] := MeshedImageData[ImageRotate[PlanarImageData[img], etc]] ; ImageRotate[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, etc__] := ImageData[ToPackedArray[ImageRotate[#, etc]& /@ img[[1]]], opts] ; ImageWarp[m_?ipMatrixQ, w:{{_,_}..}, opts___?OptionQ] := Module[{k, nr, nc}, {nr, nc} = Dimensions[m]; k = InterpolationOrder /. Flatten[{opts, Options[ImageWarp]}]; Switch[ k, 0, warp0[N[m], w, nr, nc], 1, warp1[N[m], w, nr, nc], _, warpN[ ListInterpolation[N[m], {{1, nr}, {1, nc}}, InterpolationOrder->k ]][w, nr, nc]] ]; ImageWarp[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, etc___] := ImageData[ImageWarp[img[[1]], etc], opts] ; ImageWarp[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, etc___] := MeshedImageData[ImageWarp[PlanarImageData[img], etc]] ; ImageWarp[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, etc___] := ImageData[ToPackedArray[ImageWarp[#, etc]& /@ img[[1]]], opts] ; WarpMatrix[xy: {{_?NumericQ, _?NumericQ} ..}, uv: {{_?NumericQ, _?NumericQ} ..}, k_Integer] := PseudoInverse[wpoly[#, k] & /@ xy].uv (* -- support functions ------------- *) rot0 = Compile[{{arr, _Real, 2}, {w, _Real, 2}, {nr, _Integer}, {nc, _Integer}}, Table[(If[1 <= #1[[1]] <= nr && 1 <= #1[[2]] <= nc, arr[[#1[[1]], #1[[2]]]], 0.] & )[ Round[w . {r, c, 1.}]], {r, 1., nr}, {c, 1., nc}]]; rot1 = Compile[{{arr, _Real, 2}, {w, _Real, 2}, {nr, _Integer}, {nc, _Integer}}, Table[(If[1 <= #1[[1]] <= nr && 1 <= #1[[2]] <= nc, bilinear[arr, #1[[1]], #1[[2]], nr, nc], 0.] & )[w . {r, c, 1.}], {r, 1., nr}, {c, 1., nc}], {{bilinear[_, _, _, _, _], _Real}}]; rotN[fun_] := Compile[{{w, _Real, 2}, {nr, _Integer}, {nc, _Integer}}, Table[(If[1 <= #1[[1]] <= nr && 1 <= #1[[2]] <= nc, fun[#1[[1]], #1[[2]]], 0.] & )[w . {r, c, 1.}], {r, 1., nr}, {c, 1., nc}], {{fun[_, _], _Real}}]; warp0 = Compile[{{arr, _Real, 2}, {w, _Real, 2}, {nr, _Integer}, {nc, _Integer}}, Block[{rng}, rng = Range[IntegerPart[Sqrt[Length[w]] - 1]]; Table[(If[1 <= #1[[1]] <= nr && 1 <= #1[[2]] <= nc, arr[[#1[[1]], #1[[2]]]], 0.] & )[Round[Flatten[Outer[Times, Join[{1}, r^rng], Join[{1}, c^rng ], 1]].w]], {r, 1., nr}, {c, 1., nc}] ]]; warp1 = Compile[{{arr, _Real, 2}, {w, _Real, 2}, {nr, _Integer}, {nc, _Integer}}, Block[{rng}, rng = Range[IntegerPart[Sqrt[Length[w]] - 1]]; Table[(If[1 <= #1[[1]] <= nr && 1 <= #1[[2]] <= nc, bilinear[arr, #1[[1]], #1[[2]], nr, nc], 0.] & )[Flatten[Outer[Times, Join[{1}, r^rng], Join[{1}, c^rng ], 1]].w], {r, 1., nr}, {c, 1., nc}]], {{bilinear[_, _, _, _, _], _Real}}]; warpN[fun_] := Compile[{{w, _Real, 2}, {nr, _Integer}, {nc, _Integer}}, Block[{rng}, rng = Range[IntegerPart[Sqrt[Length[w]] - 1]]; Table[( If[(1 <= #[[1]] <= nr) && (1 <= #[[2]] <= nc), fun[#[[1]], #[[2]]], 0.] &)[Flatten[Outer[Times, Join[{1}, r^rng], Join[{1}, c^rng ], 1]].w], {r, 1., nr}, {c, 1., nc}] ]] ; bilinear = Compile[{{arr, _Real, 2}, {r, _Real}, {c, _Real}, {nr, _Integer}, {nc, _Integer}}, Module[{r0, c0, r1, c1, dr, dc}, r0 = Floor[r]; c0 = Floor[c]; If[r0 == nr, dr = 0.; r1 = r0, dr = r - r0; r1 = r0 + 1]; If[c0 == nc, dc = 0.; c1 = c0, dc = c - c0; c1 = c0 + 1]; (1. - dr)*((1. - dc)*arr[[r0,c0]] + dc*arr[[r0,c1]]) + dr*((1. - dc)*arr[[r1,c0]] + dc*arr[[r1,c1]])] ] ; wpoly = Compile[{{pt, _Real, 1}, {k, _Integer}}, Flatten[Outer[Times, Join[{1}, pt[[1]]^Range[k]], Join[{1}, pt[[2]]^Range[k]], 1]]] (* ---------------------- Reflect -------------------------------------- *) Reflect[a_List] := Map[Reverse, a, {0, TensorRank[a]-1}]; Reflect[img:ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === None ] := ImageData[Reflect[img[[1]]], opts]; Reflect[img:ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === True ] := MeshedImageData[Reflect[PlanarImageData[img]]] ; Reflect[img:ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === False ] := ImageData[ToPackedArray[Reflect /@ img[[1]]], opts]; (* -------------------- Resize ----------------------------------------- *) Resize[a_List, ndims:{__Integer}, opt___?OptionQ] := Module[{fun, k, dims}, dims = Dimensions[a]; k = InterpolationOrder /. Flatten[{opt, Options[Resize]}]; fun = ListInterpolation[N[a], Thread[{1., N[dims]}], InterpolationOrder -> k]; ToPackedArray[Apply[fun, Outer[List, Sequence@@Apply[Range, Thread[{1., N[dims], N[(dims-1)/(ndims-1)]}], {1}]], {TensorRank[a]}]] ] /; TensorRank[a] == Length[ndims] Resize[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, dims_, etc___] := ImageData[Resize[img[[1]], dims, etc], opts] ; Resize[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, dims_, etc___] := MeshedImageData[Resize[PlanarImageData[img], dims, etc]] ; Resize[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, dims_, etc___] := ImageData[ToPackedArray[Resize[#, dims, etc]& /@ img[[1]]], opts] ; (* ----------------- Downsample and Upsample --------------------------- *) DownSample[x_List] := Take[x, Sequence@@({1, #1, 2}& /@ Dimensions[x])] DownSample[x_List, k_Integer?Positive] := Take[x, Sequence@@({1, #1, k}& /@ Dimensions[x])] DownSample[x_List, k:{__Integer?Positive}] := Take[x, Sequence @@ MapThread[{1, #1, #2} &, {Dimensions[x], k}]]; DownSample[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, etc___] := ImageData[DownSample[img[[1]], etc], opts] ; DownSample[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, etc___] := MeshedImageData[DownSample[PlanarImageData[img], etc]]; DownSample[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, etc___] := ImageData[ToPackedArray[DownSample[#1, etc]& /@ img[[1]]], opts] ; UpSample[x_List] := iupsample[x, Table[2, {TensorRank[x]}], If[MatchQ[Nest[First, x, TensorRank[x]], _Real | _Complex], 0., 0]] UpSample[x_List, k_Integer?Positive] := iupsample[x, Table[k, {TensorRank[x]}], If[MatchQ[Nest[First, x, TensorRank[x]], _Real | _Complex], 0., 0]] UpSample[x_List, k : {__Integer?Positive}] := iupsample[x, k, If[MatchQ[Nest[First, x, TensorRank[x]], _Real | _Complex], 0., 0]] /; (TensorRank[x] == Length[k]) || Message[UpSample::rank] UpSample[x_List, k : {__Integer?Positive}, v_] := iupsample[x, k, v] /; (TensorRank[x] == Length[k]) || Message[UpSample::rank] UpSample[img : ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, etc___] := ImageData[UpSample[img[[1]], etc], opts] ; UpSample[img : ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, etc___] := MeshedImageData[UpSample[PlanarImageData[img], etc]] ; UpSample[img : ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, etc___] := ImageData[ToPackedArray[UpSample[#, etc]& /@ img[[1]]], opts] ; (* --------- UpSample support function ------------------- *) iupsample[x_, k_, v_] := Module[{xdims, ndims, tmp}, xdims = Dimensions[x]; ndims = k xdims; tmp = Table[v, Evaluate[Sequence @@ (List /@ ndims)]]; tmp[[Sequence @@ MapThread[Range[1, #1, #2] &, {ndims, k}]]] = x; tmp] ; (* ------------ Replicate -------------------------------------------- *) Replicate[x_List] := ireplicate[x, Table[2, {TensorRank[x]}]] Replicate[x_List, k_Integer?Positive ] := ireplicate[x, Table[k, {TensorRank[x]}] ]; Replicate[x_List, k:{__Integer?Positive} ] := ireplicate[x, k] /; (TensorRank[x] == Length[k]) || Message[Replicate::rank] Replicate[img : ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, etc___] := ImageData[Replicate[img[[1]], etc], opts] ; Replicate[img : ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, etc___] := MeshedImageData[Replicate[PlanarImageData[img], etc]] ; Replicate[img : ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, etc___] := ImageData[ToPackedArray[Replicate[#, etc]& /@ img[[1]]], opts] ; (* ---------- Replicate support -----------*) ireplicate[x_, k_] := x[[Sequence @@ MapThread[(Ceiling[Range[#1 ]/#2] &), {k Dimensions[x], k}]]] (* ------------------------ Interpolate ------------------------------- *) Interpolate[x_List] := With[{n = TensorRank[x]}, ListConvolve[Outer[Times, Sequence @@ Table[{0.5, 1., 0.5}, {n}], 1], iupsample[N[x], Table[2, {n}], 0.], Table[2, {n}]]] Interpolate[x_List, k_Integer?Positive] := With[{n = TensorRank[x]}, ListConvolve[ Outer[Times, Sequence @@ Table[1. - Abs[i]/N[k], {n}, {i, -k + 1, k - 1}], 1], iupsample[N[x], Table[k, {n}], 0.], Table[k, {n}]]] Interpolate[x_List, k : {__Integer?Positive}] := With[{n = Length[k]}, ListConvolve[ Outer[Times, Sequence @@ (1. - Abs[Range[-# + 1, # - 1]]/# & /@ k), 1], iupsample[N[x], k, 0.], Table[k, {n}] ]] /; (TensorRank[x] == Length[k]) || Message[Interpolate::rank] Interpolate[x_List, h_?VectorQ, k_Integer?Positive] := With[{n = TensorRank[x]}, ListConvolve[Outer[Times, Sequence @@ Table[h, {n}], 1], iupsample[N[x], Table[k, {n}], 0.], Floor[(Length[h]+1)/2]]] Interpolate[x_List, h : {__?VectorQ}, k : {__Integer?Positive}] := ListConvolve[Outer[Times, Sequence @@ h, 1], iupsample[N[x], k, 0.], Floor[(Length[#] + 1)/2] & /@ h ] /; (TensorRank[x] == Length[k] == Length[h]) || Message[Interpolate::rank] Interpolate[ img : ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === None, etc___ ] := ImageData[Interpolate[img[[1]], etc], opts] ; Interpolate[ img : ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === True, etc___ ] := MeshedImageData[Interpolate[PlanarImageData[img], etc]] ; Interpolate[ img : ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === False, etc___ ] := ImageData[ToPackedArray[Interpolate[#, etc]& /@ img[[1]]], opts] ; Decimate[x_List] := With[{n = TensorRank[x]}, DownSample[ListConvolve[ Outer[Times, Sequence @@ Table[{0.25, 0.5, 0.25}, {n}], 1], x, 2]]]; Decimate[x_List, k_Integer?Positive] := With[{n = TensorRank[x]}, DownSample[ ListConvolve[ Outer[Times, Sequence @@ (Table[1. - Abs[i]/N[k], {n}, {i, -k + 1, k - 1}]/k), 1], x, k], k]]; Decimate[x_List, k : {__Integer?Positive}] := With[{n = Length[k]}, DownSample[ ListConvolve[ Outer[Times, Sequence @@ ((1. - Abs[Range[-# + 1, # - 1]]/#)/# & /@ k), 1], x, Table[k, {n}]], k]] Decimate[x_List, h_?VectorQ, k_Integer?Positive] := With[{n = TensorRank[x]}, DownSample[ ListConvolve[Outer[Times, Sequence @@ Table[h, {n}], 1], x, Floor[(Length[h] + 1)/2]], k]]; Decimate[x_List, h : {__?VectorQ}, k : {__Integer?Positive}] := DownSample[ ListConvolve[Outer[Times, Sequence @@ h, 1], x, Floor[(Length[#] + 1)/2] & /@ h ], k] Decimate[ img : ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === None, etc___ ] := ImageData[Decimate[N[img[[1]]], etc], opts] ; Decimate[ img : ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === True, etc___ ] := MeshedImageData[Decimate[PlanarImageData[img], etc]] ; Decimate[ img : ImageData[_, opts__?OptionQ] /; (PixelInterleave /. {opts}) === False, etc___ ] := ImageData[ToPackedArray[Decimate[#, etc]& /@ N[img[[1]]]], opts] ; (* --------------------- Padding --------------------------------------- *) ZeroPad[arr_List, pad : {_Integer?NonNegative, _Integer?NonNegative} ..] := PadRight[arr, Dimensions[arr] + (Plus@@# & )/@ {pad}, If[MatchQ[Nest[First, arr, TensorRank[arr]], _Real | _Complex], 0., 0], First /@ {pad}] /; Length[{pad}] == TensorRank[arr] || Message[ZeroPad::rank] ZeroPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, pad__List] := ImageData[ZeroPad[img[[1]], pad], opts] ; ZeroPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, pad__List] := MeshedImageData[ZeroPad[PlanarImageData[img], pad]] ; ZeroPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, pad__List] := ImageData[ToPackedArray[ZeroPad[#, pad]& /@ img[[1]]], opts] ; PeriodicPad[arr_List, pad : {_Integer?NonNegative, _Integer?NonNegative} ..] := PadRight[arr, Dimensions[arr] + (Plus@@# & )/@ {pad}, arr, First /@ {pad}] /; Length[{pad}] == TensorRank[arr] || Message[ZeroPad::rank] PeriodicPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, pad__List] := ImageData[PeriodicPad[img[[1]], pad], opts] ; PeriodicPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, pad__List] := MeshedImageData[PeriodicPad[PlanarImageData[img], pad]] ; PeriodicPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, pad__List] := ImageData[ToPackedArray[PeriodicPad[#, pad]& /@ img[[1]]], opts] ; FixedPad[arr_List, pad : {_Integer?NonNegative, _Integer?NonNegative} ..] := With[{tr = TensorRank[arr], vr = RotateRight[Range[TensorRank[arr]]]}, Fold[Transpose[imap[#1, #2, tr], vr] &, arr, Reverse[{pad}]]] /; Length[{pad}] == TensorRank[arr] || Message[FixedPad::rank] FixedPad[arr_List, pad : {_Integer?NonNegative, _Integer?NonNegative} .., v_?NumberQ] := PadRight[arr, Dimensions[arr] + (Plus@@# & )/@ {pad}, If[MatchQ[Nest[First, arr, TensorRank[arr]], _Real | _Complex ], N[v], v], First /@ {pad}] /; Length[{pad}] == TensorRank[arr] || Message[FixedPad::rank] FixedPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, pad__List] := ImageData[FixedPad[img[[1]], pad], opts] ; FixedPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, pad__List] := MeshedImageData[FixedPad[PlanarImageData[img], pad]] ; FixedPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, pad__List] := ImageData[ToPackedArray[FixedPad[#, pad]& /@ img[[1]]], opts] ; FixedPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === None, pad__List, v_?NumberQ ] := ImageData[FixedPad[img[[1]], pad, v], opts] ; FixedPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === True, pad__List, v_?NumberQ ] := MeshedImageData[FixedPad[PlanarImageData[img], pad, v ]] ; FixedPad[img:ImageData[_, opts__?OptionQ ] /; (PixelInterleave /. {opts}) === False, pad__List, v_?NumberQ ] := ImageData[ToPackedArray[FixedPad[#, pad, v]& /@ img[[1]]], opts] ; (* ------- FixedPad support -------------------- *) imap[arr_, {l_, r_}, tr_] := Map[PadRight[PadLeft[#, Length[#] + l, {First[#]}], Length[#] + r + l, {Last[#]}] &, arr, {tr - 1}]; (* ---------- Other matrix operations ---------------------------------- *) MatrixJoin[a_?MatrixQ] := a; MatrixJoin[a__?MatrixQ] := rowJoin[a]; MatrixJoin[a : {__?MatrixQ}] := rowJoin @@ a; MatrixJoin[a : {{_?MatrixQ}..}] := columnJoin @@ (First /@ a); MatrixJoin[a:{{__?MatrixQ}..}] := columnJoin @@ ((rowJoin @@ # &) /@ a); columnJoin[a__?MatrixQ] := Join[a]; rowJoin[a__?MatrixQ] := MapThread[Join,{a}]; ColumnThread[a__?MatrixQ] := Flatten[MapThread[List, {a}, 1], 1]; RowThread[a__?MatrixQ] := Join @@ # & /@ MapThread[List, {a}, 2]; MatrixThread[a_?MatrixQ] := a; MatrixThread[a__?MatrixQ] := RowThread[a]; MatrixThread[a : {__?MatrixQ}] := RowThread @@ a; MatrixThread[a : {{_?MatrixQ}}] := ColumnThread @@( First /@ a); MatrixThread[a : {{__?MatrixQ} ..}] := ColumnThread @@( RowThread @@ # & /@ a); (* ------------ general support functions ----------------------- *) ipNumericQ[x_ /; Head[N[x]] === Real] := True ipNumericQ[x_ /; Head[x] === Real] := True ipNumericQ[x_ /; Head[x] === Integer] := True ipNumericQ[x_ /; Head[x] === Complex] := True ipNumericQ[x_] := False ipMatrixQ[m_?Developer`PackedArrayQ] := MatrixQ[m] ipMatrixQ[m_] := MatrixQ[m, NumberQ] Protect[ Evaluate[protected] ] (********************************************************) End[] (********************************************************) SetAttributes[ {UpSample, DownSample, Decimate, Interpolate, Resize, Reflect, Replicate, ZeroPad, PeriodicPad, FixedPad, MatrixJoin, ColumnThread, RowThread, MatrixThread, ImageWarp, WarpMatrix, ImageRotate}, { Protected, ReadProtected } ] ; (*********************************************************) EndPackage[] (********************************************************)