# How to efficiently upsample a greyscale image to generate a representative binary image

I want to create binary images by upsampling a series of greyscale images (192 x 144 resolution) by a factor of 10 with the new pixel values being a pseudorandom distribution of 0's & 1's based on the original grey level value. The new resolution would be 1920 x 1440.

Here is a small example of a greyscale image:

i = Image[{{0.16, 0.22, 0.32}, {0.73, 0.06, 0.13}, {0., 0.86, 0.18}}, ImageSize->100]

The following function gives the desired result for such small images/arrays:

SeedRandom[123]
resize[dat_] :=
Map[SparseArray[
Partition[
RandomSample[
ConstantArray[0, IntegerPart[(1 - #)*100]]~Join~
ConstantArray[1, IntegerPart[100 #]]
], 10]] &, dat, {2}]

s = resize[ImageData@i];
bin = ArrayFlatten[s];
Image[bin, ImageSize -> 100]


However, when I try to uses it for a larger image ArrayFlatten gets upset...

SeedRandom[123]
bigi = Image@RandomReal[1, {50, 50}, WorkingPrecision -> 2]


ArrayFlatten[resize[ImageData@bigi]]


Obviously, I am stepping outside of ArrayFlatten's defined parameters, but I am unable to decipher the meaning of the error message...

Why is this happening?

Is there a simpler way to achieve my desired result for larger greyscale images?

• This is probably a rounding issue. After all, not all matrices in the result of resize have the same dimension. Commented Oct 11, 2020 at 8:10
• Also, I think SparseArray should be avoided here because the resulting arrays are not at all sparse. Commented Oct 11, 2020 at 11:43

This method is short, but slow at higher resolutions:

ImageApply[RandomVariate@*BernoulliDistribution, ImageResize[img, {100, 100}]]


Instead, it makes more sense to pre-generate a random image first which is much faster at high resolutions:

With[{dims = {1920, 1440}},
Binarize[ImageSubtract[ImageResize[img, dims], RandomImage[1, dims]],0]]


• Fascinating! While the original pixel shapes are obliterated, the overall binary distributions appear to be spatially similar. Commented Oct 11, 2020 at 0:08

Maybe using RandomChoice works better (it does so for me).

f[img_, k_] := Image[ArrayFlatten[
Map[
RandomChoice[{1 - #, #} -> {0, 1}, {k, k}] &,
ImageData[img],
{2}
]
]];


Example:

f[ExampleData[{"Texture", "Bark"}], 5]

• This works, although the cell tally's have a probabilistic weight rather than an exact representation of the grey-value. I'm still curious as to why this would be easier for ArrayFlatten to handle for large images than shuffling two ConstantArray's and partitioning. Is it a packed-/unpacked-array issue? Commented Oct 11, 2020 at 0:10