[OpenCV]OpenCV常用語法函數與坑點


1. 加載圖像(cv::imread)

imread()功能是加載圖像文件成為一個Mat對象,如果讀取文件失敗,則會返回一個空矩陣,即 Mat::data 的值是 NULL。imread()函數的聲明如下:

Mat imread(const string& filename, int flags=1)

其中第一個參數是表示圖像文件名稱;第二個參數表示加載的圖像是什么類型,支持常見的三個參數值:

  • IMREAD_UNCHANGED(<0)表示加載原圖,不做任何改變
  • IMREAD_GRAYSCALE(0)表示把原圖作為灰度圖像加載進來
  • IMREAD_COLOR(>0)表示把原圖作為RGB圖像加載進來

imread()函數支持多種文件格式,且該函數是根據圖像文件的內容來確定文件格式,而不是根據文件的擴展名來確定。所只是的文件格式如下:

  • Windows 位圖文件 - BMP, DIB;
  • JPEG 文件 - JPEG, JPG, JPE;
  • 便攜式網絡圖片 - PNG;
  • 便攜式圖像格式 - PBM,PGM,PPM;
  • Sun rasters - SR,RAS;
  • TIFF 文件 - TIFF,TIF;
  • OpenEXR HDR 圖片 - EXR;
  • JPEG 2000 圖片- jp2。

你所安裝的 OpenCV 並不一定能支持上述所有格式,文件格式的支持需要特定的庫,只有在編譯 OpenCV 添加了相應的文件格式庫,才可支持其格式。

2. 顯示圖像(cv::nameWindows與cv::imshow)

  • namewindows功能是創建一個OpenCV窗口,它是由OpenCV自動創建與釋放,你無須手動銷毀它。
  • 常見用法 nameWindows("windowTitle", WINDOW_AUTOSIZE)
  • WINDOW_AUTOSIZE 會自動根據圖像大小,顯示窗口大小,不能認為改變窗口大小
  • WINDOW_NORMAL 跟QT集成的時候會使用,允許修改窗口大小
  • imshow 根據窗口名稱顯示圖像到窗口上去,第一個參數是窗口名稱,第二個參數是Mat對象

3. 修改圖像(cv::cvtColor)

cvtColor的功能是把圖像從一個色彩空間轉換到另一個色彩空間。有三個參數如下:
第一個參數表示原圖像
第二個參數表示色彩空間轉換之后的圖像
第三個參數表示轉換方式,如:CV_BGR2GRAY、CV_BGR2HSV等
代碼如下:

cvtColor(src, outputImage, CV_BGR2GRAY);

4. 保存圖像(cv::imwrite)

將圖像寫入文件,可使用 imwrite()函數,該函數的聲明如下:

bool imwrite( const string& filename, InputArray img, const vector<int>& params=vector<int>());

文件的格式由 filename 參數指定的文件擴展名確定。推薦使用 PNG 文件格式。BMP 格式是無損格式,但是一般不進行壓縮,文件尺寸非常大;JPEG 格式的文件嬌小,但是 JPEG 是有損壓縮,會丟失一些信息。PNG 是無損壓縮格式,推薦使用。
imwrite()函數的第三個參數 params 可以指定文件格式的一些細節信息。這個參數里面的數值是跟文件格式相關的:

  • JPEG:表示圖像的質量,取值范圍從 0 到 100。數值越大表示圖像質量越高,當然文件也越大。默認值是 95。
  • PNG:表示壓縮級別,取值范圍是從 0 到 9。數值越大表示文件越小,但是壓縮花費的時間也越長。默認值是 3。
  • PPM,PGM 或 PBM:表示文件是以二進制還是純文本方式存儲,取值為0 或 1。如果取值為 1,則表示以二進制方式存儲。默認值是 1。

並不是所有的 Mat 對象都可以存為圖像文件,目前支持的格式只有 8U 類型的單通道和 3 通道(顏色順序為 BGR)矩陣;如果需要要保存 16U 格式圖像,只能使用 PNG、JPEG 2000 和 TIFF 格式。如果希望將其他格式的矩陣保存為圖像文件,可以先用 Mat::convertTo()函數或者 cvtColor()函數將矩陣轉為可以保存的格式。
注意:在保存文件時,如果文件已經存在,imwrite()函數不會進行 醒,將直接覆蓋掉以前的文件。

5. 讀視頻

VideoCapture 既可以從視頻文件讀取圖像,也可以從攝像頭讀取圖像。可以使用該類的構造函數打開視頻文件或者攝像頭。如果 VideoCapture 對象已經創建,也可以使用 VideoCapture::open()打開,VideoCapture::open()函數會自動調用VideoCapture::release()函數,先釋放已經打開的視頻,然后再打開新視頻。

VideoCapture cap(0);  //打開第一個攝像頭
VideoCapture cap("filename.avi");  //打開視頻文件

