#include <bits/stdc++.h>

using namespace std;

#define countof(a) (sizeof(a)/sizeof(*a))

#define vi vector<int>
#define vvi vector<vector<int> >
#define vpi vector<pi >
#define pi pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define all(n) n.begin(), n.end()

#define FROMTO(var, from, to) for (register int var = (from), var##down = ((int)(to)) < ((int)(from));var##down ? (var >= (int)(to)) : (var <= (int)(to));var##down ? var-- : var++)
#define UPTO(var, from, to)   for (register int var = (from); var <= ((int)to); var++)
#define DOWNTO(var, from, to) for (register int var = (from); var >= ((int)to); var--)
#define FOR(var, to)          UPTO(var, 0, (to)-1)
#define DOWN(var, from)       DOWNTO(var, (from)-1, 0) 

#define INIT(var, val) FOR(i,countof(var)) var[i] = val
#define INPUT(var) FOR(i,countof(var)) cin >> var[i]
#define INPUT1(var) FOR(i,countof(var)) cin >> var[i], var[i]--

#define SORT(v) qsort(v,countof(v),sizeof(*v),int_less)
#define SORTT(v) qsort(v,countof(v),sizeof(*v),int_greater)
#define QSORT(v,b) qsort(v,countof(v),sizeof(*v),b)

const int INF = ((1 << 30)-1);
#define MOD 1000000007
#define LINF ((1LL << 62)-1)

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;

struct Comb {
    vector<vector<s64> > data;
    Comb(int n) { // O(n^2)
        data = vector<vector<s64> >(n+1,vector<s64>(n+1,1));
        UPTO(i,1,n) {
            FOR(j,i+1) {
                if (!j || j == i) data[i][j] = 1;
                else data[i][j] = data[i-1][j-1] + data[i-1][j];
            }
        }
    }
    
    s64 ncr(int n, int r) {
        return data[n][r];
    }
};

static inline int ri() {
  int a;
  scanf("%d", &a);
  return a;
}

int int_less(const void *a, const void *b) {
  return (*((const int*)a) - *((const int*)b));
}
int int_greater(const void *a, const void *b) {
  return (*((const int*)b) - *((const int*)a));
}

