Em sua essência tanto refe outfornecer um mecanismo para passar o endereço de uma variável a um método para que ele possa ser atualizado - atribuindo ao refou outparâmetro atualiza a variável no contexto do chamador. Onde eles diferem está nas garantias: outgarante que a variável será atualizada, refnão.
Do outro lado da chamada, existem diferenças semelhantes. outNão é garantido que um parâmetro para nosso método contenha algo útil na chegada e deve ser definido como um valor em algum momento, enquanto um refparâmetro pode ser assumido como tendo um valor e não precisamos fazer nada específico com ele.
Essa diferença tem impactos na análise, geração e otimização de código que, embora não sejam muito aparentes para nós na maioria das vezes, podem ter alguns efeitos na maneira como nossos programas acabam operando. O gerador de código pode adiar a alocação da variável até imediatamente antes da chamada, o otimizador pode decidir que pode reordenar algumas operações com mais eficácia com base no contrato, etc.
Em termos de uso: como regra geral, uso outpara situações em que não me importo com o conteúdo da variável quando ela chega como parâmetro e refquando eu faço.