Photo Mosaic with G'Mic

Well, almost done.

v=5
te={w<h?$v/w:$v/h}

to_a at[0] "get ia,0,0",{$te*w},{$te*h} r[^0] {$te*w},{$te*h},1,4,5 r[^0] {w#0},{h#0},1,4,0,2 split_opacity l[^0-1] repeat {$!/2} +get[{$>*2}] ia done +a[^0-{$!-1-$!/3}] x endl index[0] .,0,1 rm. r[^0-{$!-(($!+1)/3)}] {w#0},{h#0},1,{s},1

It looks like I rarely use lines these day. The next step is to erase mismatch between indexed image, and convert that to transparency mask which be applied to the smaller images. The opacity layers will be multiplied, and applied per tile images.

Also, saving this here for easier access to coding in the morning. Also, I’m using this equation to help me out.

y=2x+(x-1)

‘get’ is my latest cli command, and this makes the work a lot easier.

On the right, those colors are going where the photo tiles are going to be.

1 Like

And using patchmatch can not look for morphological resemblance (?)

I tried that, didn’t understand how it works, so I’ll just continue with this approach.

I only use this, but short pieces of the image:

gmic sample cat sample apples +patchmatch[0] [1],64,64,1,1,1 fx_posterize[2] 800,0,0,4,64,0,0,0,50,50 +warp[-2] [-1]

EDIT : Never mind, it didn’t work at all. :frowning:

I’ll try to find out another way, but this is definitely difficult to code.

I do not know if it’s useful, here’s an example of positioning and blending.

# example blending

# Gmicky 2w*1h
rm[0]
fx_gmicky 2
resize[-1] 200%

# variables
Color_Tolerance=10
Maximum_Number_of_Output_Layers=2
Minimal_Area_PourCent=8
Autocrop_Output_Layers=0
W_Origine={w}
H_Origine={h}
# 2 layers
quantize[-1] $Maximum_Number_of_Output_Layers
fx_split_colors[-1] $Color_Tolerance,$Maximum_Number_of_Output_Layers,$Minimal_Area_PourCent,$Autocrop_Output_Layers
to_rgba[-1,-2]
# Gmicky rgb
+fx_gmicky 0
to_rgb[-1]
# where you want to see Gmicky
expand_x[-1] {abs({$W_Origine-{w}})/2},0 
expand_y[-1] {abs({$H_Origine-{h}})/2},0
# blend alpha
blend[-1,-2] alpha

rv[-1,-2]

I did just found the solution, to creating photo-mosaic, but the result are atrocious, but it works nevertheless.

#@cli rep_lbchstatfunc_to_pal: (eq. to rep_layers_by_channel_statistical_function_to_palette)
rep_lbchstatfunc_to_pal: rep_layers_by_channel_statistical_function_to_palette $*
#@cli rep_layers_by_channel_statistical_function_to_palette: variable
#@cli: Converts layers to palette using statistical function by channels per layers into 1x1 tile, then append them.
rep_layers_by_channel_statistical_function_to_palette: to_rgb rep_bchstatfunc $1 a x

#copy and paste below into code filter in g'mic, and copy and paste above to somewhere where you can remove it when not needed#
v=5
te={w<h?$v/w:$v/h}
to_a
at[0] "rep_bchstatfunc ia,0",{$te*w},{$te*h} r[^0] {$te*w},{$te*h},1,4,5 r[^0] {w#0},{h#0},1,4,0,2 +rep_lbchstatfunc_to_pal[^0] ia split_opacity[^{$!-1}] index[0] .,0,1 rm. l[^0-1] repeat {$!/2} +rep_bchstatfunc[{$>*2}] ia,0 done endl l[^1-{($!-1)-($!-2)/3}] repeat {$!-1} l[0,{$>+1}] f. "i#0==i#1?255:0" to_gray. endl done endl repeat {($!-2)/3+1} l[{1+($>*2)},{($!-1)-($!-2)/3+$>}] / 255 f.. "i#0*i#1" * 255 endl done rm[^0-{($!-1)-($!-2)/3}] repeat {($!-2)/2} a[{$>+2},{$>+3}] c done blend[^0-1] alpha rv[0,2] rm. split_opacity[0] blend[^0] multiply a c

Using code, you can change the value of v. Works with any layer greater than 3 as 2 are at least needed minimum for the mosaic.

Here’s the atrocious result -

That’s due to the indexing technique. I may need to find out just how to get a better indexing for the purpose of generating the mosaic. Either that or I may have to add blending using the original [0] image. Or both.

EDIT: One more example, but this time, more passable. Had to add more images for the mosaic result.

EDIT: I may have to keep in mind about expand_x, and expand_y for future filters.

1 Like

Not quite what the OP was looking for, but nevertheless interesting. Reminds me of those Lego grid bases. Or a map of grid based video games.

Exactly, however, I"ll admit that this is a start to a new filter unless someone makes a better version than my own. Also, I’ll share this result too -

1 Like

Now add an option, that every photo can only used 1 or n times.

That’s going to be hard given that it’s a bit hard to maintain the code.

I made a better algorithm to make the end image better. There’s two problem - A incredible annoying bug, and having to figure out shift due to nearest neighbor scaling issue. This approach uses indexing instead.

#@cli rep_lbchstatfunc_to_pal: (eq. to rep_layers_by_channel_statistical_function_to_palette)
rep_lbchstatfunc_to_pal: rep_layers_by_channel_statistical_function_to_palette $*
#@cli rep_layers_by_channel_statistical_function_to_palette: variable
#@cli: Converts layers to palette using statistical function by channels per layers into 1x1 tile, then append them.
rep_layers_by_channel_statistical_function_to_palette: to_rgb rep_bchstatfunc $1 a x

#copy and paste below into code filter in g'mic, and copy and paste above to somewhere where you can remove it when not needed#
v=25
isw={w>h?1:w/h}
ish={h>w?1:h/w}
vw={floor($v*$isw)}
vh={floor($v*$ish)}
nsw={ceil(w/$vw)}
nsh={ceil(h/$vh)}
to_a

l[0] +r[0] {$nsw},{$nsh},1,{s},5 endl
+rep_lbchstatfunc_to_pal[^0-1] ia
split_opacity[1]
index[1] .,.85,1
a[1,2] c
r[1] {w#0+($v-(w#0%$v))},{h#0+($v-(h#0%$v))},1,{s#1},1
shift[1] {w>h?0:0},{h>w?0:0}
f[0] "i#1"
rm[1]
r[^0,{$!-1}] {ceil($vw)},{ceil($vh)},1,4,5
r[^0,{$!-1}]  {w#0},{h#0},1,4,0,2
split_opacity[^{$!-1}]
l[0,{$!-1}] pal_l. r[^0] {w#0},{h#0},1,3,1 endl

ti={($!+1)/3}
repeat {($ti-1)} l[0,{$!-$ti+$>+1}] f. "i#0==i#1?255:0" to_gray. endl done
repeat {($ti-1)} l[{($>*2)+3},{$!-$ti+$>+1}] f.. "i#0==i#1?255:0" endl done
rm[^0-{$!-$ti}]
repeat {($!/2)-1} a[{$>+2},{$>+3}] c done
blend[^0-1] alpha rv[0,2] rm. split_opacity.. blend[^0] multiply a c

Some part of the image are shifted for some reason, and I don’t know how exactly do I fix that bug. There’s also the need to add shift because some areas have bigger side than the other areas. See what I mean by deleting everything after shift and checking for yourself.

That would also depend on how many input files you have for the mosaic.

EDIT: Finally, I figured out what’s wrong with the colors. So, irrelevant part of post is gone.

EDIT: It is uploaded to g’mic community. And here’s a sample image. It uses indexing, and no apply_tiles.

^Also works with transparency too.

1 Like

Ok, now I got a issue here. When developing the gui filter - I am not exactly sure how do I get the number of layer inputs to affect the dynamic options. It seems to treat $! as one every time.

u "{$1}_"{$!>=1?2:0}\
"{$2}_"{$!>=1?2:0}\
"{$3}"\
"{$4}"\
"{$5}"\
"{$6}"\
"{$7}"\
"{$8}"
text_outline {$!},2,22,23,2,1,255 # nb layers
text_outline {{$!}-1},2,42,23,2,1,255 # nb layers - 1

This is the first test that does not block my PC with your ‘Mosaic’ filter.
The result is funny on the picture of ‘Gmicky’
Under G’MIC-GIMP-QT the command line used is ’ rep_mosaic_gen 20,{{$!}-1} '.
Thumbnails are from www.uihere.com

rep_mosaic_test_01

1 Like

Photo-mosaic has been updated. I think I should add the option to have the end result resized to nearest divisible numbers by tile_width, and tile_height? Is there anything else other than that I should add (I can’t do automatic rotation to make the end result even better as a option)? Should I add the option to have users to use original picture color as a blending mode?

For your reference,

#@cli rep_mosaic_gen: 0>=tile_width,0>=tile_height,0>=dithering<=1,1>=interpolation<=6,autocrop-by-median_bool[0=Do not autocrop by median|1=Autocrop by median]
1 Like

Your parameter conditions and formatting need revision. See example:

With the bug on my aspect ratio, I gotta say that I give up on the mosaic project. I couldn’t find a fix despite it works mostly.

Now that the aspect crop bug is fixed. I’m on my way to fixing my cli formatting. All of them. A few info might go amiss though considering the large info I added.