While both designed to contain files not belonging to the Operating System,
/usr/local are not designed to contain the same set of files.
/usr/local is a place to install files built by the administrator usually by using the make command. The idea is to avoid clashes with files that are part of the operating systems that would either be overwritten or overwrite the local ones otherwise.
/usr/bin/foo is part of the OS while
/usr/local/bin/foo is a local alternative.
All files under
/usr are shareable between OS instances although this is rarely done with Linux. This is a part where the FHS is weak, as
/usr is defined to be read-only but
/usr/local/bin need to be read write for local installation of software to succeed. The SVR4 file system standard which was the main source of inspiration for the FHS is recommending to avoid
/usr/local and use
/opt/local instead to avoid this contradiction.
/usr/local is a legacy from the original BSD. At that time, the source code of
/usr/bin OS commands were in
/usr/src/usr.bin) while the source of commands developed locally were in
/usr/local/src and their binaries in
/usr/local/bin. There was no notion of packaging (outside tarballs).
On the other hand,
/opt is a directory to install unbundled packages each in their own subdirectory. They are already built whole packages provided by an independent third party software distributor. For example
someapp would be installed in
/opt/someapp, one of its command would be in
/opt/someapp/bin/foo, its configuration file would be in
/etc/opt/someapp/foo.conf, and its log files in