É possível usar um shader para encontrar a "diferença" entre duas texturas? (Xna/hlsl)

StackOverflow https://stackoverflow.com/questions/1182158

  •  19-09-2019
  •  | 
  •  

Pergunta

Fiz um aplicativo simples baseado na webcam que detecta as "bordas do movimento", então desenha uma textura que mostra onde os pixels do quadro atual são significativamente diferentes do quadro anterior. Este é o meu código:

// LastTexture is a Texture2D of the previous frame.
// CurrentTexture is a Texture2D of the current frame.
// DifferenceTexture is another Texture2D.
// Variance is an int, default 100;

Color[] differenceData = new Color[CurrentTexture.Width * CurrentTexture.Height];
Color[] currentData = new Color[CurrentTexture.Width * CurrentTexture.Height];
Color[] lastData = new Color[LastTexture.Width * LastTexture.Height];

CurrentTexture.GetData<Color>(currentData);
LastTexture.GetData<Color>(lastData);

for (int i = 0; i < currentData.Length; i++)
{
    int sumCD = ColorSum(currentData[i]); // ColorSum is the same as c.R + c.B + c.G where c is a Color.
    int sumLD = ColorSum(lastData[i]);
    if ((sumCD > sumLD - Variance) && (sumCD < sumLD + Variance))
        differenceData[i] = new Color(0, 0, 0, 0); // If the current pixel is within the range of +/- the Variance (default: 100) variable, it has not significantly changes so is drawn black.
    else
        differenceData[i] = new Color(0, (byte)Math.Abs(sumCD - sumLD), 0); // This has changed significantly so is drawn a shade of green.
}

DifferenceTexture = new Texture2D(game1.GraphicsDevice, CurrentTexture.Width, CurrentTexture.Height);
DifferenceTexture.SetData<Color>(differenceData);

LastTexture = new Texture2D(game1.GraphicsDevice,CurrentTexture.Width, CurrentTexture.Height);
LastTexture.SetData<Color>(currentData);

Existe uma maneira de descarregar esse cálculo para a GPU usando shaders (ela pode ir a cerca de 25/26 fps usando o método acima, mas isso é um pouco lento)? Eu tenho um entendimento básico de como os shaders do HLSL funcionam e não esperam uma solução completa, só quero saber se isso seria possível e como obter os dados de textura da "diferença" do shader e se isso seria realmente mais rápido .

Desde já, obrigado.

Foi útil?

Solução

Em relação ao seu comentário acima sobre a decisão de usar uma abordagem de encadeamento duplo para o seu problema, confira as extensões paralelas .NET CTP da Microsoft. Microsoft.com

Se você não está planejando implantar para um Xbox360, essa biblioteca funciona muito bem com o XNA e eu vi grandes melhorias de velocidade em certos loops e iterações.

Você basicamente teria que alterar algumas linhas de código, por exemplo:

for (int i = 0; i < currentData.Length; i++)
{
    // ...
}

mudaria para:

Parallel.For(0, currentData.Length, delegate(int i)
{
   // ...
});

Para fazer automaticamente fazer cada núcleo em seu processador ajudar com o número de trituração. É rápido e excelente.

Boa sorte!

Outras dicas

Você pode provar duas texturas dentro do shader do pixel e depois escrever a diferença como o valor da cor. Se você configurar um Renderizar alvo, as informações de cores que você oput do shader serão armazenadas nesta textura em vez do framebuffer.

Não sei que tipo de ganho de velocidade você esperaria ver, mas é assim que eu faria.

*EDIT - Ah, e esqueci de dizer, esteja ciente do tipo de amostragem que você usa, pois isso afetará os resultados. Se você deseja que seu algoritmo se traduza diretamente na GPU, use a amostragem de pontos para começar.

o Operador Sobel Ou algo como é usado em mecanismos de jogo e outros aplicativos em tempo real para detecção de borda. É trivial escrever como um shader de pixels.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top