/*
    Author:zeke
    
    pass System Test!
    GET AC!!
*/
#include <iostream>
#include <queue>
#include <vector>
#include <iostream>
#include <vector>
#include <string>
#include <cassert>
#include <algorithm>
#include <functional>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <deque>
#include <map>
#include <iomanip>
#include <utility>
#include <stack>
using ll = long long;
using ld = long double;
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define all(x) (x).begin(), (x).end()
#define rep3(var, min, max) for (ll(var) = (min); (var) < (max); ++(var))
#define repi3(var, min, max) for (ll(var) = (max)-1; (var) + 1 > (min); --(var))
#define Mp(a, b) make_pair((a), (b))
#define F first
#define S second
#define Icin(s) \
    ll(s);      \
    cin >> (s);
#define Scin(s) \
    ll(s);      \
    cin >> (s);
template <class T>
bool chmax(T &a, const T &b)
{
    if (a < b)
    {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
bool chmin(T &a, const T &b)
{
    if (b < a)
    {
        a = b;
        return 1;
    }
    return 0;
}
typedef pair<ll, ll> P;
typedef vector<ll> V;
typedef vector<V> VV;
typedef vector<P> VP;
ll MOD = 1e9 + 7;
ll INF = 1e18;

struct BipartiteMatching
{
    vector<vector<int>> graph;
    vector<int> match, alive, used;
    int timestamp;

    BipartiteMatching(int n) : graph(n), alive(n, 1), used(n, 0), match(n, -1), timestamp(0) {}

    void add_edge(int u, int v)
    {
        graph[u].push_back(v);
        graph[v].push_back(u);
    }

    bool dfs(int idx)
    {
        used[idx] = timestamp;
        for (auto &to : graph[idx])
        {
            int to_match = match[to];
            if (alive[to] == 0)
                continue;
            if (to_match == -1 || (used[to_match] != timestamp && dfs(to_match)))
            {
                match[idx] = to;
                match[to] = idx;
                return true;
            }
        }
        return false;
    }

    int bipartite_matching()
    {
        int ret = 0;
        for (int i = 0; i < graph.size(); i++)
        {
            if (alive[i] == 0)
                continue;
            if (match[i] == -1)
            {
                ++timestamp;
                ret += dfs(i);
            }
        }
        return ret;
    }

    void output()
    {
        for (int i = 0; i < graph.size(); i++)
        {
            if (i < match[i])
            {
                cout << i << "-" << match[i] << endl;
            }
        }
    }
};

//BipartiteMatching(n)　頂点n個
//add_edge(s,t)
//bipartite_matching()最大マッチング数
template <typename flow_t>
struct FordFulkerson
{
    struct edge
    {
        int to;
        flow_t cap;
        int rev;
        bool isrev;
        int idx;
    };

    vector<vector<edge>> graph;
    vector<int> used;
    const flow_t INF;
    int timestamp;

    FordFulkerson(int n) : INF(numeric_limits<flow_t>::max()), timestamp(0)
    {
        graph.resize(n);
        used.assign(n, -1);
    }

    void add_edge(int from, int to, flow_t cap, int idx = -1)
    {
        graph[from].emplace_back((edge){to, cap, (int)graph[to].size(), false, idx});
        graph[to].emplace_back((edge){from, 0, (int)graph[from].size() - 1, true, idx});
    }

    flow_t dfs(int idx, const int t, flow_t flow)
    {
        if (idx == t)
            return flow;
        used[idx] = timestamp;
        for (auto &e : graph[idx])
        {
            if (e.cap > 0 && used[e.to] != timestamp)
            {
                flow_t d = dfs(e.to, t, min(flow, e.cap));
                if (d > 0)
                {
                    e.cap -= d;
                    graph[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }

    flow_t max_flow(int s, int t)
    {
        flow_t flow = 0;
        for (flow_t f; (f = dfs(s, t, INF)) > 0; timestamp++)
        {
            flow += f;
        }
        return flow;
    }

    void output()
    {
        for (int i = 0; i < graph.size(); i++)
        {
            for (auto &e : graph[i])
            {
                if (e.isrev)
                    continue;
                auto &rev_e = graph[e.to][e.rev];
                cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
            }
        }
    }
};
/*使い方:
    FordFulkerson(V):= 頂点数 Vで初期化する。
    add_edge(from,to,cap):=頂点fromからtoに容量capの辺を張る。
    max_flow(s,t,f):= 頂点sからtに最大流を流し、その流量を返す。
    int main() {
        int V, E;
        scanf("%d %d", &V, &E);
        FordFulkerson< int > g(V);
        for(int i = 0; i < E; i++) {
            int a, b, c;
            scanf("%d %d %d", &a, &b, &c);
            g.add_edge(a, b, c);
        }
    printf("%d\n", g.max_flow(0, V - 1));
}
*/
int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    ll h,w;
    cin>>h>>w;
  //  ll sreg;
 //   ll greg;
    VV vec(h, V(w));
    FordFulkerson<ll> g(h + w+100);
    ll sx,sy,gx,gy;
    rep(i,h){
        string s;
        cin >> s;
        rep(j,w){
            if(s[j]=='S'){
                g.add_edge(h + w + 20, i, 1e18);
                g.add_edge(h + w + 20, h + j, 1e18);
                sx=i;sy=j;
                vec[i][j] = 1;
            }else if(s[j]=='T'){
                g.add_edge(i, h + w + 21, 1e18);
                g.add_edge(h+j, h + w + 21, 1e18);
                vec[i][j] = 1;
                gx=i;gy=j;
            }else if(s[j]=='o'){
                vec[i][j] = 1;
            }
        }
    }
    if(sx==gx||sy==gy){
        cout<<-1<<endl;
        return 0;
    }
    rep(i,h)rep(j,w){
        if(vec[i][j]==1){
            g.add_edge(i , h + j,1);
            g.add_edge(h+j, i, 1);
        }
    }
    cout << g.max_flow(h+w+20, h+w+21) << endl;
}


Measured memory_bytes: 2048