簡體   English   中英

C/C++ 中的圖像縮放和旋轉

[英]Image scaling and rotating in C/C++

縮放二維圖像陣列的最佳方法是什么? 例如,假設我有一個 1024 x 2048 字節的圖像,每個字節都是一個像素。 每個像素都是從 0 到 255 的灰度級別。我希望能夠通過任意因子縮放此圖像並獲得新圖像。 所以,如果我將圖像縮放 0.68 倍,我應該得到一個大小為 0.68*1024 x 0.68*2048 的新圖像。 一些像素將相互折疊。 而且,如果我按 3.15 的系數進行縮放,我會得到一個像素被復制的更大的圖像。 那么,實現這一目標的最佳方法是什么?

接下來,我希望能夠在 0 到 360 度 (0 - 2Pi) 的范圍內以任意角度旋轉圖像。 旋轉后裁剪圖像不是問題。 什么是最好的方法來做到這一點?

有多種縮放和旋轉圖像的方法。 最簡單的擴展方法是:

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

但這在增加尺寸時會產生塊狀效果,而在減小尺寸時會丟失細節。 有一些方法可以產生更好看的結果,例如,雙線性過濾

對於旋轉,可以使用旋轉矩陣計算 src 像素位置:

sx,sy = M(dx,dy)

其中 M 是將目標像素映射到源圖像的矩陣。 同樣,您需要進行插值以產生非塊狀結果。

但是如果你不想進入圖像處理的數學,有很多可用的庫。

您正在做的是將一組輸入點映射到一組輸出點。 問題的第一部分是確定調整大小或旋轉的映射; 第二部分是處理不完全位於像素邊界上的點。

調整大小的映射很容易:

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

旋轉映射只是有點困難。

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

確定網格外像素值的技術稱為插值。 有許多這樣的算法,在速度和最終圖像質量方面差別很大。 其中一些按質量/時間遞增的順序是最近鄰濾波器、雙線性濾波器、雙三次濾波器和 Sinc 濾波器。

沒有簡單的方法可以實現這一點。 縮放和旋轉都不是微不足道的過程。

因此,建議使用 2d 成像庫。 正如divideandconquer.se 指出的那樣, Magick++可以是一個想法,但還有其他想法。

你想自己做這些骯臟的工作還是ImageMagick可以為你做?

復制或丟棄像素不是最好的方法或圖像調整大小,因為結果會顯示像素化和鋸齒。 為了獲得最佳效果,您應該對圖像重新采樣,這將使生成的圖像看起來更加平滑。 重采樣的方法有很多,比如雙線性、雙三次、lanczos 等。

看看 wxWidgets 的ResampleBicubic函數。 它適用於各種圖像,不僅是灰度,而且您應該能夠根據自己的需要進行調整。 然后還有來自 VirtualDub的重采樣代碼。 Google Codesearch 可能會顯示更多相關代碼。

編輯:鏈接在預覽中看起來不錯,但發布時已損壞。 這很奇怪。 去谷歌代碼搜索並分別查詢“wxwidgets resamplebicubic”和“virtualdub resample”得到相同的結果。

它還沒有被提及,所以我將指出 OpenCV 具有縮放和旋轉圖像的功能,以及大量其他實用程序。 它可能包含許多與問題無關的功能,但它非常容易設置和用於此類庫。

您可以嘗試手動實現這樣的轉換,但是縮放和旋轉的簡單方法通常會導致大量細節丟失。

使用 OpenCV,可以像這樣進行縮放:

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

這使用 Lanczos 插值將圖像縮小了 0.68 倍。

我對旋轉不太熟悉,但這里是 OpenCV 網站上的一個教程中的一個示例的一部分,我已將其編輯為相關部分。 (原文也有歪斜和翻譯……)

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

OpenCV 網站

他們也有一些非常好的文檔。

CxImage是一個免費的圖像處理庫,可以為所欲為 除了瑣碎的東西,我沒有親自使用它,但我看到它反復推薦。

CxImage 調整大小方法會產生奇怪的結果。 我將 Resample 和 Resample2 函數與所有可用的插值方法變體一起使用,結果相同。 to white!例如,嘗試將填充白色的 1024 x 768 圖像調整為 802 x 582 大小。您會發現圖像上的像素顏色白色 您可以檢查一下:在 Windows Paint 中打開調整大小的圖像並嘗試用黑色填充它。 結果肯定會讓你開心。

查看英特爾性能原語 我以前使用過它,它在 x86 上產生了接近最佳的性能。 還有一個測試程序可以使用各種算法。

point scaling(point p,float sx,float sy) {
    point s;

    int c[1][3];
    int a[1][3]={p.x,p.y,1};
    int b[3][3]={sx,0,0,0,sy,0,0,0,1};

    multmat(a,b,c);

    s.x=c[0][0];
    s.y=c[0][1];

    return s;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM