日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

转载:【opencv入门教程之三】:图片的载入|显示|输出

發(fā)布時間:2025/3/13 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转载:【opencv入门教程之三】:图片的载入|显示|输出 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.


本系列文章由@淺墨_毛星云 出品,轉(zhuǎn)載請注明出處。??

文章鏈接:?http://blog.csdn.net/poem_qianmo/article/details/20537737

作者:毛星云(淺墨)????郵箱:?happylifemxy@163.com?

寫作當前博文時配套使用的OpenCV版本: 2.4.8


這篇文章中,我們將詳細而深入地弄懂入門OpenCV2最基本的問題,那就是圖像的載入,顯示和輸出。

PS:文章末尾提供了博文配套程序源代碼的下載。

依然是先看一張運行截圖:



了解過之前老版本OpenCV的童鞋們都應(yīng)該清楚,對于OpenCV1.0時代的基于 C 語言接口而建的圖像存儲格式IplImage*,如果在退出前忘記release掉的話,就會照成內(nèi)存泄露。而且用起來超級麻煩,我們往往在debug的時候,很大一部分時間在糾結(jié)手動釋放內(nèi)存的問題。雖然對于小型的程序來說手動管理內(nèi)存不是問題,但一旦我們寫的代碼變得越來越龐大,我們便會開始越來越多地糾纏于內(nèi)存管理的問題,而不是著力解決你的開發(fā)目標。

這,就有些舍本逐末的感覺了。


而淺墨在這篇文章開頭想說,自從OpenCV踏入2.0時代,用Mat類數(shù)據(jù)結(jié)構(gòu)作為主打之后,OpenCV變得越發(fā)像需要很少編程涵養(yǎng)的Matlab那樣,上手超級快。甚至有些函數(shù)名稱都和matlab一樣,比如大家所熟知的imread,imwrite,imshow等函數(shù)。

這對于我們廣大圖像處理領(lǐng)域的孩子們來說,這的確是一個可喜可賀的事情。

?

這篇文章中,我們主要來詳細看一看入門OpenCV2最基本的問題,那就圖像的載入,顯示和輸出。


?


?

一、開胃菜之一???關(guān)于OpenCV的命名空間

?


OpenCV中的C++類和函數(shù)都是定義在命名空間cv之內(nèi)的,有兩種方法可以訪問。第一種是,在代碼開頭的適當位置,加上usingnamespace cv;這句。

另外一種是在使用OpenCV類和函數(shù)時,都加入cv::命名空間。不過這種情況難免會不爽,每用一個OpenCV的類或者函數(shù),都要多敲四下鍵盤寫出cv::,很麻煩。

所以,淺墨推崇大家在代碼開頭的適當位置,加上using namespace cv;這句。于是和opencv命名空間一了百了了。

?

?

