Funcionamento do DIRAC

Nessa seção, iremos descrever aspéctos do funcionamento do Dirac relacionados ao software desenvolvido. O objetivo é dar ao leitor ferramentas teóricas para entender a ferramenta apresentada.

Visão geral

O Dirac é um codec livre de royalties (pode ser usado sem precisar pagar licenças), voltado à compressão de vídeos de uso geral, desde QCIF (176x144) até HDTV (1920x1080). Ele usa diversos métodos de compressão e visa ser competitivo com outros codecs.

Ele foi desenvolvido para enfrentar a crescente complexidade e custos das tecnologias de compressão de vídeo atuais. Dirac é um poderoso e flexível sistema de compressão, que oferece uma solução completa de compressão a partir de um pequeno conjunto de ferramentas. Um elemento chave da sua flexibilidade é a utilização da wavelet multi-resolution transform para comprimir as imagens e movimentos (modelo híbrido de compensação de movimento), que permite que o Dirac seja utilizado em toda uma gama de resoluções sem recorrer a outras ferramentas.

O Dirac possui um excelente desempenho em comparação a outros codecs, e certamente é muito melhor do que MPEG-2.

Arquitetura

Conforme apresentado pelo projeto dirac-research, a arquitetura do nosso encoder vai seguir o modelo híbrido de compensasão de movimento. Abaixo temos sua arquitetura geral:

Figura 1: Arquitetura do encoder híbrido por compensasão de movimento
Figura 1: Arquitetura do encoder híbrido por compensasão de movimento

As principais funcionalidades do Dirac podem ser organizadas em 4 grupos.

O primeiro é destacado pelo bloco de transformação, escala e quantização, que será responsável por pegar os dados de um frame e aplicar a wavelet transform, além de escalar os coeficientes para aplicar a quantização.

O segundo está relacionado ao Entropy coding. A partir dos vetores de movimento e dos coeficientes gerados pelo grupo anterior, será capaz de gerar dados compactados.

O terceiro bloco, Motion estimation, é responsável por buscar a relação entre o frame atual e os frames codificados que são referenciados, a partir da relação entre distorção e taxa de bits dos vetores de movimento.

Por fim, o quarto bloco a se destacar é o Motion compensantion, responsável por prever o frame atual a partir dos vetores de movimento para minimizar a necessidade de codificar os dados resuduais.

Princípio do RDO

Para a codificação de vídeo, o Dirac se utiliza do Rate-Distortion Optimization. Esse método pode ser descrito em termos de multiplicadores Lagrangianos e é baseado no Principle of Equal Slopes, que define que o parâmetro de codificação deve ser selecionado de modo a termos uma variação entre taxa de bits e distorção igual para todas as partes do sistema.

Isso pode ser visto graficamente a partir dos gráficos abaixo. Eles representam duas curvas de distorção por taxa de bits, nas quais temos selecionados os valores de B1 e B2. Para cada ponto na curva, temos diferentes valores da derivada.

Figura 2: Curvas de taxa de bits x distorção para dois componentes do sinal
Figura 2: Curvas de taxa de bits x distorção para dois componentes do sinal
Segundo o Principle of Equal Slopes, devemos escolher valores em que a derivada tenha sempre o mesmo valor para garantirmos uma escolha ótima.

Para obtermos o mesmo valor da derivada em todos os componentes, partimos de um valor de λ, que define o valor desejado da derivada no ponto.

Figura 3:  Deslocamento da curva D + λR
Figura 3: Deslocamento da curva D + λR

Assim, conforme podemos notar no gráfico acima, temos que minimizar a função:

Error(p) + λ * Rate(p) (1)
a fim de encontrarmos o ponto com a derivada desejada.

Para se conseguir uma atingir uma taxa de bits específica, é necessário iteragir sobre os valores do parâmetro λ a fim de encontrarmos o valor que nos dá a taxa desejada. Na prática, essa iteração é feita de forma rápida quando se tem um tamanho de buffer adequado. Utiliza-se um histórico recente para modelar a curva de taxa de bits x distorção.

É interessante notar que o parâmetro de Lagrange λ é calculado a partir do parâmetro de coficação QF em cada parte do processo.

Estimativa de movimento

O Dirac trabalha com três tipos de imagens. Imagens do tipo Intra, que são codificadas sem nenhuma referência, imagens do tipo L1 e imagens do tipo L2. Os dois tipos de imagens são codificados a partir de outras imagens previamente codificadas, mas não necessariamente anteriores na sequência temporal do vídeo.

As imagens do tipo L1 são codificadas sempre a partir de imagens I ou imagens L1 anteriores. Dessa forma, em um grupo de imagens (GOP), a primeira imagem L1 vai ter apenas uma referência, ou seja, apenas à imagem I, que inicia o grupo. Já as imagens L1 posteriores terão como referência as duas últimas images L1/I.

