加載和顯示圖像
從文件和顯示加載圖像
在本節中,我將向您展示如何使用 OpenCV 庫函數從文件加載圖像并在窗口中顯示圖像。
首先,打開C++ IDE并創建一個新項目。然后,必須為 OpenCV 配置新項目。
#include <iostream> #include <opencv2\opencv.hpp> using namespace cv; using namespace std; int main() {// 讀取一個圖像文件并賦給image變量Mat image = imread("lena.png");// 判斷讀取圖像是否為空if (image.empty()) {cout << "沒有發現讀取圖像文件";// 輸入人員字符cin.get();return -1;}// 定義一個窗體的名稱String winName = "lena 圖像";// 創建一個窗體用于顯示圖像namedWindow(winName);// 把圖像顯示到創建窗體上面imshow(winName, image);// 等待輸入字符并關閉窗口waitKey(0);destroyWindow(winName); }
將上述代碼片段復制并粘貼到 IDE 中并運行它。請注意,您必須將代碼中的圖像路徑替換為計算機中圖像的有效位置。然后,您應該會看到如下圖所示的輸出。
解釋
讓我們逐行瀏覽上面的OpenCV程序。
//#include "stdafx.h"
這是由Visual Studio IDE生成的預編譯頭文件。如果您使用的是Visual Studio,請取消注釋此行以避免編譯錯誤。
opencv2/opencv.hpp?頭文件本身將包含 OpenCV 庫中所有其他必要的頭文件。您必須僅包含此頭文件才能編譯 OpenCV 代碼。
還應包含 iostream?頭文件,因為我們在程序中使用 COUT 和 CIN 將錯誤消息打印到控制臺。
所有 OpenCV 函數、類和數據結構都在?cv?命名空間內聲明。因此,我們必須在程序頂部添加“**使用命名空間 cv”**行。否則,我們必須在每個 OpenCV 函數、類和數據結構之前附加 ’cv::“說明符。(例如 - cv::Mat, cv::imread() 等)。
我們還必須使用 std 命名空間,因為 cout、endl 和 cin 函數位于?std?命名空間內。
該函數從文件“*C:\Users\Desktop\lena.png*”加載圖像,并將其作為 Mat 對象返回。
在你的代碼中,你必須將“*C:\Users\Desktop\lena.png*”替換為計算機中圖像文件的有效位置。
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; Mat image = imread("C:\Users\Desktop\lena.png");
Mat imread(const String&filename, int flags = IMREAD_COLOR)
此函數從指定文件加載圖像,并作為 Mat 對象返回。如果函數無法讀取文件,它將返回一個空的 Mat 對象。
- 文件名?- 您必須提供圖像文件的相對或絕對路徑。如果要提供相對路徑,則它應該是相對于cpp文件的。始終支持 JPEG、JPG、BMP、PNG、TIFF 和 TIF 圖像文件類型。支持其他映像文件類型,具體取決于您的平臺和安裝的編解碼器。
- flags?- 標志參數有幾個可能的值。在上面的程序中,我沒有向此參數傳遞任何值,以便使用默認的IMREAD_COLOR參數。
- IMREAD_UNCHANGED - 圖像將按原樣加載。如果要在輸入圖像中獲取 alpha 通道(如果可用),則必須使用此標志。
- IMREAD_GRAYSCALE - 圖像將作為灰度圖像加載(即 - 單通道圖像,黑白圖像)
- IMREAD_COLOR - 圖像將作為BGR圖像加載(即 - 3通道圖像,彩色圖像)
// Check for failureif (image.empty()) {cout << "Could not open or find the image" << endl;cin.get(); //wait for any key pressreturn -1;}
如果?imread()?函數無法加載圖像,則返回的 Mat 對象將為空。如果 Mat 對象為空,**則 image.empty()** 函數將返回 true。在這種情況下,我們的程序會將錯誤消息打印到控制臺并等待任何按鍵。當用戶按鍵盤中的任意鍵時,程序將退出,返回 -1。最好檢查圖像是否為空并退出程序。否則,您的程序將在嘗試執行?imshow()?函數時崩潰。
此函數創建一個名為“*lena*”的窗口。窗口的名稱稍后將在此代碼中用于標識窗口。
namedWindow(windowName); // Create a window
void namedWindow(const String&winname, int flags = WINDOW_AUTOSIZE)
此函數創建一個可用于放置圖像和跟蹤欄的窗口。如果已存在具有給定名稱的窗口,則此函數不執行任何操作。
- winname?- 窗口的名稱。該名稱將顯示在新創建的窗口的標題欄中。此名稱也是此窗口的標識符,它將在以后的 OpenCV 函數調用中用于標識窗口。
- 標志?- 確定窗口的大小。在上面的程序中,我沒有向此參數傳遞任何值,因此將使用默認WINDOW_AUTOSIZE參數。
- WINDOW_AUTOSIZE - 用戶無法調整窗口大小。圖像將以其原始大小顯示。
- WINDOW_NORMAL-用戶可以調整窗口大小。
imshow(windowName, image); // Show our image inside the created window.
此函數在上一步中創建的窗口中顯示圖像。
void imshow(const String&winname, InputArray mat)
此函數在 winname 指定的窗口中顯示圖像。如果使用WINDOW_AUTOSIZE標志創建窗口,則圖像將以其原始大小顯示。否則,圖像可能會縮放到窗口的大小。如果尚未通過調用 namedWindow() 函數創建窗口,則此函數將創建一個帶有 WINDOW_AUTOSIZE 標志的窗口。此函數調用后應遵循 waitKey(int) 函數調用,以便提供足夠的時間在指定的持續時間(以毫秒為單位)內在窗口中繪制和顯示圖像。如果不調用waitKey(int)函數,圖像將不會顯示在窗口中。
- winname?- 由 namedWindow() 函數創建的窗口的名稱。
- mat?- 保存圖像的墊子對象
waitKey(0); // Wait for any keystroke in the window
waitKey(0) 函數永遠等待按鍵。當按下任何鍵時,此函數返回鍵的 ASCII 值,您的程序將繼續。
如果將正值傳遞給 waitKey() 函數,則它僅等待按鍵的持續時間,由傳遞的值(以毫秒為單位)指定。如果在此期間按下任何鍵,此函數將返回該鍵的 ASCII 值,您的程序將繼續。如果在此期間沒有按下任何鍵,它將返回 -1,程序將繼續。
僅當程序至少打開了一個活動的 HIGHGUI 窗口時,此功能才有效。
此函數關閉以名稱 windowName 標識的打開窗口,并取消分配任何關聯的內存使用量。此功能對于上述程序不是必需的,因為當程序退出時,操作系統通常會關閉所有打開的窗口并取消分配任何關聯的內存使用量。
destroyWindow(windowName); //destroy the created window
總結
在上面的部分中,您已經了解到,
- 如何從文件加載圖像
- 如何處理圖像加載失敗時的錯誤情況
- 如何創建窗口并顯示圖像
- 如何在不退出程序的情況下等待,直到用戶按下某個鍵
- 如何銷毀已創建的窗口
創建空白圖像和顯示
以下程序也與以前的程序非常相似。唯一的區別是該程序創建一個空白圖像,而不是從文件加載現有圖像。
將上述簡單代碼片段復制并粘貼到 IDE 中并運行它。然后,您應該會看到如下圖所示的輸出。
#include <iostream> #include <opencv2\opencv.hpp> using namespace cv; using namespace std; int main() {Mat image(200, 300, CV_8UC3, Scalar(200, 31, 120));// 定義一個窗體的名稱String winName = "blank Image Window";// 創建一個窗體用于顯示圖像namedWindow(winName);// 把圖像顯示到創建窗體上面imshow(winName, image);// 等待輸入字符并關閉窗口waitKey(0);destroyWindow(winName); }
本節中新增的 OpenCV 函數說明
Mat image(600, 800, CV_8UC3, Scalar(100, 250, 30));
這是 Mat 類中可用的眾多構造函數之一。它創建一個高 600 像素、寬 800 像素的圖像。為圖像中的每個像素分配 24 位。24 位將由三個無符號 8 位整數組成,分別代表藍色、綠色和紅色平面。三個整數的值應介于 0 到 255 之間。
然后,此構造函數使用 3 個無符號整數(100、250、30)初始化創建圖像的每個像素。因此,它初始化藍色通道為 100,綠色通道初始化為 250,紅色通道初始化為 30。由于綠色通道的值明顯大于其他通道的值,因此輸出圖像為綠色。您可以嘗試這三個值的不同組合并查看輸出圖像。
Mat:**:Mat(int rows, int cols, int type, const Scalar& s)**
此構造函數將創建一個具有指定行數和列數的 Mat 對象,并使用 s 中給出的值初始化每個元素。
row?- 2D 數組中的行數(即 - 圖像的高度(以像素為單位)
cols?- 2D 數組中的列數(即 - 圖像的寬度(以像素為單位)
type?- 二維數組的數據類型,指定每個通道中每個元素的深度和數據類型以及通道數。(當然,如果通道數大于 2,則 1D 數組變為 2D 數組)。
- CV_8UC1
- CV_8UC2
- CV_8UC3
- CV_8UC4
- CV_8UC(n)
- CV_8SC1
- CV_8SC2
- CV_8SC3
- CV_8SC4
- CV_8SC(n)
- CV_16UC1
- CV_16UC2
- CV_16UC3
- CV_16UC4
- CV_16UC(n)
- CV_16SC1
- CV_16SC2
- CV_16SC3
- CV_16SC4
- CV_16SC(n)
- CV_32SC1
- CV_32SC2
- CV_32SC3
- CV_32SC4
- CV_32SC(n)
- CV_32FC1
- CV_32FC2
- CV_32FC3
- CV_32FC4
- CV_32FC(n)
- CV_64FC1
- CV_64FC2
- CV_64FC3
- CV_64FC4
- CV_64FC(n)
- s - 使用?s?為每個通道給出的值初始化每個數組元素(像素)。