OpenCV_002-圖像操作入門

遵循軟件開發者學習一項新技術的傳統流程,先來看一個 "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 中我們有多個模塊。其中的每個都關注圖像處理的一個不同領域或方法。你可能已經從這些教程本身的用戶指南的結構看到了這一點。在你使用它們中的任何一個之前,你首先需要包含頭文件,其中聲明瞭每個獨立的模塊的內容。

你幾乎總是會使用:

  • core 部分,因爲這裏定義了庫的基本構建塊

  • imgcodecs 模塊,提供了用於讀取和寫入的功能

  • highgui 模塊,因爲它包含了在窗口中顯示圖像的功能

我們還包含了 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() 函數返回一個 numpyndarray 對象。

    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.

參考 Getting Started with Images

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章