Já as imagens L2 possuem duas referências, uma anterior e uma posterior. A referência posterior está sempre ligada a uma imagem do tipo I ou L1. Já a referência anterior será sempre a imagem imediatamente anterior a ela no curso temporal do filme. Dessa forma, essa referência pode ser qualquer um dos três tipos de imagens.

Assim, a partir dos parâmetros de codificação do Dirac L1sep = 3 e NumL1 = 2, podemos contruir o seguinte grupo de imagens:

Figura 4: Grupo de imagens com L1_sep = 3 e Num_L1 = 2
Figura 4: Grupo de imagens com L1sep = 3 e NumL1 = 2
Para realizar a predição, o Dirac conta com dois buffers de imagens nos quais cada imagem é armazenada com informações referentes a ordem em que deve ser exibida, referências a outras imagens e o momento em que deve ser descartada.

A estimativa de movimento é a parte mais complicada e que mais consome recursos no sistema de codificação de vídeos. Assim, para melhorar o desempenho dessa tarefa, o Dirac adota um abordagem em 3 passos.

No primeiro passo, os vetores de movimeto são encontrados para cada bloco e cada referência usando uma estimativa de movimento hierárquica. Nela, tanto as imagens quanto as referências são reduzidos de tamanho por um fator de 2 em cada dimensão a cada estágio da hierarquia. Dessa forma, temos imagens menores para realizarmos a busca. Apesar das imagens estarem 4 vezes menor a cada estágio, mantemos os tamanhos dos blocos. Dessa forma, temos 4 vezes menos blocos disponíveis para cada estágio. Quando vamos retornando aos estágios onde as imagens são maiores, usamos os vetores de movimento encontrado nos estágios anteriores como referência para a nova busca, limitando ela a uma região ao redor desses vetores de referência.

Por fim, o Dirac sempre inclui um vetor de comprimento zero em cada sub-macrobloco como parte da região de busca para que não sejam perdidos movimentos lentos.

No segundo passo, os vetores encontrados são refinados usando uma precisão de sub-pixel. Esse processo também ocorre hierarquicamente, com passos de 1/2 em 1/2 pixel até a precisão desejada. O primeiro estágio é feito comparando-se o vetor (V0,W0) encontrado para um determinado sub-bloco com seus 8 vizinhos (V04,W04), (V0,W04), (V0-4,W04), (V04,W0), (V0-4,W0), (V04,W0-4), (V0,W0-4), (V0-4,W0-4).

Assim será escolhido um novo vetor (V1,W1), que será um guia para o próximo estágio. Podemos observar o processo graficamente a partir da imagem abaixo:

Figura 5: Refinamento hierarquico com precisão de sub-pixels até 1/8 de pixel
Figura 5: Refinamento hierarquico com precisão de sub-pixels até 1/8 de pixel
Por fim, na terceira fase é feita a escolha dos modos de decisão, que escolhe qual preditor será usado e como os vetores de movimento serão agrupados.

A estimativa de movimento é mais acurada quando se levam em conta todos os três componentes envolvidos, mas esse processo é extremamente custoso do ponto de vista de processamento além de ser mais complicado. Assim, o Dirac utiliza apenas a luminância para a estimativa de movimento.

Compensação de movimento

Métodos de predição de compensação de movimento permitem que possamos prever os pixels de uma determinada imagem a partir dos vetores de movimento e da diferença entre essa imagem e a imagem anterior a qual aplica-se os vetores de movimento.

As diferentes técnicas apresentam formas diferentes de agrupamento dos pixels e mesmo em como a predição é formada a partir desses agrupamentos. Na compensação de blocos de movimentos convencional, como as usadas no MPEG2, H.264 e muito outros codecs, as imagens sao divididas em blocos retangulares disjuntos e os vetores de movimentos, associados a cada bloco, definem as diferenças entre as imagens de referência.

No OBMC, a imagem que está sendo predita é dividida em blocos de dimensão xblen e yblen, com sobreposição regular, de forma a cobrir, pelo menos, a imagem toda, conforme mostrado abaixo.

A sobreposição é garantida iniciando cada bloco na horizontal com uma separação xbsep e na vertical por ybsep dos seus vizinhos, onde esses valores sao menores que os correspondentes tamanhos dos blocos. A sobreposição entre os blocos na horizontal é dada por:

xoffset = (xblen−xbsep)/2, (2)
tanto na esquerda quanto na direita.

Na vertical, temos:

yoffset = (yblen−ybsep)/2 (3)
em cima e em baixo.

Figura 6: Cobertura dos blocos de uma imagem sendo predita
Figura 6: Cobertura dos blocos de uma imagem sendo predita
Como resultado, um pixel que está em uma area sobreposta pertence a mais de um bloco, logo estará associado a mais de uma predição, podendo chegar a ter oito predições associados a ele, sendo 4 blocos e 2 referências. Essas predições são combinadas em uma única a partir de pesos que totalizam 1.

