G'MIC Challenge: Create image from photographs with a single line

@Reptorian

That’s right. I simply use the beginning of another project to activate the ‘tsp’ script :o)

That’s cool, Gary. Just sharing some insights I discovered with voronoi stippler over the years. Another one is to invert the target, then after running, invert that result to get white on black (similar results to what you got with yours). :slight_smile:

@lylejk
Thank you : The Traveling Salesman problem. • GIMP Chat

I always have fun with the scripts of @David_Tschumperle and @grosgood

A black line on a white background :

if {w}>{h}
resize 1000,{{h}/{w}*1000}
else
resize {{w}/{h}*1000},1000
fi
samj_Masques_Noir_Et_Blanc_Preview 3,50
to_gray
negate
dilate 10
pointcloud. 3
channels. 0,1
resize. 2%,1
add. 12
tsp. 200
1024,1024,1,1
repeat {0,w}
 line. {0,boundary=2;[I[$>],I[$>+1]]},1,255
done
rm[-2]
dilate 2
negate
1 Like

I like this last one. Black line on white canvas. It still has a laser beam coming out of the eye of the tiger. :rotating_light: :joy_cat:

Going back to Rep’s original, I sort of like the meandering single line (i.e, no picking up the pin) result. Again, I would want this ability in the plugin, since, well, I’m a GIMPer. Not opposed to CLI or scripts (hence TSP), but like to be able to keep withing an editing environment. Maybe David or someone can figure out how to do this within the G’MIC plugin. While I’m asking, would like the Hilbert (and other type) of variable density single line fill render abilities as well (doesn’t hurt to ask). lol

:slight_smile:

Well, the main difference of @Reptorian’s sample and the rest of yours is that the line can cross itself! Although it is different, I recall this:

Somehow, instead of having the edges of the image or shape as direction change points, we could have the edges and textures of the image… and instead of straight lines, we have splines, etc.

Some remarks follows to my tests :

I did some testing with splines but it’s very, very slow.

@lylejk
Make a GMIC-Gimp plug-in is difficult because the rendering is very, very slow.
It could be sequential, for example :

  • At first visualize the completed areas.
  • Then validate the final overview.

The stability of the plug-in during the time of treatment must be taken into consideration.

Just brainstorming. We don’t have to implement all the ideas. I think it would still work with straight lines, we just have to decide when to change directions and how many times.

The thing is G’MIC is probably the wrong program to do this because of the slowness but who knows: you are all geniuses. :nerd_face:

Appreciate the followup, samj. I guess I’m still wanting G’MIC to be the do all of do alls. lololololool

Still, my Dad always told me there’s always more than one way to skin a cat. lol

:slight_smile:

That’s why I attempted to recreate/convert many Paint.NET plugin to G’MIC.

Appreciate your efforts, Rep since coder I’m not. So many great coders that have made me happy over the years, you included, Rep. :slight_smile:

1 Like

I had fun exporting to SVG in the directory where is ‘update310.gmic’
I join the code I activate in GIMP and the file ‘list_points_tsp.svg’ created by the script.
I will realize a plug-in by separating the rendering and the SVG backup.


CRLF="\\r\\n"
Liste="<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>"$CRLF
Liste=$Liste"<svg xmlns=\\"http://www.w3.org/2000/svg\\" version=\\"1.1\\" width=\\"1024\\" height=\\"1024\\">"$CRLF
Liste=$Liste"<title>Test GMIC SVG</title>"$CRLF
Liste=$Liste"<desc>Points et Segments</desc>"$CRLF
if {w}>{h}
resize 1000,{{h}/{w}*1000}
else
resize {{w}/{h}*1000},1000
fi
samj_Masques_Noir_Et_Blanc_Preview 3,50
to_gray
negate
dilate 10
pointcloud. 3
channels. 0,1
resize. 2%,1
add. 12
tsp. 200
+crop 0,0,1,0
Xend={i0}
Yend={i1}
rm[-1]
repeat {{w}-1}
Index=$>
 +crop $Index,0,{$Index+1},0
 Xa={i0}
 Ya={i1}
 rm[-1]
 +crop {$Index+1},0,{$Index+2},0
 Xb={i0}
 Yb={i1}
 rm[-1]
 Liste=$Liste"<line x1=\\""$Xa
 Liste=$Liste"\\" y1=\\""$Ya
 Liste=$Liste"\\" x2=\\""$Xb
 Liste=$Liste"\\" y2=\\""$Yb
 Liste=$Liste"\\" stroke=\\"black\\" />"$CRLF
done
Liste=$Liste"<line x1=\\""$Xb
Liste=$Liste"\\" y1=\\""$Yb
Liste=$Liste"\\" x2=\\""$Xend
Liste=$Liste"\\" y2=\\""$Yend
Liste=$Liste"\\" stroke=\\"black\\" />"$CRLF
Liste=$Liste"</svg>"$CRLF
('$Liste')
output_text.  $_path_rc/Liste_Points_TSP.svg
# SVG validé sur https://validator.w3.org/
rm.
1024,1024,1,1
repeat {0,w}
 line. {0,boundary=2;[I[$>],I[$>+1]]},1,255
