#include <bits/stdc++.h>
using namespace std;

//#include <boost/algorithm/string/join.hpp>
//#include <boost/range/irange.hpp>
//#include <boost/multiprecision/cpp_int.hpp>
//#include "boost/multi_array.hpp"
//
//using boost::irange;
//using boost::algorithm::join;
//
// boost::multi_array<int, 3> table;
// table.resize(boost::extents[10][9][8]);

typedef long long ll;
typedef unsigned long long ull;
//typedef long double ld;

typedef map<int, int> mii;
typedef pair<int, int> pii;
typedef pair<double,double> pdd;
typedef set<int> si;
typedef set<ll> sll;
typedef vector<int> vi;
typedef vector<pair<int, int > > vii;
typedef vector<ll> vll;
typedef vector<double> vd;
typedef vector<vi> vvi;
typedef vector<vii> vvii;
typedef vector<vll> vvll;

//constexpr ll MOD = 1e9+7;
template<typename T>constexpr auto inf=numeric_limits<T>::max()/4;
constexpr int INF=inf<int>;
constexpr ll LINF=inf<ll>;

#define Sort(x) sort(begin(x),end(x))
#define Reverse(x) reverse(begin(x),end(x))
#define ABS(a,b) ((a)<(b)?(b)-(a):(a)-(b))
#define nbit(n) (1ull<<(n))
#define _ol3(_1,_2,_3,name,...)name
#define _rep(i,n)_repi(i,0,n)
#define _repi(i,a,b)for(int i=a,i##_l=(b);i<i##_l;++i)
#define REP(...) _ol3(__VA_ARGS__,_repi,_rep,)(__VA_ARGS__)
#define REPR(i,n) for(int i=n-1;i>=0;--i)
#define REPA(i,v) REP(i,(v).size())

// sort(begin(x), end(x), greater<ll>());
// lower_bound(a.begin(), a.end(), val): a[i] ≥ valである最左の位置
// upper_bound(a.begin(), a.end(), val): a[i] > valである最左の位置

// Returns minimum of a and b.
// If a is less b, a is set to b.
template<typename T>
T chmin(T& a, T b) {
  if (a > b) {
    a = b;
  }
  return a;
}

// Returns maximum of a and b.
// If a is less b, a is set to b.
template<typename T>
T chmax(T& a, T b) {
  if (a < b) {
    a = b;
  }
  return a;
}

template <typename T>
void dumpContents(const T& v, const string& msg)
{
  cerr << "### " << msg << " ###\n";
  for (const auto& x : v) {
    cerr << x << " ";
  }
  cerr << endl;
}

struct before_main_function {
  before_main_function() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout<<setprecision(20)<<fixed;
#define endl "\n"
  }
} before_main_function;

template <int MAX_V>  // Max |V|, including s and t
class FordFulkerson {

  struct edge {
      int to;  // destination node
      ll cap;  // capacity
      int rev; // reverse edge
  };

  vector<edge> G[MAX_V]; // adjacency list
  bool used[MAX_V];

public:

  // Add an edge to the graph G.
  //
  // @param from a node
  // @param to a node
  // @param capacity
  void addEdge(const int from, const int to, const ll cap) {
      G[from].push_back(edge{to, cap, (int)G[to].size()});
      // Add a reverse eddge
      G[to].push_back(edge{from, 0, (int)G[from].size() -1});
  }

  // Search for an augument path from v with flow f.
  //    - t is the sink node
  int dfs(const int v, const int t, const ll f) {
      if (v==t) return f;
      used[v] = true;
      for (auto& e : G[v]) {
  	if (used[e.to] || e.cap == 0) continue;

  	const ll d = dfs(e.to, t, min({f, e.cap}));
  	if (d<=0) continue;

  	e.cap -= d;
  	G[e.to][e.rev].cap += d;
  	return d;
      }
      return 0;
  }

  // Return the max flow from s to t for the graph G.
  ll maxFlow(const int s, const int t) {
      ll flow = 0;
      while (true) {
  	fill(used, used+MAX_V, false);

  	const ll f = dfs(s, t, LINF);
  	if (f==0) return flow;
  	flow += f;
      }
  }
};
// ========== end of template ==========
int H, W;
int N; //nodes

FordFulkerson<2+100+100> G;

int main(int argc, char** argv) {
  cin >> H >> W;

  N = 2 + H + W;
  vi sp(2);
  vi tp(2);

  int S = H+W;
  int T = H+W+1;

  REP(h, H) {
    string s;
    cin >> s;
    REP(w, W) {
      switch (s[w]) {
      case '.':
        break;
      case 'S':
        G.addEdge(h, w+H, LINF);
        G.addEdge(w+H, h, LINF);
        G.addEdge(S, h, LINF);
        G.addEdge(S, w+H, LINF);
        sp = {h, w};
        break;
      case 'T':
        G.addEdge(h, w+H, LINF);
        G.addEdge(w+H, h, LINF);
        G.addEdge(h, T, LINF);
        G.addEdge(w+H, T, LINF);
        tp = {h, w};
        break;
      case 'o':
        G.addEdge(h, w+H, 1);
        G.addEdge(w+H, h, 1);
        break;
      }
    }
  }

  if (sp[0] == tp[0] || sp[1]==tp[1]) {
    cout << -1 << endl;
    return 0;
  }

  cout << G.maxFlow(S, T) << endl;

  return 0;
}

/* vim: set expandtab shiftwidth=2 softtabstop=2 : */


Measured memory_bytes: 1536