No Dirac, os blocos irão ultrapassar tanto a esquerda quanto o topo por xoffset e yoffset. A imagem será completamente coberta pelos blocos e, tanto na direita quanto na parte de baixo, os blocos poderão ultrapassar as margens por algum outro valor, podendo haver blocos completamente fora da imagem. Isso acontece pois os blocos estão organizados em macroblocos, que são matrizes de 4x4 blocos.As predições para pixels fora da imagem são descartadas.

Macroblocos

Um macrobloco (MB) consiste em uma matriz 4x4 de blocos, e podem ser divididos de 3 maneiras diferentes:
  • nível 0: sem divisão, apenas um vetor de movimento por referência para o MB;
  • nível 1: dividido em 4 sub-macroblocos. cada um com uma matriz 2x2 de blocos e um vetor de movimento por sub-macrobloco por referência;
  • nível 2: dividido em 16 sub-macroblocos, o que significa q o macrobloco foi dividido nos seus 16 blocos.

Figura 7: Modos de divisão do macrobloco

Figura 7: Modos de divisão do macrobloco
O modo de divisão é escolhido a partir da repetição do processo de estimativa de movimento para os sub-macroblocos e para o macrobloco como um todo, usando a métrica RDO, e levando-se em conta os diferentes tamanhos de cada entidade. Ao mesmo tempo, é escolhido o melhor modo de predição para cada entidade. Existem quatro modos disponíveis:
  • INTRA: codificado intra, predito por valores DC;
  • REF1_ONLY: predito apenas a partir da referência 1;
  • REF2_ONLY: predito apenas a partir da referência 2, caso exista;
  • REF1AND2: predição bidirecional.

O resultado é uma hierarquia de parâmetros: o nivel de divisões determina qual modo, vetores de movimento e, no caso do tipo intra, os valores DC do bloco serão apresentados.

Na estimativa de movimento, um custo geral por macrobloco é computado e comparado para cada combinação deses parâmetros. É uma operação complicada que possui um efeito significativo na performance.

O Dirac consegue usar quase qualquer tamanho de bloco para o processo de sobreposição funcionar adequadamente, especialmente quando temos o croma subamostrado. Por exemplo, a separação entre blocos deve ser multipla de 4 com relação ao tamanho do bloco para que possamos ter uma sobreposição simétrica para luminancia e crominancia em um caso de subamostragem de crominancia.

Codificando uma sequência

Para termos uma visão geral do trabalho realizado pelo Dirac, vamos ver como uma sequencia é codificada.

Durante a codificação, o Dirac mantem o controle de quantas imagens já foram codificadas, quantas imagens foram armazenadas no buffer e qual é a próxima imagem a ser codificada, segundo o grupo de imagens. Assim, ele consegue gerencias seus 2 buffers de imagens, um que contem as imagens limpas, que são utilizadas pela estimativa de movimento, e outro que contem uma versão decodificada de uma imagem já codificada, que é usada para a compensação de movimento.

Como a codificação não é feita na mesma ordem em que as imagens são apresentadas, devido a presença de imagens do tipo L2, o Dirac verifica se a próxima imagem a ser codificada já está no buffer. Se não estiver prossegue lendo mais imagens do vídeo original para o buffer.
Assim que a proxima imagem a ser codificada entra no buffer, ele a codifica e armazena no buffer de imagens codificadas e incrementa o número de imagens já codificadas.

Por fim, o Dirac verifica os buffers em busca de imagens que já podem ser descartadas, pois já foram codificadas e as imagens que se referem a ela também já a utilizaram. Dessa forma, o Dirac consegue trabalhar com um buffer relativamente pequeno, proporcional aos parâmetros de configuração do grupo de imagens e das características dos quadros que estão sendo codificados.

É interessante notar que, caso esteja habilitado o Denoising, a cada figura lida do vídeo para o buffer é aplicado um filtro 3x3, com a seguinte configuração:

1 1 1
1 5 1
1 1 1
Assim, temos que cada pixel tem seu valor alterado para a uma média em que seu valor é multiplicado por 5 e é considerado seus 8 vizinhos com peso 1. Dessa forma, reduzimos o ruído na imagem.

A codificação de uma imagem é feita da seguinte forma. Primeiramente definimos os parâmetros de codficação da imagem, como por exemplo suas referências e quantizadores, a partir de sua posição no grupo de imagens. Se a imagem não for do tipo Intra, fazemos a estimativa de movimento. Caso uma imagem do tipo L1 ou L2 possua mais de 33% de seus blocos do tipo intra, consideramos que a estimativa de movimento falhou para essa imagem e convertemos ela em uma imagem do tipo Intra, sem alterar as referências para ela. Isso é chamado de Cut Detection. Caso a imagem resultante ainda não seja do tipo intra, é realizado a compensação de movimento.

Para cada componente e para cada sub-banda, é selecionado o lambda RDO e o quantizador que serão usados. Por fim, é aplicado a quantisação e codificação a sub-bandas dos componentes.

Last edited Mar 31, 2010 at 2:41 PM by tiagodeliberali, version 9

Comments

No comments yet.