In the shell:
for f in ./IMG_*.jpg ; do
t=${f##*/}
touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done
Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.
Doing it with find needs the shell, too:
$ find -name "IMG_*.jpg" -exec bash -c '
for f; do t=${f##*/}; touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}" ; done
' sh {} \+
The first argument to Bash after the script goes to the $0 variable, which usually contains the shell name. The rest go to the positional parameters $1, $2, etc. and for f or for f in "$@" loops over them.
The construct is here is rather common (theat least in unix.SE answers).
The main part of the loop here is the same as abovein the first example.
The find command in your question find .. -exec touch -t"$(...)" {} \; doesn't work since the command substitution is in double quotes, so it gets expanded before find runs. The {} is piped literally to awk, and it just so happens that the awk script only prints a dot.
If you did put the command substitution in single quotes, it would be passed to touch as-is (find would only substitute {}). touch would get the argument -t$(echo ...), dollar signs, parenthesis and all. find doesn't run the command through the shell by itself, we need to explicitly do it, as above.
In single quotes example:
$ find -name x -exec echo 'hello $(foo {})' \;
hello $(foo ./x)