/* copied from https://gist.github.com/MiSawa/9759784 */
/* edited by QCFium */
struct Dinic {
private:
    typedef s64 Cap;
    static const Cap INF = LINF;
    struct LCNode {
        typedef LCNode* Ptr;
        Ptr ch[2], par, min_node;
        Cap val, min_val, lazy;
        int name;
        LCNode() : par(0), min_node(this), val(INF), min_val(INF), lazy(0) {
            ch[0] = ch[1] = 0;
        }
        inline void push() {
            if (lazy == 0) return;
            val += lazy; min_val += lazy;
            FOR(i, 2) if (ch[i]) ch[i]->lazy += lazy;
            lazy = 0;
        }
        inline void update() {
            push();
            if (ch[0]) {
                min_val = ch[0]->min_val + ch[0]->lazy;
                min_node = ch[0]->min_node;
            }
            if (!ch[0] || min_val > val) {
                min_val = val; min_node = this;
            }
            if (ch[1] && min_val > ch[1]->min_val + ch[1]->lazy) {
                min_val = ch[1]->min_val + ch[1]->lazy;
                min_node = ch[1]->min_node;
            }
        }
        inline void set_value(Cap v) { expose(); val = v; update(); }
        inline Cap get_value() { expose(); return val; }
        inline Ptr get_min_node_on_path() { expose(); return min_node; }
        inline void add_to_path(Cap c) { expose(); lazy += c; push(); }
        inline int state() {
            if(par && par->ch[0] == this) return -1;
            if(par && par->ch[1] == this) return +1;
            return 0;
        }
        inline void rotate() {
            Ptr p = par; p->push(); push();
            bool lr = state()+1;
            if (p->state()) p->par->ch[p->state()>0] = this;
            par = p->par;
            p->ch[lr] = ch[!lr];
            if (ch[!lr]) ch[!lr]->par = p;
            (p->par = this)->ch[!lr] = p;
            p->update(); update();
        }
        inline void splay() {
            while (state()) {
                int s = state() * par->state();
                if (s) (s == 1 ? par : this)->rotate();
                rotate();
            }
            push();
        }
        inline void expose() {
            if (!par) return;
            for (Ptr p = this; p; p = p->par) p->splay();
            for (Ptr p = this; p->par; p = p->par) p->par->ch[1] = p;
            splay();
        }
        inline void cut() {
            expose();
            if (!ch[0]) return;
            ch[0]->par = 0;
            ch[0]->push();
            ch[0] = 0;
            update();
        }
        inline void link_to(Ptr p) {
            expose();
            par = p;
        }
        inline Ptr find_root() {
            expose();
            Ptr p = this;
            while (p->ch[0]) p = p->ch[0];
            p->expose();
            return p;
        }
    };
    struct E{
        int dst;
        Cap cap;
        int rev;
        E(int dst, Cap cap, int rev) : dst(dst), cap(cap), rev(rev) {}
    };
    int n;
    vector<vector<E> > g;
    vector<int> level, active;
    vector<LCNode> lc;
    inline void unuse_edge(E &e) {
        E &ee = g[e.dst][e.rev]; int u = ee.dst;
        Cap use = ee.cap - lc[u].get_value();
        e.cap += use; ee.cap -= use;
        active[u] = false;
        lc[u].cut(); lc[u].set_value(INF);
    }
    inline void init(){
        lc.resize(n);
        active.assign(n, false);
        FOR(u, n) lc[u].name = u;
    }
    Cap dfs(const int &s, const int &t) {
        vector<int> iter(n); FOR(u, n) iter[u] = (int)(g[u].size()) - 1;
        Cap res = 0;

        while(1){
            const int &u = lc[t].find_root()->name;
            if (u == s) {
                Cap f = lc[t].get_min_node_on_path()->get_value();
                res += f;
                lc[t].add_to_path(-f);
                while (1) {
                    int v = lc[t].get_min_node_on_path()->name;
                    Cap f = lc[v].get_value();
                    if (f > 0) break;
                    unuse_edge(g[v][iter[v]]);
                }
            } else {
                for (int &i = iter[u]; i >= 0; --i) {
                    E &e = g[u][i], &ee = g[e.dst][e.rev]; int v = e.dst;
                    if (level[u]-1 != level[v] || ee.cap <= 0) continue;
                    active[u] = true;
                    lc[u].set_value(ee.cap);
                    lc[u].link_to(&lc[v]);
                    break;
                }
                if (active[u]) continue;
                if (u == t) break;
                level[u] = -1;
                for (auto& e : g[u]) if (active[e.dst] && iter[e.dst] == e.rev)
                    unuse_edge(g[e.dst][e.rev]);
            }
        }
        FOR(u, n) if (active[u]) unuse_edge(g[u][iter[u]]);
        return res;
    }

public:
	Dinic(int n) : n(n), g(n) {}
	inline void add_hen(int src, int dst, Cap cap, bool direct) {
		if (src == dst) return;
		g[src].push_back(E(dst,cap,g[dst].size()));
		g[dst].push_back(E(src,direct?0:cap ,g[src].size() - 1));
	}
    Cap run(int s, int t) { // O(NMlogN)
        init();
        vector<int> q(n);
        for (Cap flow = 0; ;) {
            level.assign(n, -1);
            int ql = 0, qr = 0;
            level[q[qr++] = s] = 0;
            while (ql != qr && level[t] == -1) {
                int u = q[ql++];
                for (auto& e : g[u]) if (e.cap > 0 && level[e.dst] == -1)
                    level[ q[qr++] = e.dst ] = level[u] + 1;
            }
            if (level[t] == -1) return flow;
            flow += dfs(s, t);
        }
    }
};


int main() {
    int h = ri();
	int w = ri();
	bool a[h][w];
	pair<int,int> c,d;
	int cnt = 0;
	FOR(i,h) {
		string s; cin >> s;
		FOR(j,w) {
			a[i][j] = s[j] == 'o';
			if (s[j] == 'S') c = {(int)i,(int)j};
			if (s[j] == 'T') d = {(int)i,(int)j};
			cnt += s[j] == 'o';
		}
	} 
	
	Dinic dinic(h+w+2);
	FOR(i,h) FOR(j,w) if (a[i][j]) dinic.add_hen(i+1, 1+h+j, 1, false);
	dinic.add_hen(0, 1+c.fi, INF, true);
	dinic.add_hen(0, 1+h+c.se, INF, true);
	dinic.add_hen(1+d.fi, h+w+1, INF, true);
	dinic.add_hen(1+h+d.se, h+w+1, INF, true);
	
	s64 res = dinic.run(0,h+w+1);
	cout << (res >= INF ? -1 : res) << endl;
    return 0;
}


Measured memory_bytes: 896