比如淺墨,在寫簡單的OpenCV程序的時候,如下這三句是標配:

  • #include <opencv2/core/core.hpp>
  • #include<opencv2/highgui/highgui.hpp>
  • using namespace cv;



  • ?

    二、開胃菜之二???關(guān)于Mat類型



    cv::Mat類是用于保存圖像以及其他矩陣數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。默認情況下,其尺寸為0,我們也可以指定初始尺寸,比如,比如定義一個Mat類對象,就要寫cv::Mat pic(320,640,cv::Scalar(100));

    ?

    Mat類型作為OpenCV2新紀元的重要代表“人物”,淺墨準備在稍后的文章中,花長篇幅詳細講解它,現(xiàn)在我們只要理解,它是對應(yīng)于OpenCV1.0時代的IplImage的主要用來存放圖像的數(shù)據(jù)結(jié)構(gòu)就行了。對于這篇文章,我們需要用到關(guān)于Mat其實就簡單的這樣一句代碼:

    Mat myMat= imread("dota.jpg");

    ?

    表示從工程目錄下把一幅名為dota.jpg的jpg類型的圖像載入到Mat類型的myMat中。這里的imread函數(shù)這篇文章的下文就會詳細剖析到。

    ?

    好吧,開胃菜就是這么多了,下面來看看今天的主要內(nèi)容,圖像的載入和顯示,處理圖像混合,設(shè)置感興趣區(qū)域以及如何輸出圖像,一項一項來擊破吧。

    ?


    三、圖像的載入和顯示



    在新版本的OpenCV2中,最簡單的圖像載入和顯示只需要3句代碼,非常便捷。這三句代碼分別對應(yīng)了三個函數(shù),他們分別是:

    imread( ), namedWindow( )以及imshow( )。我們依次來解析一下這三個函數(shù)。

    ?

    ?

    1.imread函數(shù)


    首先,我們看imread函數(shù),可以在OpenCV官方文檔中查到其原型如下:

    ?

    Mat imread(const string& filename, intflags=1 );

    ?

    ■?第一個參數(shù),const string&類型的filename,填我們需要載入的圖片路徑名。

    在Windows操作系統(tǒng)下,OpenCV的imread函數(shù)支持如下類型的圖像載入:

    ?

    • Windows位圖 - *.bmp, *.dib
    • JPEG文件 - *.jpeg, *.jpg, *.jpe
    • JPEG 2000文件- *.jp2
    • PNG圖片 - *.png
    • 便攜文件格式- *.pbm, *.pgm, *.ppm
    • Sun rasters光柵文件 - *.sr, *.ras
    • TIFF 文件 - *.tiff, *.tif

    ■?第二個參數(shù),int類型的flags,為載入標識,它指定一個加載圖像的顏色類型。可以看到它自帶缺省值1.所以有時候這個參數(shù)在調(diào)用時我們可以忽略,在看了下面的講解之后,我們就會發(fā)現(xiàn),如果在調(diào)用時忽略這個參數(shù),就表示載入三通道的彩色圖像。

    可以在OpenCV中標識圖像格式的枚舉體中取值。通過轉(zhuǎn)到定義,我們可以在higui_c.h中發(fā)現(xiàn)這個枚舉的定義是這樣的:

  • enum
  • {
  • /* 8bit, color or not */
  • CV_LOAD_IMAGE_UNCHANGED =-1,
  • /* 8bit, gray */
  • CV_LOAD_IMAGE_GRAYSCALE =0,
  • /* ?, color */
  • CV_LOAD_IMAGE_COLOR =1,
  • /* any depth, ? */
  • CV_LOAD_IMAGE_ANYDEPTH =2,
  • /* ?, any color */
  • CV_LOAD_IMAGE_ANYCOLOR =4
  • };

  • 相應(yīng)的解釋:

    • CV_LOAD_IMAGE_UNCHANGED,這個標識在新版本中被廢置了,忽略。
    • CV_LOAD_IMAGE_ANYDEPTH- 如果取這個標識的話,若載入的圖像的深度為16位或者32位,就返回對應(yīng)深度的圖像,否則,就轉(zhuǎn)換為8位圖像再返回。
    • CV_LOAD_IMAGE_COLOR- 如果取這個標識的話,總是轉(zhuǎn)換圖像到彩色一體
    • CV_LOAD_IMAGE_GRAYSCALE- 如果取這個標識的話,始終將圖像轉(zhuǎn)換成灰度1

    ?

    如果輸入有沖突的標志,將采用較小的數(shù)字值。比如CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR 將載入3通道圖。

    如果想要載入最真實的圖像,選擇CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR。

    ?

    因為flags是int型的變量,如果我們不在這個枚舉體中取值的話,還可以這樣來:

    • flags >0返回一個3通道的彩色圖像。
    • flags =0返回灰度圖像。
    • flags <0返回包含Alpha通道的加載的圖像。

    需要注意的點:輸出的圖像默認情況下是不載入Alpha通道進來的。如果我們需要載入Alpha通道的話呢,這里就需要取負值。

    ?

    如果你搞怪,flags取1999,也是可以的,這時就表示返回一個3通道的彩色圖像。

    ?

    ?

    好了,講了這么多,來幾個載入示例,一看就懂:

    ?

  • Mat image0=imread("dota.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);//載入最真實的圖像
  • Mat image1=imread("dota.jpg",0);//載入灰度圖
  • Mat image2=imread("dota.jpg",199);//載入3通道的彩色圖像
  • Mat logo=imread("dota_logo.jpg");//載入3通道的彩色圖像



  • 2.namedWindow函數(shù)


    顧名思義,namedWindow函數(shù),用于創(chuàng)建一個窗口。

    函數(shù)原型是這樣的:

    void namedWindow(const string& winname,int flags=WINDOW_AUTOSIZE );

    ? ? ??■?第一個參數(shù),const string&型的name,即填被用作窗口的標識符的窗口名稱。

    ? ? ??■?第二個參數(shù),int 類型的flags?,窗口的標識,可以填如下的值:

      • WINDOW_NORMAL設(shè)置了這個值,用戶便可以改變窗口的大小(沒有限制)
      • WINDOW_AUTOSIZE如果設(shè)置了這個值,窗口大小會自動調(diào)整以適應(yīng)所顯示的圖像,并且不能手動改變窗口大小。
      • WINDOW_OPENGL?如果設(shè)置了這個值的話,窗口創(chuàng)建的時候便會支持OpenGL。

    函數(shù)剖析:

    首先需要注意的是,它有默認值WINDOW_AUTOSIZE,所以,一般情況下,這個函數(shù)我們填一個變量就行了。

    namedWindow函數(shù)的作用是,通過指定的名字,創(chuàng)建一個可以作為圖像和進度條的容器窗口。如果具有相同名稱的窗口已經(jīng)存在,則函數(shù)不做任何事情。

    我們可以調(diào)用destroyWindow()或者destroyAllWindows()函數(shù)來關(guān)閉窗口,并取消之前分配的與窗口相關(guān)的所有內(nèi)存空間。

    但話是這樣說,其實對于代碼量不大的簡單小程序來說,我們完全沒有必要手動調(diào)用上述的destroyWindow()或者destroyAllWindows()函數(shù),因為在退出時,所有的資源和應(yīng)用程序的窗口會被操作系統(tǒng)會自動關(guān)閉。

    ?

    3.imshow函數(shù)


    在指定的窗口中顯示一幅圖像。

    void imshow(const string& winname, InputArray mat);

    ?■?第一個參數(shù),const string&類型的winname,填需要顯示的窗口標識名稱。

    ?■?第二個參數(shù),InputArray?類型的mat,填需要顯示的圖像。

    ?

    這里的InputArray?我們講一下吧,不然一直是個梗在這邊。通過轉(zhuǎn)到定義大法,我們可以在

    Highgui.hpp中查到imshow的原型:

    ?

    CV_EXPORTS_W void imshow(const string&winname, InputArray mat);

    ?

    進一步對InputArray轉(zhuǎn)到定義,在core.hpp中查到一個typedef聲明:

    typedef const _InputArray& InputArray;

    這其實一個類型聲明引用,就是說_InputArray和InputArray是一個意思,既然他們是一個意思,我們就來做最后一步,對_InputArray進行轉(zhuǎn)到定義,終于,我們在core.hpp發(fā)現(xiàn)了InputArray的真身:


  • class CV_EXPORTS _InputArray
  • {
  • public:
  • enum {
  • KIND_SHIFT = 16,
  • FIXED_TYPE = 0x8000 << KIND_SHIFT,
  • FIXED_SIZE = 0x4000 << KIND_SHIFT,
  • KIND_MASK = ~(FIXED_TYPE|FIXED_SIZE) - (1 << KIND_SHIFT) + 1,
  • NONE = 0 <<KIND_SHIFT,
  • MAT = 1 <<KIND_SHIFT,
  • MATX = 2 <<KIND_SHIFT,
  • STD_VECTOR = 3 <<KIND_SHIFT,
  • STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
  • STD_VECTOR_MAT = 5 <<KIND_SHIFT,
  • EXPR = 6 <<KIND_SHIFT,
  • OPENGL_BUFFER = 7 <<KIND_SHIFT,
  • OPENGL_TEXTURE = 8 <<KIND_SHIFT,
  • GPU_MAT = 9 <<KIND_SHIFT,
  • OCL_MAT =10 <<KIND_SHIFT
  • };
  • _InputArray();
  • _InputArray(const Mat& m);
  • _InputArray(const MatExpr& expr);
  • template<typename _Tp> _InputArray(const _Tp* vec, int n);
  • template<typename _Tp> _InputArray(const vector<_Tp>&vec);
  • template<typename _Tp> _InputArray(constvector<vector<_Tp> >& vec);
  • _InputArray(const vector<Mat>& vec);
  • template<typename _Tp> _InputArray(const vector<Mat_<_Tp>>& vec);
  • template<typename _Tp> _InputArray(const Mat_<_Tp>& m);
  • template<typename _Tp, int m, int n> _InputArray(constMatx<_Tp, m, n>& matx);
  • _InputArray(const Scalar& s);
  • _InputArray(const double& val);
  • // < Deprecated
  • _InputArray(const GlBuffer& buf);
  • _InputArray(const GlTexture& tex);
  • // >
  • _InputArray(const gpu::GpuMat& d_mat);
  • _InputArray(const ogl::Buffer& buf);
  • _InputArray(const ogl::Texture2D& tex);
  • virtual Mat getMat(int i=-1) const;
  • virtual void getMatVector(vector<Mat>& mv) const;
  • // < Deprecated
  • virtual GlBuffer getGlBuffer() const;
  • virtual GlTexture getGlTexture() const;
  • // >
  • virtual gpu::GpuMat getGpuMat() const;
  • /*virtual*/ ogl::Buffer getOGlBuffer() const;
  • /*virtual*/ ogl::Texture2D getOGlTexture2D() const;
  • virtual int kind() const;
  • virtual Size size(int i=-1) const;
  • virtual size_t total(int i=-1) const;
  • virtual int type(int i=-1) const;
  • virtual int depth(int i=-1) const;
  • virtual int channels(int i=-1) const;
  • virtual bool empty() const;
  • #ifdefOPENCV_CAN_BREAK_BINARY_COMPATIBILITY
  • virtual ~_InputArray();
  • #endif
  • int flags;
  • void* obj;
  • Size sz;
  • };


  • 可以看到,_InputArray類的里面首先定義了一個枚舉,然后是各類的模板類型和一些方法。更復(fù)雜的我們暫且不挖深講了,很多時候,遇到函數(shù)原型中的InputArray類型,我們把它簡單地當做Mat類型就行了。

    ?

    imshow?函數(shù)詳解:

    imshow?函數(shù)用于在指定的窗口中顯示圖像。如果窗口是用CV_WINDOW_AUTOSIZE(默認值)標志創(chuàng)建的,那么顯示圖像原始大小。否則,將圖像進行縮放以適合窗口。而imshow?函數(shù)縮放圖像,取決于圖像的深度:

    • 如果載入的圖像是8位無符號類型(8-bit unsigned),就顯示圖像本來的樣子。
    • 如果圖像是16位無符號類型(16-bit unsigned)或32位整型(32-bit integer),便用像素值除以256。也就是說,值的范圍是[0,255 x 256]映射到[0,255]。
    • 如果圖像是32位浮點型(32-bit floating-point),像素值便要乘以255。也就是說,該值的范圍是[0,1]映射到[0,255]。


    還有一點,若窗口創(chuàng)建(namedWindow函數(shù))的時候,如果設(shè)定了支持OpenGL(WINDOW_OPENGL?),那么imshow還支持ogl::Buffer ,ogl::Texture2D以及gpu::GpuMat作為輸入。

    ?



    ?

    四、輸出圖像到文件——imwrite函數(shù)


    在OpenCV中,輸出圖像到文件,我們一般都用imwrite函數(shù),它的聲明如下:

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

    ?

    ?■?第一個參數(shù),const string&類型的filename,填需要寫入的文件名就行了,帶上后綴,比如,“123.jpg”這樣。

    ?■?第二個參數(shù),InputArray類型的img,一般填一個Mat類型的圖像數(shù)據(jù)就行了。

    ?■?第三個參數(shù),const vector<int>&類型的params,表示為特定格式保存的參數(shù)編碼,它有默認值vector<int>(),所以一般情況下不需要填寫。而如果要填寫的話,有下面這些需要了解的地方:

    ?

      • 對于JPEG格式的圖片,這個參數(shù)表示從0到100的圖片質(zhì)量(CV_IMWRITE_JPEG_QUALITY),默認值是95.
      • 對于PNG格式的圖片,這個參數(shù)表示壓縮級別(CV_IMWRITE_PNG_COMPRESSION)從0到9。較高的值意味著更小的尺寸和更長的壓縮時間,而默認值是3。
      • 對于PPM,PGM,或PBM格式的圖片,這個參數(shù)表示一個二進制格式標志(CV_IMWRITE_PXM_BINARY),取值為0或1,而默認值是1。

    ?

    函數(shù)解析:

    imwrite函數(shù)用于將圖像保存到指定的文件。圖像格式是基于文件擴展名的,可保存的擴展名和imread中可以讀取的圖像擴展名一樣,為了方便查看,我們在這里再列一遍:

      • Windows位圖 - *.bmp, *.dib
      • JPEG文件 - *.jpeg, *.jpg, *.jpe
      • JPEG 2000文件- *.jp2
      • PNG圖片 - *.png
      • 便攜文件格式- *.pbm, *.pgm, *.ppm
      • Sun rasters光柵格式 - *.sr, *.ras
      • TIFF 文件 - *.tiff, *.tif

  • #include <vector>
  • #include <stdio.h>
  • #include<opencv2/opencv.hpp>
  • using namespace cv;
  • using namespace std;
  • void createAlphaMat(Mat &mat)
  • {
  • for(int i = 0; i < mat.rows; ++i) {
  • for(int j = 0; j < mat.cols; ++j) {
  • Vec4b&rgba = mat.at<Vec4b>(i, j);
  • rgba[0]= UCHAR_MAX;
  • rgba[1]= saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) *UCHAR_MAX);
  • rgba[2]= saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) *UCHAR_MAX);
  • rgba[3]= saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
  • }
  • }
  • }
  • int main( )
  • {
  • //創(chuàng)建帶alpha通道的Mat
  • Mat mat(480, 640, CV_8UC4);
  • createAlphaMat(mat);
  • vector<int>compression_params;
  • compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
  • compression_params.push_back(9);
  • try{
  • imwrite("透明Alpha值圖.png", mat, compression_params);
  • }
  • catch(runtime_error& ex) {
  • fprintf(stderr,"圖像轉(zhuǎn)換成PNG格式發(fā)生錯誤:%s\n", ex.what());
  • return1;
  • }
  • fprintf(stdout,"PNG圖片文件的alpha數(shù)據(jù)保存完畢~\n");
  • return 0;
  • }




  • 五、一個綜合示例



    最后是一個綜合示例,載入圖像,進行簡單圖像混合,顯示圖像,并且輸出混合后的圖像到j(luò)pg。

    由于篇幅原因,這里的圖像混合具體細節(jié)我們放到稍后的文章中再講,現(xiàn)在先給大家看看混合的效果和源碼。囧,因為opencv圖像處理真的很少涉及到設(shè)計模式的問題,所以很多時候往往就是main函數(shù)中塞滿一串串代碼打天下,即便是OpenCV官方的示例都是如此。

    好了,如下就是這篇文章配套綜合示例的配套源碼,非常的簡單明了:

    ?

  • //-----------------------------------【程序說明】----------------------------------------------
  • // 程序名稱::【OpenCV入門教程之三】圖像的載入,顯示與輸出 一站式完全解析 博文配套源碼
  • // VS2010版 OpenCV版本:2.4.8
  • // 2014年3月5日 Create by 淺墨
  • // 描述: 圖像的載入,顯示與輸出 一站式剖析 配套源碼
  • // 圖片素材出處:dota2原畫圣堂刺客 dota2 logo 動漫人物
  • //------------------------------------------------------------------------------------------------
  • #include<opencv2/core/core.hpp>
  • #include<opencv2/highgui/highgui.hpp>
  • using namespace cv;
  • int main( )
  • {
  • //-----------------------------------【一、圖像的載入和顯示】--------------------------------------
  • // 描述:以下三行代碼用于完成圖像的載入和顯示
  • //--------------------------------------------------------------------------------------------------
  • Mat girl=imread("girl.jpg"); //載入圖像到Mat
  • namedWindow("【1】動漫圖"); //創(chuàng)建一個名為 "【1】動漫圖"的窗口
  • imshow("【1】動漫圖",girl);//顯示名為 "【1】動漫圖"的窗口
  • //-----------------------------------【二、初級圖像混合】--------------------------------------
  • // 描述:二、初級圖像混合
  • //-----------------------------------------------------------------------------------------------
  • //載入圖片
  • Mat image= imread("dota.jpg",199);
  • Mat logo= imread("dota_logo.jpg");
  • //載入后先顯示
  • namedWindow("【2】原畫圖");
  • imshow("【2】原畫圖",image);
  • namedWindow("【3】logo圖");
  • imshow("【3】logo圖",logo);
  • //定義一個Mat類型,用于存放,圖像的ROI
  • Mat imageROI;
  • //方法一
  • imageROI=image(Rect(800,350,logo.cols,logo.rows));
  • //方法二
  • //imageROI=image(Range(350,350+logo.rows),Range(800,800+logo.cols));
  • //將logo加到原圖上
  • addWeighted(imageROI,0.5,logo,0.3,0.,imageROI);
  • //顯示結(jié)果
  • namedWindow("【4】原畫+logo圖");
  • imshow("【4】原畫+logo圖",image);
  • //-----------------------------------【三、圖像的輸出】--------------------------------------
  • // 描述:將一個Mat圖像輸出到圖像文件
  • //-----------------------------------------------------------------------------------------------
  • //輸出一張jpg圖片到工程目錄下
  • imwrite("我喜歡打dota2 by淺墨.jpg",image);
  • waitKey();
  • return 0;
  • }


  • 運行這個程序,會彈出四個我們在OpenCV中創(chuàng)建的窗口。

    下面是運行截圖。首先是圖像載入和顯示的演示,我們載入了一張動漫人物圖:

    ?

    ?


    接著是載入一張dota2原畫和dota2logo圖,為圖像融合做準備:

    ?


    logo圖:


    最終,經(jīng)過處理,得到dota2原畫+logo的融合,并輸出一張名為我喜歡打dota2 by淺墨.jpg的圖片到工程目錄下。

    ?

    ?

    ?嗯,本篇文章到這里就基本結(jié)束了,最后放出本篇文章配套示例程序的下載地址。


    本篇文章的配套源代碼請點擊這里下載:



    【淺墨OpenCV入門教程之三】圖像的載入,顯示和輸出配套源代碼下載


    OK,本節(jié)的內(nèi)容大概就是這些,我們下篇文章見:)

    ?

    淺墨_毛星云 博客專家 原創(chuàng)文章 159獲贊 9891訪問量 755萬+ 已關(guān)注 他的留言板

    總結(jié)

    以上是生活随笔為你收集整理的转载:【opencv入门教程之三】:图片的载入|显示|输出的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。