1. 程式人生 > >ATP的OpenCV筆記(一):對圖片的基本操作

ATP的OpenCV筆記(一):對圖片的基本操作

寫在前面

ATP成功進化成棄坑大師。。

主要是正式開課以後自己亂搞著玩兒的東西就不想管它了QAQ。。。Python學會了以後也懶得往部落格裡寫了。。

這次打算開的坑emmm是上課講的內容?由於要記住的函式用法太多ATP懶得每次遇到都百度所以相當於在blog裡面記一下嗯就是這樣。

OpenCV是個可以用來做影象處理的庫?在C++和python裡面都有對應的版本,不過C++的配置環境好麻煩。。python的還不大會。。而且上課要用的是C++的所以暫且先記一下C++的?

OpenCV具體怎麼安裝怎麼配置什麼的。。。ATP因為是直接按照助教老師發的文件照葫蘆畫瓢自己也不是很明白所以就不寫了。。。

這次ATP用來寫C++的東西是Visual Studio。好複雜啊這玩意兒。。。難用死了QAQ

嗯前言就先說這麼些叭。

進入正題

要在VS里弄一個用OpenCV處理影象的程式出來首先得在OpenCV的工作目錄下新建一個專案然後把這個專案配置好,包括設定依賴然後新建個原始檔。

仍然先貼程式碼。

#include "cv.h"
#include "highgui.h"
#include <cstdio>
using namespace std;
IplImage *srcimage, *newimage;
int main()
{
    if ((srcimage = cvLoadImage("03.jpg", 0)) == 0) {
        printf("??!!\n");
    }
    cvNamedWindow("source", 1);
    cvShowImage("source", srcimage);
    cvSaveImage("gray.jpg", srcimage);

    cvWaitKey(0);

    cvDestroyWindow("source");
    cvReleaseImage(&srcimage);

    return 0;
}

這個程式實際上就是讀入了一個圖片然後把這個圖片轉換成黑白的然後存下來並且在另一個窗口裡顯示出來。

其實ATP覺得這函式名字這麼長就算不知道它是啥原理大概翻譯一下也知道它在幹啥了。

關於IplImage

部落格園這個字型是什麼鬼啊喂為什麼小寫L和大寫I長得一模一樣。。。還好程式碼塊裡面還能區分出來它是IPLIMAGE(全大寫版本)

這個東西是OpenCV裡面用來接收影象的資料型別。它有一大堆屬性,比如是灰的還是彩的呀,影象size是多少呀之類的。不過這段程式碼裡一個也沒用到。用到了再說叭。

為啥要新建一個這個型別的指標而不新建一個這個型別的變數,是因為函式們返回的都是指標型別。。。ATP也沒啥辦法

比如下面那個載入圖片的函式——

關於cvLoadImage

這個函式返回一個指標指向一個IplImage型別的變數,裡面存的就是載入進來的圖片。

同時它還可以像上面那麼用——如果圖片載入失敗,比如你的路徑指定錯了之類的話,賦值語句的返回值就是0。

函式要帶兩個引數,第一個字串是圖片的路徑。它一開始預設是指到原始檔放置的那個目錄的,也就是像上面那種指定路徑的方式需要把圖片和main.cpp放一起才行。

還可以在原始檔所在的目錄下新建一個資料夾然後在路徑字串裡面加上資料夾路徑。

比如這樣:

srcimage = cvLoadImage("image\\03.jpg", 0);

第二個引數是說明這個圖片是灰的還是彩的。0代表強制轉化為灰度圖,1代表彩色圖,-1代表按照原圖來。

這裡的灰色和彩色不僅僅是指它“看起來”怎麼樣。根本區別在於它要用單通道存還是三通道存。也就是說如果是灰度圖,它的每個畫素只需要一個數字描述,就是它的灰度;如果是彩色圖,每個畫素就需要三個數字描述,就是RGB三個資料。

就比如說如果把一個灰色的圖片載入成“彩色圖”的形式,計算機並不會自動給它上色(要是可以的話就上天了),它看起來還是灰色的,但是它在內部的每個畫素已經需要三個數字了。

反之如果載入成“灰色圖”的形式,它看起來也還是灰色的,但它內部每個畫素只需要一個數字來描述。

關於cvNamedWindow和cvShowImage

cvNamedWindow可以建立一個視窗。第一個引數就是視窗名字,第二個引數是個整數,可以不寫,預設值就是1。這個引數ATP也不知道有啥作用。。。。好像跟視窗大小的調整有關?

