#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdio.h>
#include<cstring>
#include<math.h>
#include<map>
#include<bitset>
#include<iomanip>
#include<queue>
#include<functional>
#include<stack>
#include<tuple>
#include<cassert>
using namespace std;

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
using ll = long long;
using P = pair<int, int>;
using MATRIX = vector< vector<ll> >;
template <class T> inline bool chmin(T &x, const T &y) {if (x > y) {x = y; return 1;} return 0;}
template <class T> inline bool chmax(T &x, const T &y) {if (x < y) {x = y; return 1;} return 0;}

const int INF = 1000000000;

template<class FT>
struct Dinic {
  const FT INF;

  struct edge {
    int to;
    FT cap;
    int rev;
    bool is_rev;
  };

  vector<vector<edge>> graph;
  vector<int> min_cost, iter;
  bool used[100000];

  Dinic(int V) : INF(numeric_limits<FT>::max()), graph(V) {};

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

  bool bfs(int s, int t) {
    min_cost.assign(graph.size(), -1);
    min_cost[s] = 0;
    queue<int> Q;
    Q.push(s);
    while(Q.size() && min_cost[t] == -1) {
      int v = Q.front();
      // cout << "v= " << v << endl;
      Q.pop();
      for(auto &e: graph[v]) {
        if(e.cap > 0 && min_cost[e.to] == -1) {
          min_cost[e.to] = min_cost[v] + 1;
          // cout << e.to << " ";
          Q.push(e.to);
        }
      }
      // cout << endl;
    }
    cout << endl;
    return min_cost[t] != -1;
  }

  FT dfs(const int v, const int t, FT flow) {
    if(v == t) {
      // cout << "flow= " << flow << endl;
      return flow;
    } 
    used[v] = true;
    // cout << "v= " << v << endl;
    for(int i = 0; i < graph[v].size(); i++) {
      edge &e = graph[v][i];
      if(e.cap > 0 && !used[e.to]) {
        // cout << e.to << " ";
        FT d = dfs(e.to, t, min(flow, e.cap));
        if(d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    // cout << endl;
    return 0;
  }

  FT max_flow(int s, int t) {
    FT flow = 0;
    while(1) {
      iter.assign(graph.size(), 0);
      memset(used, 0, sizeof(used));
      FT f = dfs(s, t, INF);
      // cout << "dfsend" << endl;
      if(f == 0) return flow;
      flow += f;
    }
    return flow;
  }

  void print() {
    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;
      }
    }
  }
};

int main() {
  int H, W;
  cin >> H >> W;
  string a[100];
  Dinic<int> g(H + W + 2);
  int S, T;
  rep(i, H) {
    cin >> a[i];
  }
  rep(i, H) {
    rep(j, W) {
      if(a[i][j] == 'S') {
        g.add_edge(H+W, i, INF);
        g.add_edge(H+W, H+j, INF);
        S = W * i + j;
      }
      if(a[i][j] == 'T') {
        g.add_edge(i, H+W+1, INF);
        g.add_edge(H+j, H+W+1, INF);
        T = W * i + j;
      }
      if(a[i][j] == 'o') {
        g.add_edge(i, H+j, 1);
        g.add_edge(H+j, i, 1);
      }
    }
  }

  if(S / W == T / W || S % W == T % W) {
    cout << -1 << endl;
    return 0;
  }

  cout << g.max_flow(H + W, H + W + 1) << endl;

  return 0;
}

Measured memory_bytes: 4540