OpenCV 笔记(02)— 图像显示、保存、腐蚀、模糊、canny 边缘检测(imread、imshow、namedWindow、imwrite)
OpenCV 提供兩種用戶界面選項:
- 基于原生用戶界面的基本界面,適用于
Mac OS X的cocoa或carbon,以及適用于Linux或Windows用戶界面的GTK,這些界面在編譯OpenCV時被默認選擇。 - 基于
Qt庫的略微更高級的界面,這是跨平臺的界面。必須在編譯OpenCV之前,在CMake中手動啟用Qt選項。
1. 圖像顯示
在 OpenCV 中,圖像顯示過程非常簡單,只需用 imread 函數載入到新版本的圖像存儲數據結構 Mat 類中,然后用 imshow 函數顯示即可。
#include <iostream>
#include "opencv2/opencv.hpp"using namespace cv;
// 使用 cv 命名空間,否則后面需要使用 cv::Mat, cv::imread 等帶cv前綴int main()
{Mat image;image = imread("./image/dog.jpg"); // 載入圖像if (image.empty()) // 或者 if(!image.data) 判斷圖片是否加載成功{std::cout << "image not exist";return -1;}namedWindow("demo 圖片");imshow("demo 圖片", image); // 顯示圖像imwrite("save.jpg", image);waitKey(0); // 等待任意按鍵按下,退出圖片顯示return 0;
}
顯示結果
代碼分析:
1.1 Mat 類
Mat 類是用于保存圖像以及其他矩陣數據的數據結構, 默認情況下其尺寸為 0。我們也可以指定其初始尺寸, 比如定義一個 Mat 類對象, 就要寫 cv::Mat pic( 320, 640, cv::Scalar(100)) 。
1.2 imread 載入圖像函數
首先來看 imread 函數, 其用于讀取文件中的圖片到 OpenCV 中。可以在 OpenCV 官方文檔中查到它的原型, 如下。
Mat imread( const String& filename, int flags = IMREAD_COLOR )
- 第一個參數,
const string&類型的filename, 填我們需要載入的圖片路徑名。 - 第二個參數,
int類型的flags, 為載入標識,它指定一個加載圖像的顏色類型。默認值為 1 這個參數可以在OpenCV中標識圖像格式的枚舉體中取值,詳情如下:
enum ImreadModes {IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion).IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image.IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format.IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image.IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2.IMREAD_REDUCED_COLOR_2 = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.};
所以有時候這個參數在調用時可以忽略,就表示載入三通道的彩色圖像。
因為 flags 是 int 型的變量,若我們不在這個枚舉體中取固定的值, 可以這樣進行:
flags>0返回一個3 通道的彩色圖像;flags=0返回灰度圖像;flags<0返回包含 Alpha 通道的加載圖像;
注意:若以彩色模式載入圖像,解碼后的圖像會以 BGR 的通道順序進行存儲,即藍、綠、紅的順序,而不是通常的 RGB 的順序。
1.3 imshow 顯示圖像函數
imshow() 函數用于在指定的窗口中顯示一幅圖像, 函數原型如下。
void imshow(const String& winname, InputArray mat);
- 第一個參數:
const string&類型的winname,填需要顯示的窗口標識名稱。 - 第二個參數:
InputArray類型的mat, 填需要顯示的圖像。
imshow 函數用于在指定的窗口中顯示圖像。如果窗口是用 CV_WINDOW_AUTOSIZE (默認值)標志創建的,那么顯示圖像原始大小。否則,將圖像進行縮放以適合窗口。
而 imshow 函數縮放圖像,取決于圖像的深度,具體如下。
- 如果載入的圖像是 8 位無符號類型(8-bit unsigned),就顯示圖像本來的樣子。
- 如果圖像是 16 位無符號類型(16-bit unsigned)或 32 位整型( 32-bit integer),便用像素值除以 256。也就是說,值的范圍是[0,255 x 256]映射到[0,255]。
- 如果圖像是 32 位浮點型(32-bit floating-point), 像素值便要乘以 255。也就是說, 該值的范圍是[0,1]映射到[0,255]。
1.4 namedWindow 創建窗口函數
namedWindow 函數用于創建一個窗口。若是簡單地進行圖片顯示,可以略去namedWindow 函數的調用,即先調用 imread 讀入圖片,然后用 imshow 直接指定出窗口名進行顯示即可。
但需要在顯示窗口之前就用到窗口名時, 比如我們后面會馬上講到滑動條的使用, 要指定滑動條依附到某個窗口上, 就需要 namedWindow 函數先創建出窗口, 顯式地規定窗口名稱了。
namedWindow 的函數原型如下:
void namedWindow(const String& winname, int flags = WINDOW_AUTOSIZE);
- 第一個參數,
const string&型的name, 填寫被用作窗口的標識符的窗口名稱; - 第二個參數,
int類型的flags, 窗口的標識, 可以填如下幾種值;
enum WindowFlags {WINDOW_NORMAL = 0x00000000, //!< the user can resize the window (no constraint) / also use to switch a fullscreen window to a normal size.WINDOW_AUTOSIZE = 0x00000001, //!< the user cannot resize the window, the size is constrainted by the image displayed.WINDOW_OPENGL = 0x00001000, //!< window with opengl support.WINDOW_FULLSCREEN = 1, //!< change the window to fullscreen.WINDOW_FREERATIO = 0x00000100, //!< the image expends as much as it can (no ratio constraint).WINDOW_KEEPRATIO = 0x00000000, //!< the ratio of the image is respected.WINDOW_GUI_EXPANDED=0x00000000, //!< status bar and tool barWINDOW_GUI_NORMAL = 0x00000010, //!< old fashious way};
namedWindow 函數的作用是通過指定的名字, 創建一個可以作為圖像和進度條的容器窗口。如果具有相同名稱的窗口已經存在, 則函數不做任何事情。
我們可以調用 destroyWindow() 或者 destroyAllWindows() 函數來關閉窗口, 并取消之前分配的與窗口相關的所有內存空間。
但是事實上, 對于代碼量不大的簡單程序來說, 我們完全沒有必要手動調用上述的 destroyWindow() 或者 destroyAllWindows() 函數, 因為在退出時, 所有的資源和應用程序的窗口會被操作系統自動關閉。
1.5 imwrite 保存圖像函數
在 OpenCV 中, 輸出圖像到文件一般采用 imwrite 函數, 它的聲明如下。
bool imwrite( const String& filename, InputArray img,const std::vector<int>& params = std::vector<int>());
- 第一個參數,
const string&類型的filename,填需要寫入的文件名。注意要帶上后綴,如“save.jpg ”。 - 第二個參數,
InputArray類型的img, 一般填一個Mat類型的圖像數據。 - 第三個參數,
const vector<int>&類型的params, 表示為特定格式保存的參數編碼。它有默認值vector<int>(), 所以一般情況下不需要填寫。而如果要填寫的話,有下面這些需要了解的地方:
- 對于
JPEG格式的圖片, 這個參數表示從 0 到100 的圖片質量 (CV _IMWRITE_JPEG_ QUALITY), 默認值是 95。 - 對于
PNG格式的圖片, 這個參數表示壓縮級別(CV_IMWRITE_PNG_COMPRESSION) 從 0 到 9。較高的值意味著更小的尺寸和更長的壓縮時間,默認值是 3。 - 對于
PPM、PGM、或PBM格式的圖片, 這個參數表示一個二進制格式標志(CV _IMWRITE_PXM_ BINARY),取值為 0 或1 , 默認值是 1 。
注意: imwrite 函數用于將圖像保存到指定的文件。圖像格式是基于文件擴展名的,可保存的擴展名和 imread 中可以讀取的圖像擴展名一致。
2. 圖像腐蝕
再來看如何用 OpenCV 實現最基本的形態學運算之腐蝕, 即用圖像中的暗色部分“腐蝕”掉圖像中的高亮部分。
#include <iostream>
#include "opencv2/highgui.hpp" // OpenCV highgui 模塊頭文件
#include "opencv2/imgproc.hpp" // OpenCV 圖像處理頭文件using namespace cv;int main()
{Mat src = imread("./image/dog.jpg"); // 載入圖像if (src.empty()) // 或者 if(!image.data) 判斷圖片是否加載成功{std::cout << "image not exist";return -1;}imshow("原始圖片", src); // 顯示圖像// 進行腐蝕操作Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));Mat dst;erode(src, dst, element);imshow("腐蝕圖片", dst);// waitKey(30)等待30毫秒,以此檢查用戶是否使用任何鍵停止應用程序的執行。waitKey(0); // 等待任意按鍵按下,退出圖片顯示,return 0;
}
程序首先依然是載入和顯示一幅圖像,然后定義一個 Mat 類型的變量來獲得 getStructuringElement 函數的返回值,而 getStructuringElement 函數的返回值為指定形狀和尺寸的結構元素(內核矩陣)。參數準備完畢,接著便可以調用 erode 函數進行圖像腐蝕操作,最后調用 imshow 函數進行顯示,用 waitKey 函數等待按鍵按下,以便能讓窗口一直顯示。
顯示結果:
3. 圖像模糊
接著讓我們看看用 OpenCV 對圖像進行均值濾波操作,模糊一幅圖像的代碼如何書寫。主要使用進行均值濾波操作的 blur 函數,代碼如下:
#include <iostream>
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"using namespace cv;int main()
{Mat src = imread("./image/dog.jpg"); // 載入圖像if (src.empty()) // 或者 if(!image.data) 判斷圖片是否加載成功{std::cout << "image not exist";return -1;}imshow("原始圖片", src); // 顯示圖像// 進行均值濾波模糊操作Mat dst;blur(src, dst, Size(15, 15));imshow("模糊圖片", dst);waitKey(0); // 等待任意按鍵按下,退出圖片顯示return 0;
}
顯示結果
4. 邊緣檢測
接著我們來看看如何用 OpenCV 進行 canny 邊緣檢測。載入圖像,并將其轉成灰度圖,再用 blur 函數進行圖像模糊以降噪,然后用 canny 函數進行邊緣檢測,最后進行顯示。
#include <iostream>
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"using namespace cv;int main()
{Mat src = imread("./image/dog.jpg"); // 載入圖像if (src.empty()) // 或者 if(!image.data) 判斷圖片是否加載成功{std::cout << "image not exist";return -1;}imshow("原始圖片", src); // 顯示圖像Mat dst, edge, gray;// 創建與原圖片同類型和大小的矩陣( dst )dst.create(src.size(), src.type());// 將原圖像轉換為灰度圖像 OpenCV2 版本// cvtColor(src, gray, CV_BGR2GRAY)// OpenCV3 或者 OpenCV4 版本cvtColor(src, gray, COLOR_BGR2GRAY);// 先使用5 x 5 內核來降噪blur(gray, edge, Size(5, 5));// 運行Canny 算子Canny(edge, edge, 1, 3, 3);imshow("Canny 邊緣檢測", edge);waitKey(0); // 等待任意按鍵按下,退出圖片顯示return 0;
}
顯示結果:
5. 其它示例
#include <iostream>
#include <string>
#include <sstream>
using namespace std;// OpenCV includes
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;const int CV_GUI_NORMAL= 0x10;int main( int argc, const char** argv )
{// Read imagesMat lena= imread("../lena.jpg");Mat photo= imread("../photo.jpg");// Create windowsnamedWindow("Lena", WINDOW_NORMAL);// Checking if Lena image has been loadedif (!lena.data) {cout << "Lena image missing!" << endl;return -1;}namedWindow("Photo", WINDOW_AUTOSIZE);if (!photo.data) {cout << "Lena image missing!" << endl;return -1;}// Move window// moveWindow函數將窗口移動到桌面的任何區域moveWindow("Lena", 10, 10);moveWindow("Photo", 520, 10);// show imagesimshow("Lena", lena);imshow("Photo", photo); // Resize window, only non autosize// resizeWindow函數將Lena窗口的大小調整為512像素,該函數有三個參// 數:window name、width和height。resizeWindow("Lena", 512, 512); // wait for any key presswaitKey(0);// Destroy the windowsdestroyWindow("Lena");destroyWindow("Photo");// Create 10 windowsfor(int i =0; i< 10; i++){ostringstream ss;ss << "Photo " << i;namedWindow(ss.str());moveWindow(ss.str(), 20*i, 20*i);imshow(ss.str(), photo);}waitKey(0);// Destroy all windowsdestroyAllWindows();return 0;
}
以上都是原生 OpenCV 的一些基本圖像處理過濾器,但也有新的開源替代品,它們能夠添加更多功能,比如 cvui (https://dovyski.github.io/cvui/) 或 OpenCVGUI (https://damiles.github.io/OpenCVGUI/)。
總結
以上是生活随笔為你收集整理的OpenCV 笔记(02)— 图像显示、保存、腐蚀、模糊、canny 边缘检测(imread、imshow、namedWindow、imwrite)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022-2028年中国防水橡胶布行业市
- 下一篇: 2022-2028年中国热熔胶产业竞争现