done
rm[-2]

Liste_Points_TSP

1 Like

@samj: For Liste, you could do:

str=initial_string
str.=" appended string"

echo $str

You can do ..= which appends the other way.

Having fun with Gmicky in GIMP/GMIC 3.1.0_pre for getting an SVG image (1 line) :

Liste_Points_TSP


## Supprimer les 2 lignes pour obtenir un SVG sur une autre image ##
rm
fx_gmicky 0
####################################################################
Param1Masque1=1.25
Param2Masque1=42
Param1Masque2=0
Param2Masque2=32.5
CRLF="\\r\\n"
Liste="<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>"$CRLF
Liste.="<svg xmlns=\\"http://www.w3.org/2000/svg\\" version=\\"1.1\\" width=\\"1024\\" height=\\"1024\\">"$CRLF
Liste.="<title>Test GMIC SVG</title>"$CRLF
Liste.="<desc>Points et Segments</desc>"$CRLF
Liste.="<polyline points=\\""
if w>h
resize 1000,{h/w*1000}
else
resize {w/h*1000},1000
fi
+samj_Masques_Noir_Et_Blanc_Preview $Param1Masque1,$Param2Masque1
to_gray.
negate.
dilate. 10
pointcloud. 3
channels. 0,1
resize. 1%,1
add. 12
tsp. 200
+crop. 0,0,1,0
Xend={i0}
Yend={i1}
rm.
repeat w
 Index=$>
 +crop. $Index,0,{$Index+1},0
 Xa={i0}
 Ya={i1}
 rm.
 Liste.=$Xa" "
 Liste.=$Ya" "
done
rm.
# ligne 2
samj_Masques_Noir_Et_Blanc_Preview $Param1Masque2,$Param2Masque2
to_gray.
negate.
dilate. 10
pointcloud. 3
channels. 0,1
resize. 1%,1
add. 12
tsp. 200
repeat w
 Index=$>
 +crop. $Index,0,{$Index+1},0
 Xa={i0}
 Ya={i1}
 rm.
 Liste.=$Xa" "
 Liste.=$Ya" "
done
Liste.=$Xend" "
Liste.=$Yend" "
# Liste.="\\" stroke=\\"blue\\" fill=\\"transparent\\" stroke-width=\\"2\\"/>"$CRLF
Liste.="\\" stroke=\\"blue\\" fill=\\"transparent\\" stroke-width=\\"2\\" mask=\\"none\\" style=\\"fill:#000000;fill-opacity:0\\"/>"$CRLF
Liste.="</svg>"$CRLF
('$Liste')
output_text.  $_path_rc/Liste_Points_TSP.svg
# SVG validé sur https://validator.w3.org/
rm
1500,100,1,3
fill_color. 255,255,255
text. "SVG disponible sur :",20,20,20,1,255,0,0
if '$_os'=='windows'
 text. $_path_rc"\\Liste_Points_TSP.svg",20,50,20,1,255,0,0
else
 text. $_path_rc"/Liste_Points_TSP.svg",20,50,20,1,255,0,0
fi
autocrop
3 Likes

@samj This is wonderful. Much closer to @Reptorian’s and @lylejk’s examples. SVG too.

@afre

Thank you :o)
The next step will replace the right segments with curves.
I have to find a formula to create a smoothed and beautiful rendering (not easy to do for me).

I use smooth path’s plugin in GIMP (not sure when/where I got this plugin). Also can simplify in Inkscape since it’s a vector, but Inkscape tends to smooth too much. :slight_smile:

(Edit) Here is a version with which uses SVG Bézier curves to get curved lines.

I join the code for GIMP GMIC 3.1.0_pre (this code is not optimized).

I will wait for the GMIC ‘exec’ command to work properly to continue.

Liste_Points_TSP


## Supprimer les 2 lignes pour obtenir un SVG sur une autre image ##
rm
fx_gmicky 0
####################################################################
Param1Masque1=1.25
Param2Masque1=42
Param1Masque2=0
Param2Masque2=32.5
Echelle=1
CRLF="\\r\\n"
Liste="<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>"$CRLF
Liste.="<svg xmlns=\\"http://www.w3.org/2000/svg\\" version=\\"1.1\\" width=\\"1024\\" height=\\"1024\\">"$CRLF
Liste.="<title>Test GMIC SVG</title>"$CRLF
Liste.="<desc>Points et Splines</desc>"$CRLF
if w>h
resize 1000,{h/w*1000}
else
resize {w/h*1000},1000
fi
+samj_Masques_Noir_Et_Blanc_Preview $Param1Masque1,$Param2Masque1
to_gray.
negate.
dilate. 10
pointcloud. 3
channels. 0,1
WWe={round(w/100*$Echelle)}
if {$WWe%2}==0 resize. $WWe,1 else resize. {$WWe-1},1 fi
add. 12
tsp. 200
+crop. 0,0,1,0
Xo={i0}
Yo={i1}
rm[-1]
+crop. 1,0,2,0
Xs={i0}
Ys={i1}
rm[-1]
+crop. 2,0,3,0
Xt={i0}
Yt={i1}
rm[-1]
+crop. 3,0,4,0
Xq={i0}
Yq={i1}
rm[-1]
Liste.="<path d=\\"M"
Liste.=$Xo" "
Liste.=$Yo" C"
Liste.=$Xs" "
Liste.=$Ys" "
Liste.=$Xt" "
Liste.=$Yt" "
Liste.=$Xq" "
Liste.=$Yq" "
Liste.="\\" stroke=\\"blue\\" fill=\\"transparent\\" stroke-width=\\"2\\" mask=\\"none\\"  style=\\"fill:#000000;fill-opacity:0\\"/>"$CRLF
Index=2
repeat {{w/2}-1}
 Xu=$Xq
 Yu=$Yq
 Xd=$Xt
 Yd=$Yt
 +crop {$Index},0,{$Index+1},0
 Xt={i0}
 Yt={i1}
 rm[-1]
 rm[-1]
 +crop {$Index+1},0,{$Index+2},0
 Xq={i0}
 Yq={i1}
 rm[-1]
 rm[-1]
 Xs={$Xu+$Xu-$Xd}
 if $Xs<0 Xs=0 fi
 if $Xs>1023 Xs=1023 fi
 Ys={$Yu+$Yu-$Yd}
 if $Ys<0 Ys=0 fi
 if $Ys>1023 Ys=1023 fi
 Liste.="<path d=\\"M"
 Liste.=$Xu" "
 Liste.=$Yu" C"
 Liste.=$Xs" "
 Liste.=$Ys" "
 Liste.=$Xt" "
 Liste.=$Yt" "
 Liste.=$Xq" "
 Liste.=$Yq" "
 Liste.="\\" stroke=\\"blue\\" fill=\\"transparent\\" stroke-width=\\"2\\" mask=\\"none\\"  style=\\"fill:#000000;fill-opacity:0\\"/>"$CRLF
 Index={$Index+2}
done
rm.
########## ligne 2
samj_Masques_Noir_Et_Blanc_Preview $Param1Masque2,$Param2Masque2
to_gray.
negate.
dilate. 10
pointcloud. 3
channels. 0,1
WWe={round(w/100*$Echelle)}
if {$WWe%2}==0 resize. $WWe,1 else resize. {$WWe-1},1 fi
add. 12
tsp. 200
+crop. 1,0,2,0
Xs={i0}
Ys={i1}
rm[-1]
+crop. 2,0,3,0
Xt={i0}
Yt={i1}
rm[-1]
+crop. 3,0,4,0
Xq={i0}
Yq={i1}
rm[-1]
Liste.="<path d=\\"M"
Liste.=$Xo" "
Liste.=$Yo" C"
Liste.=$Xs" "
Liste.=$Ys" "
Liste.=$Xt" "
Liste.=$Yt" "
Liste.=$Xq" "
Liste.=$Yq" "
Liste.="\\" stroke=\\"blue\\" fill=\\"transparent\\" stroke-width=\\"2\\" mask=\\"none\\"  style=\\"fill:#000000;fill-opacity:0\\"/>"$CRLF
Index=2
repeat {{w/2}-1}
 Xu=$Xq
 Yu=$Yq
 Xd=$Xt
 Yd=$Yt
 +crop {$Index},0,{$Index+1},0
 Xt={i0}
 Yt={i1}
 rm[-1]
 +crop {$Index+1},0,{$Index+2},0
 Xq={i0}
 Yq={i1}
 rm[-1]
 Xs={$Xu+$Xu-$Xd}
 if $Xs<0 Xs=0 fi
 if $Xs>1023 Xs=1023 fi
 Ys={$Yu+$Yu-$Yd}
 if $Ys<0 Ys=0 fi
 if $Ys>1023 Ys=1023 fi
 Liste.="<path d=\\"M"
 Liste.=$Xu" "
 Liste.=$Yu" C"
 Liste.=$Xs" "
 Liste.=$Ys" "
 Liste.=$Xt" "
 Liste.=$Yt" "
 Liste.=$Xq" "
 Liste.=$Yq" "
 Liste.="\\" stroke=\\"blue\\" fill=\\"transparent\\" stroke-width=\\"2\\" mask=\\"none\\"  style=\\"fill:#000000;fill-opacity:0\\"/>"$CRLF
 Index={$Index+2}
done
Liste.="</svg>"$CRLF
('$Liste')
output_text.  $_path_rc/Liste_Points_TSP.svg
# SVG validé sur https://validator.w3.org/
rm
1500,100,1,3
fill_color. 255,255,255
text. "SVG disponible sur :",20,20,20,1,255,0,0
if '$_os'=='windows'
 text. $_path_rc"\\Liste_Points_TSP.svg",20,50,20,1,255,0,0
else
 text. $_path_rc"/Liste_Points_TSP.svg",20,50,20,1,255,0,0
fi
autocrop
3 Likes

Très bien !

@afre
Merci !