#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<vector>
#include<array>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cassert>
#include<functional>
#include<random>
#include<complex>
#include<bitset>
#include<chrono>
//#include<boost/multiprecision/cpp_int.hpp>
#define int int64_t
#define uint uint64_t
#define REP(i, a, b) for (int64_t i = (int64_t)(a); i < (int64_t)(b); i++)
#define rep(i, a) REP(i, 0, a)
#define EACH(i, a) for (auto i: a)
#define ITR(x, a) for (auto x = a.begin(); x != a.end(); x++)
#define ALL(a) (a.begin()), (a.end())
#define HAS(a, x) (a.find(x) != a.end())
#define Min(x) *min_element(ALL(x))
#define Max(x) *max_element(ALL(x))
#define Unique(L) (L.erase(unique(ALL(L)), L.end()))
#define veccat(v1, v2) std::copy((v2).begin(),(v2).end(),std::back_inserter(v1)/*v1の後ろにv2を入れる*/)
#define intmax (std::numeric_limits<int64_t>::max() / 4)
using namespace std;
//typedef boost::multiprecision::cpp_int bigint;
const double EPS = 1e-9;
const double PI = acos(-1.0);

template <class Flow>class MaxFlow {
private:

	struct Edge {
		int to;
		Flow cap;
		int rev;
		Edge(int to, Flow cap, int rev) : to(to), cap(cap), rev(rev) {}
	};

	Flow INF;
	Flow EPS;
	int size;
	vector<int>level;
	vector<int>iter;
	vector<int>que;
	vector<vector<Edge>>graph;
public:

	MaxFlow(const int n, Flow eps = 0, Flow inf = 1e9) :
		level(n), iter(n), que(n), size(n), graph(n), EPS(eps), INF(inf) {}

	void add_edge(const int from, const int to, const Flow cap) {
		graph[from].push_back(Edge(to, cap, graph[to].size()));
		graph[to].push_back(Edge(from, 0, graph[from].size() - 1));
	}

	void add_undirected_edge(const int from, const int to, const Flow cap) {
		graph[from].push_back(Edge(to, cap, graph[to].size()));
		graph[to].push_back(Edge(from, cap, graph[from].size() - 1));
	}

	Flow max_flow(const int source, const int sink) {
		Flow flow = 0;

		while (1) {
			bfs(source, sink);

			if (level[sink] == -1) return flow;

			for (int i = 0; i < size; i++) iter[i] = 0;

			flow += dfs(source, sink, INF);
		}
	}

private:

	void bfs(const int from, const int to) {
		int qs = 0, qt = 0;

		for (int i = 0; i < size; i++) level[i] = -1;

		level[from] = 0;
		que[qt++] = from;

		while (qs < qt && level[to] == -1) {
			int now = que[qs++];

			for (int i = 0; i < graph[now].size(); i++) {
				int next = graph[now][i].to;

				if (graph[now][i].cap > EPS && level[next] == -1) {
					level[next] = level[now] + 1;
					que[qt++] = next;
				}
			}
		}
	}

	Flow dfs(const int from, const int to, const Flow cap) {
		Flow flow = 0;

		if (from == to || cap <= EPS) return cap;

		for (int &i = iter[to]; i < graph[to].size(); i++) {
			int next = graph[to][i].to;
			Edge &edge = graph[next][graph[to][i].rev];
			Flow res;

			if (edge.cap <= EPS || level[next] >= level[to]) continue;

			res = dfs(from, next, min(cap - flow, edge.cap));

			if (res <= EPS) continue;

			edge.cap -= res;
			graph[to][i].cap += res;
			flow += res;

			if (abs(flow - cap) <= EPS) break;
		}

		return flow;
	}
};


signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);

	int H, W;
	cin >> H >> W;
	vector<vector<int>>a(H, vector<int>(W, -1));
	int num = 0, sh, sw, gh, gw;
	rep(i, H) {
		string s;
		cin >> s;
		rep(j, W) {
			switch (s[j]) {
			case 'S':
				sh = i;
				sw = j;
				a[i][j] = 0;
				break;
			case 'T':
				gh = i;
				gw = j;
				a[i][j] = 1;
				break;
			case 'o':
				a[i][j] = 2 + num++;
				break;
			}
		}
	}
	num += 2;
	MaxFlow<int>MF(num*2);
	rep(i, H)rep(j, W)if (a[i][j] != -1) {
		rep(ii, H)if (ii != i&&a[ii][j] != -1) {
			MF.add_edge(a[i][j], a[ii][j] + num, 1e8);
		}
		rep(jj, W)if (jj != j&&a[i][jj] != -1) {
			MF.add_edge(a[i][j], a[i][jj] + num, 1e8);
		}
		MF.add_edge(a[i][j] + num, a[i][j], 1);
	}
	int ans = MF.max_flow(0, 1 + num);
	if (H*W<ans)cout << -1 << endl;
	else cout << ans << endl;

	return 0;
}

Measured memory_bytes: 124800