遵循軟件開發者學習一項新技術的傳統流程,先來看一個 "Hello, world" 程序。
目標
在這份教程中,我們將學習如何:
- 從文件中讀取一幅圖像 (使用 cv::imread)
- 在 OpenCV 窗口中顯示一幅圖像 (使用 cv::imshow)
- 向文件中寫入一幅圖像 (使用 cv::imwrite)
C++ 版本
源代碼
可下載的代碼:點擊 這裏
代碼一覽:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
int main() {
samples::addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data");
std::string image_path = samples::findFile("starry_night.jpg");
Mat img = imread(image_path, IMREAD_REDUCED_COLOR_2);
if (img.empty()) {
std::cout << "Could not read the image: " << image_path << std::endl;
return 1;
}
imshow("Display window", img);
int k = waitKey(0); // Wait for a keystroke in the window
if (k == 's') {
imwrite("starry_night.png", img);
}
return 0;
}
源碼說明
在 OpenCV 4 中我們有多個模塊。其中的每個都關注圖像處理的一個不同領域或方法。你可能已經從這些教程本身的用戶指南的結構看到了這一點。在你使用它們中的任何一個之前,你首先需要包含頭文件,其中聲明瞭每個獨立的模塊的內容。
你幾乎總是會使用:
我們還包含了 iostream 以方便控制檯行輸出和輸入。
通過聲明 using namespace cv;
,在下面的代碼中,庫函數可以無需顯式聲明命名空間即可訪問。
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
現在讓我們分析一下主要的代碼。第一步,我們從 OpenCV 示例中讀取圖像 "starry_night.jpg" 文件。爲了做到這一點,調用 cv::imread 函數使用由第一個參數指定的文件路徑加載圖像。第二個參數是可選的,它指定了想要的圖像的格式。這個值可以是:
- IMREAD_COLOR 以 BGR 8 位格式加載圖像。這個是這裏使用的默認值。
- IMREAD_UNCHANGED 按原本的格式加載圖像(包括 alpha 通道,如果有的話)
- IMREAD_GRAYSCALE 將圖像加載爲一個灰度圖
- IMREAD_ANYDEPTH,當輸入具有對應的深度時返回 16位/32位 圖像,否則把它轉爲 8 位
- IMREAD_ANYCOLOR,以任何可能的格式讀取色彩格式
- IMREAD_LOAD_GDAL,使用 gdal 驅動加載圖像
- IMREAD_REDUCED_GRAYSCALE_2,總是把圖像轉爲單通道灰度圖,且圖像大小減爲原來的 1/2
- IMREAD_REDUCED_COLOR_2,總是把圖像轉爲 3 通道 BGR 彩色圖像,且圖像大小減爲原來的 1/2
- IMREAD_REDUCED_GRAYSCALE_4,總是把圖像轉爲單通道灰度圖,且圖像大小減爲原來的 1/4
- IMREAD_REDUCED_COLOR_4,總是把圖像轉爲 3 通道 BGR 彩色圖像,且圖像大小減爲原來的 1/4
- IMREAD_REDUCED_GRAYSCALE_8,總是把圖像轉爲單通道灰度圖,且圖像大小減爲原來的 1/8
- IMREAD_REDUCED_COLOR_8,總是把圖像轉爲 3 通道 BGR 彩色圖像,且圖像大小減爲原來的 1/8
- IMREAD_IGNORE_ORIENTATION,不要根據 EXIF 的方向標記旋轉圖像。
讀取之後,圖像數據將被保存在 cv::Mat 對象中。
samples::addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data");
std::string image_path = samples::findFile("starry_night.jpg");
Mat img = imread(image_path, IMREAD_REDUCED_COLOR_2);
OpenCV 的源碼倉庫中包含了一些測試文件,位於 opencv/samples/data
目錄下,samples::findFile()
默認在當前目錄中查找文件。但通過 samples::addSamplesDataSearchPath()
函數,可以爲示例文件的查找添加搜索目錄。對於 Eclipse 來說,默認的程序運行的當前目錄就是項目的根目錄,但可以通過執行配置中 "Arguments" 標籤下的 "Working directory:" 進行配置。
注意:OpenCV 提供了對 Windows 位圖 (bmp),可移植圖像格式 (pbm,pgm,ppm) 和 Sun raster (sr,ras) 圖像格式的支持。藉助於插件 (如果是自己編譯庫的話,需要指定使用它們,儘管如此,在我們提供的包中默認包含它們)你也可以加載像 JPEG (jpeg,jpg,jpe),JPEG 2000 (jp2 - 在 CMake 中的編碼名稱爲 Jasper),TIFF 文件 (tiff,tif) 和可移植網絡圖形 (png) 這樣的圖像格式。
imread()
函數在讀取文件並解碼之後,還可以對文件做格式轉換,具體的轉換方式由這個函數的第二個參數指定。
之後,執行了一個檢查,檢查圖像是否被正確加載。
if (img.empty()) {
std::cout << "Could not read the image: " << image_path << std::endl;
return 1;
}
然後,使用一個對 cv::imshow 函數的調用顯示圖像。第一個參數是窗口的標題,第二個參數是將要顯示的 cv::Mat 對象。
由於我們想要我們的窗口一直顯示,直到用戶按下了一個鍵(否則程序將過快結束),我們使用 cv::waitKey 函數,它只接受一個參數,表示應該等用戶輸入多長時間(以毫秒爲單位)。0 表示一直等待。返回值爲按下的鍵。
imshow("Display window", img);
int k = waitKey(0); // Wait for a keystroke in the window
最後,當按下的鍵是 "s" 鍵時,圖像被寫入文件。爲了做到這一點,以文件路徑和 cv::Mat 對象爲參數調用 cv::imwrite 函數。
if (k == 's') {
imwrite("starry_night.png", img);
}
Python 版本
源代碼
可下載的代碼:點擊 這裏
代碼一覽:
#!/use/bin/env python
import cv2 as cv
import sys
def main():
cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
img = cv.imread(cv.samples.findFile("starry_night.jpg"))
if img is None:
sys.exit("Could not read the image.")
print(img.__class__.__name__)
cv.imshow("Display window", img)
k = cv.waitKey(0)
if k == ord("s"):
cv.imwrite("starry_night.png", img)
if __name__ == "__main__":
main()
源碼說明
這裏可以看一下 C++ 代碼和 Python 代碼之間的轉換。對於 Python 程序,首先需要導入 OpenCV python 庫。執行這個操作的正確方法是,另外爲其分配名稱 cv,以下將使用這個名稱來引用 OpenCV python 庫。
import cv2 as cv
import sys
隨後,從 OpenCV 示例中讀取 "starry_night.jpg" 文件的過程與 C++ 版完全相同:藉助於 cv.samples.addSamplesDataSearchPath()
和 cv.samples.findFile()
查找文件的路徑;通過調用 cv.imread()
讀取文件。各個函數的接口和參數也與 C++ 版完全相同。Python 版的 cv.imread()
同樣支持 C++ 版的所有加載標記參數。
cv.imread()
函數返回一個 numpy 的 ndarray
對象。
cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
img = cv.imread(cv.samples.findFile("starry_night.jpg"))
OpenCV 支持加載的圖像文件格式與 C++ 完全相同。
圖像文件加載之後,執行檢查,檢查圖像是否被正確加載。
if img is None:
sys.exit("Could not read the image.")
print(img.__class__.__name__)
隨後通過 cv.imshow()
函數在窗口中顯示圖像,通過 cv.waitKey(0)
等待用戶按下按鍵:
cv.imshow("Display window", img)
k = cv.waitKey(0)
這兩個接口與 C++ 版完全相同。
最後,如果用戶按下 "s" 保存文件(與 C++ 版完全相同)。
if k == ord("s"):
cv.imwrite("starry_night.png", img)
Done.