而cvShowImage就用來在這個窗口裡顯示要顯示的圖片。第一個引數傳字串,是視窗名字;第二個引數傳指標,是指向要顯示的圖片的。

關於cvSaveImage

就是把某個指標指向的圖片儲存下來啦。第一個引數是代表路徑的字串,第二個引數傳指標。(你看這玩意兒到處都是指標

關於cvWaitKey

這個就是等使用者按鍵用的。如果不加這個玩意兒的話程式會直接執行下去,你能看到的就只有控制檯介面一閃而過了。。。

雖然這裡用得像一個void函式但是這玩意兒實際上是有返回值的!返回的就是使用者按下去的那個鍵。

裡面的那個引數delay是告訴計算機要等多久的,預設值是0。如果這個數小於等於0的話程式就會一直等待下去直到使用者按鍵為止,否則就等待delay毫秒再往下走。

關於cvDestroyWindow和cvReleaseImage

這兩個函式是每次OpenCV的程式結束了以後必須要加上的,作用分別是銷燬視窗和釋放圖片。實際上就是記憶體釋放,如果這兩句不加的話,程式不釋放記憶體就直接退出會報錯。

cvDestroyWindow函式裡面帶一個字串引數表示視窗名稱,cvReleaseImage函式裡面帶一個指標型別變數,指向的是要釋放的那個指標,也就是說它帶進去的是一個指向IplImage型別指標的指標。。。看起來特別繞不過反正ATP就光記住了每次用的時候在前面加取地址符(×

正兒八經的Lv.2

上面那個程式碼光把圖片顯示出來了但是什麼也沒對它做。。所以ATP把上面那個程式碼改了一下!

#include "cv.h"
#include "highgui.h"
#include <cstdio>
using namespace std;
IplImage *srcimage, *newimage;
int main()
{
    if ((srcimage = cvLoadImage("03.jpg", 0)) == 0) {
        printf("??!!\n");
    }
    cvNamedWindow("source", 1);
    cvShowImage("source", srcimage);

    cvWaitKey(0);

    newimage = cvCreateImage(cvGetSize(srcimage), srcimage->depth, srcimage->nChannels);
    cvFlip(srcimage, newimage, 0);
    cvSaveImage("gray.jpg", newimage);
    cvShowImage("source", newimage);

    cvWaitKey(0);

    cvDestroyWindow("source");
    cvReleaseImage(&srcimage);

    return 0;
}

這段程式碼實現的功能是在第一次按鍵以後把圖片上下翻轉,第二次按鍵的時候釋放視窗並關閉。

關於cvCreateImage

這個函式實際上可以看成是對指標變數所指向的內容初始化,相當於“new”一個東西出來。ATP一開始寫的時候忘加這一句了結果執行出來的newimage就是個0kb的空圖片。。

這個函式帶三個引數,第一個引數要帶一個cvSize型別的結構體,裡面儲存圖片的寬和高,直接用cvGetSize函式就可以很方便地得到這個引數。

ATP一開始做的時候把它和IplImage裡面的imageSize引數混了。。舉個例子來講srcimage->imageSize這個變數裡面存的是一個int整型代表srcimage影象所佔的位元組數。

第二個引數是srcimage的一個屬性,表示的是影象的“位深度”。可以理解成是用來表示一個畫素的每個資料的“取值範圍”。具體到它的取值什麼的,OpenCV裡面有規定的常量,常見的比如:

IPL_DEPTH_8U:無符號8位整型,取值範圍是0~255

IPL_DEPTH_16S:有符號16位整型,取值範圍是-32768~32767

還有好多別的ATP不一一列舉了。

比如ATP在第一個cvWaitKey後面加了這麼一句:

printf("%d\n", srcimage->depth);

ATP的程式碼輸出了一個“8”,說明這個影象位深度是8,也就是每個畫素佔8個位元組。

第三個引數nChannels表示的就是通道數目。也就是上面提到過的“灰色圖”還是“彩色圖”。

關於cvFlip

這個函式是上面那段程式碼的關鍵部分,就是把一個圖片進行翻轉。

第一個引數指向原圖片,第二個引數指向翻轉後的圖片,第三個引數代表翻轉方式。0是按x軸對稱,1是按y軸對稱,-1是先按x軸對稱再按y軸對稱。

實際上這玩意兒的原理大概。。。就,按照畫素訪問圖片然後按提前設定的對映方式變過去就好了?

然後下面就是把翻轉後的圖片存下來然後顯示出來啦。。。。

然後這篇文章就結束了ATP還不知道它啥時候會發出來下一篇叻。