Ridimensionamento e rotazione dell’immagine in C / C ++

Qual è il modo migliore per scalare un array di immagini 2D? Ad esempio, supponiamo di avere un’immagine di 1024 x 2048 byte, con ogni byte come un pixel. Ogni pixel è un livello di scala di grigi da 0 a 255. Mi piacerebbe essere in grado di ridimensionare questa immagine con un fattore arbitrario e ottenere una nuova immagine. Quindi, se ridimensiono l’immagine di un fattore di 0,68, dovrei ottenere una nuova immagine di dimensione 0,68 * 1024 x 0,68 * 2048. alcuni pixel saranno collassati l’uno sull’altro. E, se scala di un fattore di dire 3.15, otterrei un’immagine più grande con pixel duplicati. Quindi, qual è il modo migliore per farlo?

Successivamente, mi piacerebbe essere in grado di ruotare un’immagine con un angolo arbitrario, nell’intervallo da 0 a 360 gradi (0 – 2Pi). Il ritaglio dell’immagine dopo la rotazione non è un problema. Quale sarebbe il modo migliore per farlo?

Non esiste un modo “semplice” per realizzarlo. Sia il ridimensionamento che la rotazione non sono procesis “banali”.

Google per una libreria di imaging 2D. Magick ++ può essere un’idea come punti divideandconquer.se, ma ce ne sono altri.

Esistono molti modi per ridimensionare e ruotare le immagini. Il modo più semplice per ridimensionare è:

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

ma questo produce effetti di blocco quando si aumentano le dimensioni e la perdita di dettagli quando si riduce la dimensione. Esistono modi per produrre risultati migliori, ad esempio il filtro bilineare .

Per la rotazione, la posizione del pixel src può essere calcasting usando una matrice di rotazione :

 sx,sy = M(dx,dy) 

dove M è una matrice che mappa i pixel di destinazione nell’immagine sorgente. Di nuovo, dovrai eseguire l’interpolazione per produrre risultati non di blocco.

Ma ci sono un sacco di librerie disponibili se non vuoi entrare nella matematica dell’elaborazione delle immagini.

Quello che stai facendo è mappare una serie di punti di input a una serie di punti di output. La prima parte del problema è determinare la mapping per il ridimensionamento o la rotazione; la seconda parte è di gestire punti che non si trovano esattamente su un limite di pixel.

La mapping per un ridimensionamento è facile:

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

La mapping per la rotazione è solo un po ‘più difficile.

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

La tecnica per determinare il valore dei pixel che si trovano fuori dalla griglia viene chiamata interpolazione. Esistono molti algoritmi di questo tipo, che variano ampiamente in termini di velocità e qualità finale dell’immagine. Alcuni di essi in ordine crescente di qualità / tempo sono il filtro vicino, bilineare, bicubico e Sinc.

Vuoi fare il lavoro sporco da solo o puoi farlo ImageMagick per te?

Duplicare o scartare i pixel non è il metodo migliore o il ridimensionamento delle immagini, in quanto i risultati mostreranno pixelizzazione e nervosità. Per i migliori risultati, dovresti ricampionare l’immagine, che darà all’immagine risultante un aspetto molto più liscio. Esistono molti metodi per ricampionare, come bilineare, bicubico, lanczos ecc.

Dai un’occhiata alla funzione BicubicResample di wxWidgets. Funzionerà con tutti i tipi di immagini, non solo in scala di grigi, ma dovresti essere in grado di adattarlo alle tue esigenze. Poi c’è anche il codice di ricampionamento da VirtualDub . Google Codesearch potrebbe rivelare più codice correlato.

MODIFICA: i collegamenti sembrano buoni nell’anteprima, ma sono interrotti quando pubblicati. Questo è strano. Vai su google codesearch e cerca rispettivamente “wxwidgets resamplebicubic” e “virtualdub resample” per ottenere gli stessi risultati.

CxImage è una libreria gratuita per la gestione delle immagini, che può fare ciò che vuoi. Non l’ho usato personalmente tranne che per cose banali, ma l’ho visto raccomandato ripetutamente.

Non è stato ancora menzionato, quindi sottolineerò che OpenCV ha funzioni per ridimensionare e ruotare le immagini, oltre a un numero enorme di altre utilità. Può contenere molte funzionalità che non sono rilevanti per la domanda, ma è molto facile da configurare e utilizzare per una libreria del suo genere.

Puoi provare a implementare le trasformazioni in questo modo manualmente, ma il semplice approccio al ridimensionamento e alla rotazione genererà generalmente una significativa perdita di dettagli.

Usando OpenCV, il ridimensionamento può essere fatto in questo modo:

 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); 

Riduce l’immagine di un fattore di 0,68 utilizzando l’interpolazione Lanczos.

Non ho familiarità con le rotazioni, ma qui fa parte di un esempio tratto da una delle esercitazioni sul sito Web di OpenCV che ho modificato nelle parti pertinenti. (L’originale aveva obliquità e traduzione anche in …)

 /// 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()); 

Sito Web OpenCV

Hanno anche una documentazione molto bella.

I metodi di ridimensionamento CxImage producono risultati strani. Ho usato le funzioni Resample e Resample2 con tutte le varianti disponibili dei metodi di interpolazione con lo stesso risultato. Ad esempio, prova a ridimensionare l’immagine 1024 x 768 riempita con il colore bianco fino alla dimensione 802 x 582. Scoprirai che ci sono dei pixel sull’immagine che hanno un colore diverso dal bianco! Puoi verificarlo: apri l’immagine ridimensionata in Windows Paint e prova a riempirla di nero. Il risultato ti divertirà sicuramente.

 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; } 

Scopri Intel Performance Primitives . L’ho usato prima e produce prestazioni quasi ottimali su x86. C’è anche un programma di test che consente di giocare con i vari algoritmi.