如果要讀一幀,可以使用 VideoCapture::read()函數。VideoCapture 類重載了>>操作符,實現了讀視頻幀的功能。

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
    VideoCapture cap(0);    //打開第一個攝像頭
    if(!cap.isOpened()) {   //檢查是否成功打開
        cerr << "Can not open a camera or file." << endl;
        return -1;
    }
    Mat edges;
    namedWindow("edges",1); //創建窗口
    while(1) {
        Mat frame;
        cap >> frame;  //從 cap 中讀一幀,存到 frame
        if(frame.empty()){  //如果未讀到圖像
            break;
        }
        cvtColor(frame, edges, CV_BGR2GRAY);  //將讀到的圖像轉為灰度圖
        Canny(edges, edges, 50, 150, 3);  //進行邊緣 取操作
        imshow("edges", edges);     //顯示結果
        if(waitKey(30) >= 0) {   //等待 30 秒,如果按鍵則推出循環
            break;
        }
    }
    //退出時會自動釋放 cap 中占用資源
    return 0;
}

6. 寫視頻

使用 OpenCV 創建視頻也非常簡單,與讀視頻不同的是,你需要在創建視頻時設置一系列參數,包括:文件名,編解碼器,幀率,寬度和高度等。編解碼器使用四個字符表示,可以是 CV_FOURCC('M','J','P','G')、CV_FOURCC('X','V','I','D')及CV_FOURCC('D','I','V','X')等。如果使用某種編解碼器無法創建視頻文件,請嘗試其他的編解碼器。
將圖像寫入視頻可以使用 VideoWriter::write()函數,VideoWriter 類中也重載了<<操作符,使用起來非常方便。另外需要注意:待寫入的圖像尺寸必須與創建視頻時指定的尺寸一致。

#include <stdio.h>
#include <iostream>
#include "opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
    //定義視頻的寬度和高度
    Size s(320, 240);
    //創建 writer,並指定 FOURCC 及 FPS 等參數
    VideoWriter writer = VideoWriter("/Users/Longxia/Downloads/myvideo.avi", CV_FOURCC('M','J','P','G'), 25, s);
    //檢查是否成功創建
    if(!writer.isOpened()) {
        cerr << "Can not create video file.\n" << endl;
        return -1;
    }
    //視頻幀
    Mat frame(s, CV_8UC3);
    for(int i = 0; i < 100; i++)
    {
        //將圖像置為黑色
        frame = Scalar::all(0);
        //將整數 i 轉為 i 字符串類型
        char text[128];
        snprintf(text, sizeof(text), "%d", i);
        //將數字繪到畫面上
        putText(frame, text, Point(s.width/3, s.height/3),
                FONT_HERSHEY_SCRIPT_SIMPLEX, 3, Scalar(0,0,255), 3, 8);
        //將圖像寫入視頻
        writer << frame;
    }
    //退出程序時會自動關閉視頻文件
    return 0;
}

7. imread()RGB的轉換

方法轉自:知乎
我們在使用OpenCV時,經常需要將處理過的圖片展示出來,由於OpenCV中顯示圖片的函數cv2.imshow()功能往往不能滿足我們的需求,所以經常用Matplotlib顯示圖像,方便結果圖片的放大、保存等操作。

但是,OpenCV和Matplotlib中圖片的像素排列方式略有不同。OpenCV中圖片像素按照BGR(HWC)方式排列,而Matpoltlib中圖片按照RGB方式排序,這樣使用OpenCV讀入的圖片經過Matplotlib展示時,就會出現反相問題。

這里使用OpenCV的logo作為實驗對象:

img = cv.imread("logo.png")#使用OpenCV讀入圖像
plt.subplot(111);plt.imshow(img);plt.title("Original")#使用matplotliob展示圖片

與原圖相比,上圖的紅色部分與藍色部分交換了位置,意思是圖片中紅色像素和藍色像素排列位置做了交換,印證了讀入的BGR格式經過Matplotlib展示后變成了RGB格式。而且綠色的部分也有明顯的色差。

要想正確的顯示圖片,必須先把讀入的BGR圖片中的B通道和R通道交換位置。這里有兩種可行的方法可以實現BGR 2 RGB操作。

方法1:先拆分通道B、G、R,再合並通道R、G、B。

b,g,r = cv.split(img)#拆分通道
img_1 = cv.merge([r,g,b])#合並通道

在拆分通道時,除了使用OpenCV的split()方法,還可以用Numpy的索引:

b = image[:,:,0]#得到藍色通道
g = image[:,:,1]#得到綠色通道
r = image[:,:,2]#得到紅色通道

在Matplotlib中顯示:

plt.subplot(111);plt.imshow(img);plt.title("Original")
plt.subplot(122);plt.imshow(img_1);plt.title("Display_RGB")


在第二幅圖片中,可以看到展示結果與原圖一致。

方法2:直接使用Numpy索引

我們都知道Numpy在計算這種大型矩陣時,索引的效率很高,所以下面的方法簡單高效,及其推薦使用。

img_2 = img[:,:,::-1]
plt.subplot(131);plt.imshow(img);plt.title("Original")
plt.subplot(132);plt.imshow(img_1);plt.title("Display_RGB")
plt.subplot(133);plt.imshow(img_2);plt.title("Display_RGB")
plt.show()

也可以

img = cv2.imread(fengmian)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # cv2默認為bgr順序

8. 圖像的膨脹(dilate)和腐蝕(erode)

詳細說明
需要注意,腐蝕和膨脹是對白色部分(高亮部分)而言的,不是黑色部分。膨脹就是圖像中的高亮部分進行膨脹,“領域擴張”,效果圖擁有比原圖更大的高亮區域。腐蝕就是原圖中的高亮部分被腐蝕,“領域被蠶食”,效果圖擁有比原圖更小的高亮區域。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM