1、圖片的本質
圖像在 OpenCV 中的本質
在 OpenCV 中,圖像被表示為一個多維數組,其中每個元素對應于圖像中的單個像素。圖像的維度取決于其通道數和像素數。
- **通道數:**圖像可以有多個通道,每個通道存儲圖像的不同信息。例如,彩色圖像通常有 3 個通道(紅色、綠色和藍色),而灰度圖像只有一個通道。
- **像素數:**圖像的像素數決定了其寬度和高度。
圖像存儲方式
OpenCV 中的圖像通常以以下格式存儲:
- **Mat:**這是 OpenCV 中最常用的圖像表示形式。Mat 是一個多維數組,可以存儲不同類型的圖像數據(例如,uint8、float32 等)。
- **IplImage:**這是一個舊的圖像表示形式,在 OpenCV 2.0 之前使用。它與 Mat 類似,但有一些限制。
Mat 中圖像的存儲
Mat 中的圖像數據以行優先順序存儲。這意味著圖像的第一個維度對應于行,而第二個維度對應于列。對于一個 3 通道的彩色圖像,Mat 中的元素順序如下:
[B00, G00, R00, B01, G01, R01, ..., Bmn, Gmn, Rmn]
其中:
B
、G
、R
表示藍色、綠色和紅色通道m
和n
是圖像的高度和寬度
通道的順序
OpenCV 中圖像的通道順序通常為 BGR(藍色、綠色、紅色)。這與其他一些圖像處理庫(如 PIL)中使用的 RGB 順序不同。
其他圖像存儲格式
除了 Mat 和 IplImage 之外,OpenCV 還支持其他圖像存儲格式,包括:
- **UMat:**一種優化的 Mat,可利用 GPU 加速。
- **cuda::GpuMat:**一種專用于 GPU 處理的 Mat。
- **std::vector<uchar>:**一種使用標準 C++ 向量存儲圖像數據的格式。
2、Mat
從文件讀取圖片并顯示
#include <iostream>
#include "opencv2/core.hpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>using namespace std;
using namespace cv;int main(){Mat image;image = imread("firefox.png"); //imread()讀取圖片if(!image.empty()){imshow("1",image); //imshow展示圖片,前面為展示名,后面為圖片。waitKey(0);}destroyAllWindows();return 0;
}
從文件讀取圖片并顯示
waitKey(0)
是 OpenCV 中的一個函數,用于等待用戶按下一個鍵。它有以下作用:
- 暫停程序執行:
waitKey(0)
會暫停程序執行,直到用戶按下一個鍵。這通常用于在顯示圖像或視頻時讓用戶有機會查看內容。 - **獲取按鍵:**當用戶按下一個鍵時,
waitKey(0)
會返回該鍵的 ASCII 碼。這可用于檢測用戶輸入并做出相應操作。 - 無限等待:
waitKey(0)
的參數為 0 表示無限等待。這意味著程序將一直暫停,直到用戶按下一個鍵。
使用示例:
cv::Mat image = cv::imread("image.png");cv::imshow("Image", image);cv::waitKey(0);
在上面的示例中,程序將暫停執行,直到用戶按下一個鍵。然后,程序將繼續執行,關閉圖像窗口并釋放資源。
注意:
waitKey(0)
是一個阻塞函數,這意味著它會阻止程序執行,直到用戶按下一個鍵。- 如果您不希望程序暫停執行,可以使用
waitKey(1)
,它將等待 1 毫秒的按鍵輸入。如果在此期間沒有按鍵輸入,程序將繼續執行。 waitKey(0)
通常用于交互式應用程序,例如圖像查看器或視頻播放器。
展示結果:
圖片大小resize函數
resize后保存為新圖片
#include <iostream>
#include "opencv2/core.hpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/mat.hpp>
#include <opencv2/imgproc.hpp>using namespace std;
using namespace cv;int main(){Mat image;image = imread("firefox.png"); //imread()讀取圖片if(!image.empty()){imshow("image",image); //imshow展示圖片,前面為展示名,后面為圖片。waitKey(0);}// destroyAllWindows();Mat resize_image;resize(image, resize_image, Size(), 1, 0.5); //resize()改變大小 前為高度 后為寬度if(!image.empty()){imshow("resize",resize_image); waitKey(0);}imwrite("resize.png",resize_image); //imwrite(文件名,圖片)寫入文件 需要指定擴展名,否則exceptiondestroyAllWindows(); return 0;
}
圖片旋轉
getRotationMatrix2D()和warpAffine()函數
Mat rotated_image;double angle = 90; //旋轉角度Point2f center(image.cols / 2.0, image.rows / 2.0); //獲取旋轉中心Mat rotation_matix = getRotationMatrix2D(center, angle, 0.5); //getRotationMatrix2D()計算旋轉矩陣 參數:旋轉中心、旋轉角度、放大倍數warpAffine(image, rotated_image, rotation_matix, image.size()); //warpAffine旋轉圖片 參數:原圖、目標圖片、旋轉矩陣、生成圖片的大小if(!rotated_image.empty()){imshow("rotate",rotated_image); waitKey(0);}imwrite("rotate.png",rotated_image); destroyAllWindows();
Point2f 是 OpenCV 中的一個結構,用于表示二維點。它包含兩個浮點成員:
x
和 y
,分別表示點的橫坐標和縱坐標。
聲明:
struct Point2f {float x;float y;};
構造函數:
- **Point2f():**創建一個默認構造的
Point2f
,其中x
和y
都為 0。 - **Point2f(float x, float y):**創建一個
Point2f
,其中x
和y
設置為指定的值。
圖片平移
warpAffine()函數和平移矩陣
平移矩陣:
平移矩陣是一個 2x3 的仿射變換矩陣,
[ 1 0 tx ][ 0 1 ty ]
其中:
tx
是水平平移量。ty
是垂直平移量。
為tx提供正值將使圖像向右移動,而負值將使圖像向左移動。
同樣,ty值為正值時,圖像會向下平移,而ty值為負值時,圖像會向上平移。
warpAffine()本質是仿射變換。
3、這里可以看到調整了大小或者平移過后窗口大小存在一些問題,:
可以使用 OpenCV 的 namedWindow()
函數來設置 imshow()
窗口的大小。
示例:
cv::namedWindow("Image", cv::WINDOW_NORMAL); // 創建一個可調整大小的窗口cv::imshow("Image", image);// 設置窗口大小cv::resizeWindow("Image", 640, 480);
參數:
- **window_name:**窗口的名稱。
- **flag:**一個標志,指定窗口的類型。
WINDOW_NORMAL
創建一個可調整大小的窗口。
其他標志:
- **WINDOW_AUTOSIZE:**窗口大小自動調整為圖像大小。
- **WINDOW_FREERATIO:**窗口可以自由調整大小,而無需保持圖像的寬高比。
- **WINDOW_FULLSCREEN:**窗口以全屏模式顯示。
注意:
namedWindow()
函數必須在imshow()
函數之前調用。- 窗口大小只能在創建窗口后設置。
- 窗口大小設置僅適用于可調整大小的窗口(即使用
WINDOW_NORMAL
標志創建的窗口)。
圖片拼接
在 OpenCV 中,可以使用 hconcat()
和 vconcat()
函數水平和垂直拼接圖像。
水平拼接(并排):
cv::Mat image1 = cv::imread("image1.png");cv::Mat image2 = cv::imread("image2.png");cv::Mat拼接圖像;cv::hconcat(std::vector[cv::Mat](cv::Mat){image1, image2},拼接圖像);
垂直拼接(上下):
cv::Mat image1 = cv::imread("image1.png");cv::Mat image2 = cv::imread("image2.png");cv::Mat拼接圖像;cv::vconcat(std::vector[cv::Mat](cv::Mat){image1, image2},拼接圖像);
參數:
- **images:**要拼接的圖像的向量。
- **拼接圖像:**用于存儲拼接圖像的 Mat 對象。
注意:
- 要拼接的圖像必須具有相同的通道數和深度。
hconcat()
和vconcat()
函數將自動調整圖像大小以匹配。- 拼接圖像的尺寸取決于要拼接的圖像的尺寸和拼接的方向。
圖片翻轉
在 OpenCV 中,可以使用 flip()
函數水平或垂直翻轉圖像。
水平翻轉:
cv::Mat image = cv::imread("image.png");cv::Mat flipped_image;// 水平翻轉cv::flip(image, flipped_image, 1);
垂直翻轉:
cv::Mat image = cv::imread("image.png");cv::Mat flipped_image;// 垂直翻轉cv::flip(image, flipped_image, 0);
參數:
- **image:**要翻轉的圖像。
- **flipped_image:**用于存儲翻轉后圖像的 Mat 對象。
- **flipCode:**指定翻轉方向的標志。
flipCode 標志:
- **0:**垂直翻轉
- **1:**水平翻轉
- **-1:**水平和垂直翻轉
注意:
- 翻轉圖像不會修改原始圖像。
- 翻轉圖像可能會導致圖像質量下降,尤其是在翻轉包含文本或其他非對稱特征的圖像時。
高斯模糊
在 OpenCV 中,可以使用 GaussianBlur() 函數對圖像應用高斯模糊。
示例:
cv::Mat image = cv::imread("image.png");
cv::Mat blurred_image;// 高斯模糊
cv::GaussianBlur(image, blurred_image, cv::Size(5, 5), 0);
參數:
**image:**要模糊的圖像。
**blurred_image:**用于存儲模糊后圖像的 Mat 對象。
**kernel_size:**模糊核的大小。它必須是一個奇數。
**sigmaX:**高斯核在 x 方向的標準偏差。如果為 0,則從 kernel_size 計算。
注意:
高斯模糊是一種線性濾波器,它使用高斯核來平滑圖像。
高斯核是一個鐘形曲線,其中心權重最大,邊緣權重逐漸減小。
kernel_size 越大,模糊效果越強。
sigmaX 越大,模糊效果越明顯。
高斯模糊可能會導致圖像質量下降,尤其是邊緣和細節丟失。
4、完整代碼:
#include <iostream>
#include "opencv2/core.hpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/mat.hpp>
#include <opencv2/imgproc.hpp>using namespace std;
using namespace cv;int main(){Mat image;image = imread("firefox.png"); //imread()讀取圖片if(!image.empty()){namedWindow("image", cv::WINDOW_NORMAL);imshow("image",image); //imshow展示圖片,前面為展示名,后面為圖片。resizeWindow("image", 640, 480);waitKey(0);}// destroyAllWindows();Mat resize_image;resize(image, resize_image, Size(), 1, 0.5); //resize()改變大小 前為高度 后為寬度if(!resize_image.empty()){namedWindow("resize", cv::WINDOW_NORMAL);imshow("resize",resize_image); resizeWindow("resize", 640, 480);waitKey(0);}imwrite("resize.png",resize_image); //imwrite(文件名,圖片)寫入文件 需要指定擴展名,否則exception// destroyAllWindows(); Mat rotated_image;double angle = 90; //旋轉角度Point2f center(image.cols / 2.0, image.rows / 2.0); //獲取旋轉中心Mat rotation_matix = getRotationMatrix2D(center, angle, 0.5); //getRotationMatrix2D()計算旋轉矩陣 參數:旋轉中心、旋轉角度、放大倍數warpAffine(image, rotated_image, rotation_matix, image.size()); //warpAffine旋轉圖片 參數:原圖、目標圖片、旋轉矩陣、生成圖片的大小if(!rotated_image.empty()){namedWindow("rotate", cv::WINDOW_NORMAL);imshow("rotate",rotated_image); resizeWindow("rotate", 640, 480); waitKey(0);}imwrite("rotate.png",rotated_image); // destroyAllWindows(); Mat translated_image; float tx = float(image.rows) / 4; //平移距離 1/4 float ty = float(image.cols) / 4; //平移距離 1/4 float warp_values[] = { 1.0, 0.0, tx, 0.0, 1.0, ty }; //構建平移矩陣Mat translation_matrix = Mat(2, 3, CV_32F, warp_values); //構建平移矩陣warpAffine(image, translated_image, translation_matrix, image.size()); //warpAffine平移圖片if(!translated_image.empty()){namedWindow("translated", cv::WINDOW_NORMAL);imshow("translated",translated_image); resizeWindow("translated", 640, 480); waitKey(0);}imwrite("translated.png",translated_image); destroyAllWindows(); Mat flipped_image_row;Mat flipped_image_col;flip(image, flipped_image_row, 1); //水平翻轉flip(image, flipped_image_col, 0); //垂直翻轉imshow("row",flipped_image_row);imshow("col",flipped_image_col);imshow("image",image);waitKey(0);destroyAllWindows(); Mat blurred_image;GaussianBlur(image, blurred_image, cv::Size(99,99), 0);imshow("blurred_image",blurred_image);waitKey(0);destroyAllWindows(); return 0;
}
簡單四宮格:
#include <opencv2/core/mat.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>using namespace cv;int main(){Mat image = imread("firefox.png");// Mat image_45;Mat image_90;Mat image_180;Mat image_270;// double angle_45 = 45;double angle_90 = 90; double angle_180 = 180;double angle_270 = 270; Point2f center(image.cols / 2.0, image.rows / 2.0); // Mat rotation_matix_45 = getRotationMatrix2D(center, angle_45, 1.0); // warpAffine(image, image_45, rotation_matix_45, image.size()); Mat rotation_matix_90 = getRotationMatrix2D(center, angle_90, 1.0); warpAffine(image, image_90, rotation_matix_90, image.size()); Mat rotation_matix_180 = getRotationMatrix2D(center, angle_180, 1.0); warpAffine(image, image_180, rotation_matix_180, image.size()); Mat rotation_matix_270 = getRotationMatrix2D(center, angle_270, 1.0); warpAffine(image, image_270, rotation_matix_270, image.size()); Mat row_1;Mat row_2;Mat image_4x4;hconcat(std::vector<cv::Mat>{image, image_90},row_1); //橫向拼接hconcat(std::vector<cv::Mat>{image_270, image_180},row_2); //縱向拼接vconcat(std::vector<cv::Mat>{row_1, row_2},image_4x4);imshow("4x4",image_4x4);waitKey(0);destroyAllWindows();return 0;
}