The faked mosaic is simple. Well I tried a simple multiplication and looks like ti works.
create a photo texture pattern covering the size of input image
modulate the grayscale photo pattern and original image
simple multiplication will do.
Both steps can be combined into single one... here simple C++ code for this:
// globals
const int txrs=41; // number of textures for mosaic
picture txr[txrs]; // mosaic textures
picture pic0,pic1; // input and output images
// init
pic0.load("MonaLisa.jpg");
int sz=32; // mosaic grid size
for (int i=0;i<txrs;i++) // load/resize/grayscale textures
{
txr[i].load(AnsiString().sprintf("textures\\%03i.jpg",i)); // load image
txr[i].resize_fit(sz,sz,0x00000000); // resize to tile size
txr[i].enhance_range();
txr[i].pixel_format(_pf_u); // convert to grayscale <0,765>
txr[i].pixel_format(_pf_rgba); // convert to grayscale RGBA
}
pic0.resize_fit((pic0.xs/sz)*sz,(pic0.ys/sz)*sz,0x00000000); // cut not full tile size part of pic1
// mosaic
int xx,yy,x,y,i,j,sz=txr[0].xs,a,b;
color c0,c1;
pic1=pic0; // copy source image to destination
// process all regions
for (y=0;y<pic1.ys;y+=sz)
for (x=0;x<pic1.xs;x+=sz)
{
// select random texture
i=Random(txrs);
// proces region
for (yy=0;yy<sz;yy++)
for (xx=0;xx<sz;xx++)
{
// grayscale texture and original color image pixels
c0=txr[i].p[yy][xx];
c1=pic1.p[y+yy][x+xx];
// mutiply them
for (j=0;j<3;j++)
{
a=BYTE(c0.db[j]);
b=BYTE(c1.db[j]);
a=(a*b)>>8;
c0.db[j]=a;
}
// store to destinatio image
pic1.p[y+yy][x+xx]=c0;
}
}
pic1.save("out.png");
I use my own picture class for images so some members are:
xs,ys
is size of image in pixels
p[y][x].dd
is pixel at (x,y)
position as 32 bit integer type
clear(color)
clears entire image with color
resize(xs,ys)
resizes image to new resolution
bmp
is VCL encapsulated GDI Bitmap with Canvas
access
pf
holds actual pixel format of the image:
enum _pixel_format_enum
{
_pf_none=0, // undefined
_pf_rgba, // 32 bit RGBA
_pf_s, // 32 bit signed int
_pf_u, // 32 bit unsigned int
_pf_ss, // 2x16 bit signed int
_pf_uu, // 2x16 bit unsigned int
_pixel_format_enum_end
};
color
and pixels are encoded like this:
union color
{
DWORD dd; WORD dw[2]; byte db[4];
int i; short int ii[2];
color(){}; color(color& a){ *this=a; }; ~color(){}; color* operator = (const color *a) { dd=a->dd; return this; }; /*color* operator = (const color &a) { ...copy... return this; };*/
};
The bands are:
enum{
_x=0, // dw
_y=1,
_b=0, // db
_g=1,
_r=2,
_a=3,
_v=0, // db
_s=1,
_h=2,
};
The input image I used was this:

And here the result:

It might need some brightness tweaking to match original input image properties.