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

#define all(x) (x).begin(), (x).end()
#define sz(x) static_cast<int>((x).size())

using LL = long long;
template<class T, size_t D>
struct vec : vector<vec<T, D - 1>> {
  template<class... Args>
  vec(size_t n = 0, Args... args)
    : vector<vec<T, D - 1>>(n, vec<T, D - 1>(args...)) {}
};
template<class T>
struct vec<T, 1> : vector<T> {
  template<class... Args>
  vec(Args... args)
    : vector<T>(args...) {}
};

template<class T>
inline bool asMn(T& a, const T& b) { return a > b ? a = b, true : false; }
template<class T>
inline bool asMx(T& a, const T& b) { return a < b ? a = b, true : false; }
inline int nex(int i, int n) { return i == n - 1 ? 0 : i + 1; }
inline int pre(int i, int n) { return !i ? n - 1 : i - 1; }

const int INF = 1e9;
mt19937 rng(static_cast<uint32_t>(chrono::steady_clock::now().time_since_epoch().count()));

struct MaxFlow {
  int n, s, t;
  struct Edge {
    int to, c, f;
    Edge(int to_, int c_, int f_)
      : to(to_), c(c_), f(f_) {}
  };
  vec<Edge, 1> edge;
  vec<int, 2> adjEdge;
  vec<int, 1> dist, ptr;
  MaxFlow(int n_, int s_, int t_)
    : n(n_), s(s_), t(t_) {
    edge = vec<Edge, 1>();
    adjEdge = vec<int, 2>(n);
  }

  void addEdge(int u, int v, int c) {
    adjEdge[u].emplace_back(sz(edge)); edge.emplace_back(v, c, 0);
    adjEdge[v].emplace_back(sz(edge)); edge.emplace_back(u, 0, 0);
  }

  bool bfs() {
    dist = vec<int, 1>(n, INF); dist[s] = 0;
    ptr = vec<int, 1>(n, 0);
    queue<int> q; q.emplace(s);
    while (sz(q)) {
      int u = q.front(); q.pop();
      for (auto& i : adjEdge[u]) {
        if (edge[i].c > edge[i].f && dist[edge[i].to] == INF) {
          dist[edge[i].to] = dist[u] + 1;
          q.emplace(edge[i].to);
        }
      }
    }
    return dist[t] != INF;
  }

  int dfs(int u, int flow) {
    if (u == t) {
      return flow;
    }
    for (; ptr[u] < sz(adjEdge[u]); ++ptr[u]) {
      int i = adjEdge[u][ptr[u]];
      if (edge[i].c == edge[i].f || dist[edge[i].to] != dist[u] + 1) {
        continue;
      }
      int ret = dfs(edge[i].to, min(flow, edge[i].c - edge[i].f));
      if (ret) {
        edge[i].f += ret;
        edge[i ^ 1].f -= ret;
        return ret;
      }
    }
    return 0;
  }

  int get() {
    int ret = 0;
    while (bfs()) {
      int tmp;
      while ((tmp = dfs(s, INF))) {
        ret += tmp;
      }
    }
    return ret;
  }
};

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  #ifdef EntityIT
  freopen("input.txt", "r", stdin);
  #endif // EntityIT

  int n, m; cin >> n >> m;

  auto to1D = [&](int x, int y) { return x * m + y; };
  auto in = [&](int x, int y) { return to1D(x, y) << 1; };
  auto out = [&](int x, int y) { return to1D(x, y) << 1 | 1; };

  vec<char, 2> grid(n, m);
  pair<int, int> s, t;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      cin >> grid[i][j];
      if (grid[i][j] == 'S') {
        s = {i, j};
      } else if (grid[i][j] == 'T') {
        t = {i, j};
      }
    }
  }

  MaxFlow mf(2 * n * m, in(s.first, s.second), out(t.first, t.second));
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      mf.addEdge(in(i, j), out(i, j), grid[i][j] == 'o' ? 1 : INF);
    }
  }
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      if (grid[i][j] != '.') {
        for (int k = 0; k < m; ++k) {
          if (j != k && grid[i][k] != '.') {
            mf.addEdge(out(i, j), in(i, k), INF);
          }
        }
      }
    }
  }
  for (int j = 0; j < m; ++j) {
    for (int i = 0; i < n; ++i) {
      if (grid[i][j] != '.') {
        for (int k = 0; k < n; ++k) {
          if (i != k && grid[k][j] != '.') {
            mf.addEdge(out(i, j), in(k, j), INF);
          }
        }
      }
    }
  }

  int ans = mf.get();
  cout << (ans < INF ? ans : -1) << '\n';

  return 0;
}


Measured memory_bytes: 71116