How fast can I split an image?
One way would be to first extract the ImageData
, Partition
it, ArrayPad
with {1, 1, 1}, convert it to Image
, and finally use ImageAssemble
.
arrPadImage = (ArrayPad[#, {{1}, {1}}, Hold[{1, 1, 1}]] // ReleaseHold // Image) &;
imagePartitionPad[img_, n_] :=
Partition[ImageData[img], Floor@(ImageDimensions[img]/n)] //
ImageAssemble[Outer[arrPadImage, #, 2]] &;
For the given image, this method takes about 0.34 s
compared to yours which takes about 3.63 s
.
imagePartitionPad[imsq, 64]
ImageData[imagePartitionPad[imsq, 64]] == ImageData[showParts[splitImage[imsq, 64]]]
True
This is almost the other answer, just slightly more vectorized and using integers for the data array which seems to be faster:
split[img_, n_] := Image[ArrayFlatten[ArrayPad[Partition[
ImageData[img, "Byte"], Reverse[Floor[ImageDimensions[img]/n]]],
{{0, 0}, {0, 0}, {1, 1}, {1, 1}}, {{{{{255, 255, 255}}}}}]], "Byte"]
split[ImageAssemble[{{img, img}}], 64]
Edit: To extract parts:
Clear[split];
split[im_, n_] := Partition[ImageData[im, "Byte"], Reverse[Floor[ImageDimensions[im]/n]]]
show[parts_] := Image[ArrayFlatten[ArrayPad[parts, {{0, 0}, {0, 0}, {1, 1}, {1, 1}},
{{{{{255, 255, 255}}}}}]], "Byte"]
parts = split[ImageAssemble[{{img, img}}], 64];
subImages = Map[Image[#, "Byte"] &, parts, {2}];
show[parts]
Here's a super naive (but nonetheless very fast) method for generating the padded image, not for splitting (since that problem is almost trivially handled via Partition
) that preserves the ImageColorSpace
and leverages the power of PackedArray
by not padding with 1
but rather with 1.
:
splitty[img_, n_, padColor : {__?NumericQ} | _?NumericQ : 1] :=
Module[
{
data = ImageData@img,
dd,
ins1,
ins2,
paddy
},
dd = Dimensions[data];
paddy =
N@
Switch[padColor,
_?NumericQ,
ConstantArray[padColor, dd[[3]]],
_,
PadRight[padColor, dd[[3]], 1][[;; dd[[3]]]]
];
ins1 =
Insert[data,
paddy,
Flatten[
Table[
{i, j},
{i, 1, dd[[1]]},
{j, 1, dd[[2]], Floor[dd[[1]]/n]}
],
1
]
];
ins2 =
Insert[
ins1,
ConstantArray[paddy, Length@ins1[[1]]],
List /@ Range[1, Length@ins1, Floor[dd[[2]]/n]]
];
Image[ins2,
ColorSpace -> ImageColorSpace@img
]
];
Note that it performs surprisingly well:
splitty[img, 64] // RepeatedTiming // First
0.014
splitty[img, 64]
And you can insert an arbitrary color:
splitty[img, 100, .5]
splitty[img, 100, {.6, .6, 0}]