Redimensionamento de imagem e rotação em C / C ++

Qual é a melhor maneira de dimensionar um array de imagens 2D? Por exemplo, suponha que eu tenha uma imagem de 1024 x 2048 bytes, com cada byte sendo um pixel. Cada pixel é um nível de escala de cinza de 0 a 255. Gostaria de poder dimensionar essa imagem por um fator arbitrário e obter uma nova imagem. Então, se eu dimensionar a imagem por um fator de 0,68, eu deveria obter uma nova imagem de tamanho 0,68 * 1024 x 0,68 * 2048. alguns pixels serão recolhidos uns sobre os outros. E, se eu dimensionar por um fator de digamos 3,15, obteria uma imagem maior com os pixels sendo duplicados. Então, qual é a melhor maneira de conseguir isso?

Em seguida, gostaria de poder girar uma imagem por um ângulo arbitrário, no intervalo de 0 a 360 graus (0 – 2Pi). Recorte da imagem após a rotação não é um problema. Qual seria a melhor forma de fazer isso?

Não há um modo “simples” de explicar isso. Tanto a escala como a rotação não são proceses “triviais”.

Google-lo para uma biblioteca de imagens 2d. Magick ++ pode ser uma idéia como pontos divideandconquer.se, mas existem outros.

Há muitas maneiras de dimensionar e girar imagens. A maneira mais simples de escalar é:

dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height] 

mas isso produz efeitos de blocos ao aumentar o tamanho e a perda de detalhes ao reduzir o tamanho. Existem maneiras de produzir resultados com melhor aparência, por exemplo, filtragem bilinear .

Para rotação, a localização do pixel src pode ser calculada usando uma matriz de rotação :

 sx,sy = M(dx,dy) 

onde M é uma matriz que mapeia os pixels de destino para a imagem de origem. Novamente, você precisará fazer interpolação para produzir resultados não-blocky.

Mas há muitas bibliotecas disponíveis se você não quiser entrar na matemática do processamento de imagens.

O que você está fazendo é mapear um conjunto de pontos de input para um conjunto de pontos de saída. A primeira parte do problema é determinar o mapeamento para o seu redimensionamento ou rotação; a segunda parte é manipular pontos que não estão exatamente em um limite de pixels.

O mapeamento para um redimensionamento é fácil:

 x' = x * (width' / width) y' = y * (height' / height) 

O mapeamento para rotação é apenas um pouco mais difícil.

 x' = x * cos(a) + y * sin(a) y' = y * cos(a) - x * sin(a) 

A técnica para determinar o valor dos pixels que estão fora da grade é chamada de interpolação. Existem muitos desses algoritmos, que variam amplamente em velocidade e qualidade de imagem final. Alguns deles, em ordem crescente de qualidade / tempo, são o vizinho mais próximo, o bilinear, o bicubico e o filtro Sinc.

Você quer fazer o trabalho sujo sozinho ou o ImageMagick pode fazer isso por você?

A duplicação ou descarte de pixels não é o melhor método ou redimensionamento de imagem, pois os resultados mostrarão pixelação e jagginess. Para obter os melhores resultados, você deve criar uma nova amostra da imagem, o que dará à imagem resultante uma aparência muito mais suave. Existem muitos methods para reamostragem, como bilineares, bicubicos, lanczos etc.

Dê uma olhada na function BicubicResample do wxWidgets. Ele funciona com todos os tipos de imagens, não apenas em escala de cinza, mas você deve ser capaz de adaptá-lo às suas necessidades. Então também há um código de reamostragem do VirtualDub . A Google Codesearch pode revelar mais códigos relacionados.

EDIT: os links parecem bem na pré-visualização, mas são quebrados quando postados. Isto é estranho. Vá para a pesquisa de códigos do Google e consulte “wxwidgets resamplebicubic” e “virtualdub resample” respectivamente para obter os mesmos resultados.

CxImage é uma biblioteca gratuita para manipular imagens, que pode fazer o que quiser. Eu pessoalmente não usei isso, exceto por coisas triviais, mas eu vi isso recomendado repetidamente.

Ainda não foi mencionado, por isso vou salientar que o OpenCV tem funções para escalar e rodar imagens, bem como um enorme número de outras utilidades. Ele pode conter muitos resources que não são relevantes para a pergunta, mas é muito fácil de configurar e usar para uma biblioteca desse tipo.

Você pode tentar implementar transformações como essa manualmente, mas a abordagem simples para dimensionamento e rotação geralmente resultará em uma perda significativa de detalhes.

Usando o OpenCV, o escalonamento pode ser feito da seguinte maneira:

 float scaleFactor = 0.68f; cv::Mat original = cv::imread(path); cv::Mat scaled; cv::resize(original, scaled, cv::Size(0, 0), scaleFactor, scaleFactor, cv::INTER_LANCZOS4); cv::imwrite("new_image.jpg", scaled); 

Isso reduz a imagem por um fator de 0,68 usando a interpolação de Lanczos.

Eu não sou tão familiarizado com rotações, mas aqui está parte de um exemplo de um dos tutoriais no site do OpenCV que eu editei para as partes relevantes. (O original tinha distorção e tradução também …)

 /// Compute a rotation matrix with respect to the center of the image Point center = Point(original.size().width / 2, original.size().height / 2); double angle = -50.0; double scale = 0.6; /// Get the rotation matrix with the specifications above Mat rot_mat( 2, 3, CV_32FC1 ); rot_mat = getRotationMatrix2D(center, angle, scale); /// Rotate the image Mat rotated_image; warpAffine(src, rotated_image, rot_mat, src.size()); 

Site OpenCV

Eles também têm uma documentação muito legal.

Os methods de redimensionamento CxImage produzem um resultado estranho. Eu usei as funções Resample e Resample2 com todas as variações disponíveis de methods de interpolação com o mesmo resultado. Por exemplo, tente resize a imagem de 1024 x 768 preenchida com cor branca para o tamanho 802 x 582. Você verá que há pixels na imagem com colors diferentes do branco! Você pode verificar isso: abra a imagem redimensionada no Windows Paint e tente preenchê-la com a cor preta. Resultado certamente irá diverti-lo.

 point scaling(point p,float sx,float sy) { point s; int c[1][3]; int a[1][3]={px,py,1}; int b[3][3]={sx,0,0,0,sy,0,0,0,1}; multmat(a,b,c); sx=c[0][0]; sy=c[0][1]; return s; } 

Confira as Primitivas de desempenho da Intel . Eu usei-o antes e ele produz um desempenho quase ótimo em x86. Existe também um programa de teste que permite jogar com os vários algoritmos.