【opencv入門篇】 10個程序快速上手opencv【下】

導言本系列博客目的在於可以在vs快速上手opencv,理論知識涉及較少,你們有興趣能夠查閱其餘博客深刻了解相關的理論知識,本博客後續也會對圖像方向的理論進一步分析,敬請期待:)html

上篇傳送:http://www.cnblogs.com/always-chang/p/6170727.htmlwindows

學習思惟導圖:數組

五、圖像輪廓檢測

主要函數介紹:網絡

1)cvFindContours數據結構

函數功能:對圖像進行輪廓檢測,這個函數將生成一條鏈表以保存檢測出的各個輪廓信息,並傳出指向這條鏈表表頭的指針。函數

函數原型:學習

int cvFindContours(spa

  CvArr* image,.net

  CvMemStorage* storage,3d

  CvSeq** first_contour,   

  int header_size=sizeof(CvContour),

  int mode=CV_RETR_LIST,   

  int method=CV_CHAIN_APPROX_SIMPLE,

  CvPoint offset=cvPoint(0,0)

);

函數說明:

第一個參數表示輸入圖像,必須爲一個8位的二值圖像。

第二參數表示存儲輪廓的容器。爲CvMemStorage類型,定義在OpenCV的\core\types_c.h中。

第三個參數爲輸出參數,這個參數將指向用來存儲輪廓信息的鏈表表頭。

第四個參數表示存儲輪廓鏈表的表頭大小,當第六個參數傳入CV_CHAIN_CODE時,要設置成sizeof(CvChain),其它狀況統一設置成sizeof(CvContour)。

第五個參數爲輪廓檢測的模式,有以下取值:

      CV_RETR_EXTERNAL:只檢索最外面的輪廓;

  CV_RETR_LIST:檢索全部的輪廓,並將其保存到一條鏈表當中;

  CV_RETR_CCOMP:檢索全部的輪廓,並將他們組織爲兩層:頂層是各部分的外部邊界,第二層是空洞的邊界;

      CV_RETR_TREE:檢索全部的輪廓,並重構嵌套輪廓的整個層次。

第六個參數用來表示輪廓邊緣的近似方法的,經常使用值以下所示:

      CV_CHAIN_CODE:以Freeman鏈碼的方式輸出輪廓,全部其餘方法輸出多邊形(頂點的序列)。

  CV_CHAIN_APPROX_SIMPLE:壓縮水平的、垂直的和斜的部分,也就是,函數只保留他們的終點部分。

第七個參數表示偏移量,好比你要從圖像的(100, 0)開始進行輪廓檢測,那麼就傳入(100, 0)。

 

使用cvFindContours函數能檢測出圖像的輪廓,將輪廓繪製出來則須要另外一函數——cvDrawContours來配合了。下面介紹cvDrawContours函數。

2)cvDrawContours

函數功能:在圖像上繪製外部和內部輪廓

函數原型:

void cvDrawContours(

  CvArr *img,

  CvSeq* contour,

  CvScalar external_color,

  CvScalar hole_color,

  int max_level,

  int thickness=1,

  int line_type=8,

  CvPoint offset=cvPoint(0,0)

);

第一個參數表示輸入圖像,函數將在這張圖像上繪製輪廓。

第二個參數表示指向輪廓鏈表的指針。

第三個參數和第四個參數表示顏色,繪製時會根據輪廓的層次來交替使用這二種顏色。

第五個參數表示繪製輪廓的最大層數,若是是0,只繪製contour;若是是1,追加繪製和contour同層的全部輪廓;若是是2,追加繪製比contour低一層的輪廓,以此類推;若是值是負值,則函數並不繪製contour後的輪廓,可是將畫出其子輪廓,一直到abs(max_level) - 1層。

第六個參數表示輪廓線的寬度,若是爲CV_FILLED則會填充輪廓內部。

第七個參數表示輪廓線的類型。

第八個參數表示偏移量,若是傳入(10,20),那繪製將從圖像的(10,20)處開始。

 1 #include <opencv2/opencv.hpp>  
 2 using namespace std;
 3 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")  
 4 IplImage *g_pGrayImage = NULL;
 5 const char *pstrWindowsBinaryTitle = "二值圖";
 6 const char *pstrWindowsOutLineTitle = "輪廓圖";
 7 CvSeq *g_pcvSeq = NULL;
 8 
 9 void on_trackbar(int pos)
10 {
11     // 轉爲二值圖  
12     IplImage *pBinaryImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, 1);
13     cvThreshold(g_pGrayImage, pBinaryImage, pos, 255, CV_THRESH_BINARY);
14     // 顯示二值圖  
15     cvShowImage(pstrWindowsBinaryTitle, pBinaryImage);
16 
17     CvMemStorage* cvMStorage = cvCreateMemStorage();
18     // 檢索輪廓並返回檢測到的輪廓的個數  
19     cvFindContours(pBinaryImage, cvMStorage, &g_pcvSeq);
20 
21     IplImage *pOutlineImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, 3);
22     int _levels = 5;
23     cvZero(pOutlineImage);
24     cvDrawContours(pOutlineImage, g_pcvSeq, CV_RGB(255, 0, 0), CV_RGB(0, 255, 0), _levels);
25     cvShowImage(pstrWindowsOutLineTitle, pOutlineImage);
26 
27     cvReleaseMemStorage(&cvMStorage);
28     cvReleaseImage(&pBinaryImage);
29     cvReleaseImage(&pOutlineImage);
30 }
31 
32 int main(int argc, char** argv)
33 {
34     const char *pstrWindowsSrcTitle = "原圖";
35     const char *pstrWindowsToolBarName = "二值化";
36 
37     // 從文件中加載原圖  
38     IplImage *pSrcImage = cvLoadImage("01.jpg", CV_LOAD_IMAGE_UNCHANGED);
39     // 顯示原圖  
40     cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
41     cvShowImage(pstrWindowsSrcTitle, pSrcImage);
42 
43     // 轉爲灰度圖  
44     g_pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
45     cvCvtColor(pSrcImage, g_pGrayImage, CV_BGR2GRAY);
46 
47     // 建立二值圖和輪廓圖窗口  
48     cvNamedWindow(pstrWindowsBinaryTitle, CV_WINDOW_AUTOSIZE);
49     cvNamedWindow(pstrWindowsOutLineTitle, CV_WINDOW_AUTOSIZE);
50 
51 
52     // 滑動條    
53     int nThreshold = 0;
54     cvCreateTrackbar(pstrWindowsToolBarName, pstrWindowsBinaryTitle, &nThreshold, 254, on_trackbar);
55 
56     on_trackbar(1);
57 
58     cvWaitKey(0);
59 
60     cvDestroyWindow(pstrWindowsSrcTitle);
61     cvDestroyWindow(pstrWindowsBinaryTitle);
62     cvDestroyWindow(pstrWindowsOutLineTitle);
63     cvReleaseImage(&pSrcImage);
64     cvReleaseImage(&g_pGrayImage);
65     return 0;
66 }

輸出:

 

六、鼠標繪圖

關鍵函數介紹

1)cvSetMouseCallback

函數功能:設置處理鼠標消息的回調函數

函數原型:

/* assign callback for mouse events */

CVAPI(void) cvSetMouseCallback(

    const char* window_name,

    CvMouseCallback on_mouse,

    void* param CV_DEFAULT(NULL)

);

函數說明:

第一個參數表示窗口名稱。

第二個參數表示鼠標消息的消息處理函數。

第三個參數表示用戶定義傳入鼠標指定消息處理函數的參數。

 

2)CvMouseCallback

函數功能:鼠標消息的回調函數

函數原型:

typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);

函數說明:

第一個參數表示鼠標消息類型,取值以下:

enum

{

    CV_EVENT_MOUSEMOVE      =0,

    CV_EVENT_LBUTTONDOWN    =1,

    CV_EVENT_RBUTTONDOWN    =2,

    CV_EVENT_MBUTTONDOWN    =3,

    CV_EVENT_LBUTTONUP      =4,

    CV_EVENT_RBUTTONUP      =5,

    CV_EVENT_MBUTTONUP      =6,

    CV_EVENT_LBUTTONDBLCLK  =7,

    CV_EVENT_RBUTTONDBLCLK  =8,

    CV_EVENT_MBUTTONDBLCLK  =9

};

第二,三個參數表示鼠標的座標。

第四個參數表示附加事件,取值以下:

enum

{

    CV_EVENT_FLAG_LBUTTON   =1,

    CV_EVENT_FLAG_RBUTTON   =2,

    CV_EVENT_FLAG_MBUTTON   =4,

    CV_EVENT_FLAG_CTRLKEY   =8,

    CV_EVENT_FLAG_SHIFTKEY  =16,

    CV_EVENT_FLAG_ALTKEY    =32

};

第五個參數即設置cvSetMouseCallback()中將接收到的參數。

 1 #include <opencv2/opencv.hpp>  
 2 using namespace std;
 3 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")  
 4 const char *pstrWindowsMouseDrawTitle = "鼠標繪圖";
 5 // 鼠標消息的回調函數  
 6 void on_mouse(int event, int x, int y, int flags, void* param)
 7 {
 8     static bool s_bMouseLButtonDown = false;
 9     static CvPoint s_cvPrePoint = cvPoint(0, 0);
10 
11     switch (event)
12     {
13     case CV_EVENT_LBUTTONDOWN:
14         s_bMouseLButtonDown = true;
15         s_cvPrePoint = cvPoint(x, y);
16         break;
17 
18     case  CV_EVENT_LBUTTONUP:
19         s_bMouseLButtonDown = false;
20         break;
21 
22     case CV_EVENT_MOUSEMOVE:
23         if (s_bMouseLButtonDown)
24         {
25             CvPoint cvCurrPoint = cvPoint(x, y);
26             cvLine((IplImage*)param, s_cvPrePoint, cvCurrPoint, CV_RGB(0, 0, 20), 3);
27             s_cvPrePoint = cvCurrPoint;
28             cvShowImage(pstrWindowsMouseDrawTitle, (IplImage*)param);
29         }
30         break;
31     }
32 }
33 int main()
34 {
35     const int MAX_WIDTH = 500, MAX_HEIGHT = 400;
36     const char *pstrSaveImageName = "Draw.jpg";
37 
38     IplImage *pSrcImage = cvCreateImage(cvSize(MAX_WIDTH, MAX_HEIGHT), IPL_DEPTH_8U, 3);
39     cvSet(pSrcImage, CV_RGB(255, 255, 255)); //能夠用cvSet()將圖像填充成白色  
40     cvNamedWindow(pstrWindowsMouseDrawTitle, CV_WINDOW_AUTOSIZE);
41     cvShowImage(pstrWindowsMouseDrawTitle, pSrcImage);
42 
43     cvSetMouseCallback(pstrWindowsMouseDrawTitle, on_mouse, (void*)pSrcImage);
44 
45     int c;
46     do{
47         c = cvWaitKey(0);
48         switch ((char)c)
49         {
50         case 'r'://r重畫
51             cvSet(pSrcImage, CV_RGB(255, 255, 255));
52             cvShowImage(pstrWindowsMouseDrawTitle, pSrcImage);
53             break;
54 
55         case 's'://s保存圖像
56             cvSaveImage(pstrSaveImageName, pSrcImage);
57             break;
58         }
59     } while (c > 0 && c != 27);
60 
61     cvDestroyWindow(pstrWindowsMouseDrawTitle);
62     cvReleaseImage(&pSrcImage);
63     return 0;
64 }

畫的太醜,就不貼了。。。

 

七、人臉檢測

使用人臉的Haar特徵分類器很是之簡單,直接使用cvHaarDetectObjects。下面來看看這個函數的介紹:

函數功能:檢測圖像中的目錄

函數原型:

CVAPI(CvSeq*) cvHaarDetectObjects(

  const CvArr* image,

  CvHaarClassifierCascade* cascade,

  CvMemStorage* storage,

  double scale_factor CV_DEFAULT(1.1),

  int min_neighbors CV_DEFAULT(3),

  int flags CV_DEFAULT(0),

  CvSize min_size CV_DEFAULT(cvSize(0,0)),

  CvSize max_size CV_DEFAULT(cvSize(0,0))

);

函數說明:

第一個參數表示輸入圖像,儘可能使用灰度圖以加快檢測速度。

第二個參數表示Haar特徵分類器,能夠用cvLoad()函數來從磁盤中加載xml文件做爲Haar特徵分類器。

第三個參數爲CvMemStorage類型,你們應該很熟悉這個CvMemStorage類型了。

第四個參數表示在先後兩次相繼的掃描中,搜索窗口的比例係數。默認爲1.1即每次搜索窗口依次擴大10%

第五個參數表示構成檢測目標的相鄰矩形的最小個數(默認爲3個)。若是組成檢測目標的小矩形的個數和小於 min_neighbors - 1 都會被排除。若是min_neighbors 爲 0, 則函數不作任何操做就返回全部的被檢候選矩形框,這種設定值通常用在用戶自定義對檢測結果的組合程序上。

第六個參數要麼使用默認值,要麼使用CV_HAAR_DO_CANNY_PRUNING,若是設置爲CV_HAAR_DO_CANNY_PRUNING,那麼函數將會使用Canny邊緣檢測來排除邊緣過多或過少的區域,所以這些區域一般不會是人臉所在區域。

第七個,第八個參數表示檢測窗口的最小值和最大值,通常設置爲默認便可。

函數返回值:

函數將返回CvSeq對象,該對象包含一系列CvRect表示檢測到的人臉矩形。

#include <opencv2/opencv.hpp>  
#include <cstdio>  
#include <cstdlib>  
#include <Windows.h>  
using namespace std;
int main()
{
    // 加載Haar特徵檢測分類器  
    // haarcascade_frontalface_alt.xml系OpenCV自帶的分類器 下面是我機器上的文件路徑  
    const char *pstrCascadeFileName = "E:\\opencv\\opencv\\data\\haarcascades\\haarcascade_frontalface_alt.xml";
    CvHaarClassifierCascade *pHaarCascade = NULL;
    pHaarCascade = (CvHaarClassifierCascade*)cvLoad(pstrCascadeFileName);

    // 載入圖像  
    const char *pstrImageName = "cyh.jpg";
    IplImage *pSrcImage = cvLoadImage(pstrImageName, CV_LOAD_IMAGE_UNCHANGED);

    IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
    cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);

    // 人臉識別與標記  
    if (pHaarCascade != NULL)
    {
        CvScalar FaceCirclecolors[] =
        {
            { { 0, 0, 255 } },
            { { 0, 128, 255 } },
            { { 0, 255, 255 } },
            { { 0, 255, 0 } },
            { { 255, 128, 0 } },
            { { 255, 255, 0 } },
            { { 255, 0, 0 } },
            { { 255, 0, 255 } }
        };

        CvMemStorage *pcvMStorage = cvCreateMemStorage(0);
        cvClearMemStorage(pcvMStorage);
        // 識別  
        DWORD dwTimeBegin, dwTimeEnd;
        dwTimeBegin = GetTickCount();
        CvSeq *pcvSeqFaces = cvHaarDetectObjects(pGrayImage, pHaarCascade, pcvMStorage);
        dwTimeEnd = GetTickCount();

        printf("人臉個數: %d   識別用時: %d ms\n", pcvSeqFaces->total, dwTimeEnd - dwTimeBegin);

        // 標記  
        for (int i = 0; i < pcvSeqFaces->total; i++)
        {
            CvRect* r = (CvRect*)cvGetSeqElem(pcvSeqFaces, i);
            CvPoint center;
            int radius;
            center.x = cvRound((r->x + r->width * 0.5));
            center.y = cvRound((r->y + r->height * 0.5));
            radius = cvRound((r->width + r->height) * 0.25);
            cvCircle(pSrcImage, center, radius, FaceCirclecolors[i % 8], 2);
        }
        cvReleaseMemStorage(&pcvMStorage);
    }

    const char *pstrWindowsTitle = "人臉識別 ";
    cvNamedWindow(pstrWindowsTitle, CV_WINDOW_AUTOSIZE);
    cvShowImage(pstrWindowsTitle, pSrcImage);

    cvWaitKey(0);

    cvDestroyWindow(pstrWindowsTitle);
    cvReleaseImage(&pSrcImage);
    cvReleaseImage(&pGrayImage);
    return 0;
}

輸出:

無遮擋背景乾淨:

三我的也能夠:

有遮擋就不行了,與商業化的軟件仍是有很大差異的。。

 

 八、灰度直方圖

主要函數介紹:

1)cvCreateHist

函數功能:建立直方圖

函數原型:

CVAPI(CvHistogram*)  cvCreateHist( // Creates new histogram

  int dims,

  int* sizes,

  int type,

  float** ranges CV_DEFAULT(NULL),

  int uniform CV_DEFAULT(1)

);

參數說明:

第一個參數表示直方圖維數,灰度圖爲1,彩色圖爲3。

第二個參數表示直方圖維數的數目,其實就是sizes數組的維數。

第三個參數表示直方圖維數尺寸的數組。

第四個參數表示直方圖類型,爲CV_HIST_ARRAY表示直方圖數據表示爲多維密集數組,爲CV_HIST_TREE表示直方圖數據表示爲多維稀疏數組。

第五個參數表示歸一化標識,其原理有點複雜。一般使用默認值便可。

函數說明:

直方圖的數據結構以下所示:

typedef struct CvHistogram

{

    int     type;

    CvArr*  bins;

    float   thresh[CV_MAX_DIM][2];  /* For uniform histograms. */

    float** thresh2;                /* For non-uniform histograms. */

    CvMatND mat;     /* Embedded matrix header for array histograms. */

}CvHistogram;

2)cvCalcHist

函數功能:根據圖像計算直方圖

函數原型:

void  cvCalcHist(

  IplImage** image,

  CvHistogram* hist,

  int accumulate CV_DEFAULT(0),

  const CvArr* mask CV_DEFAULT(NULL)

)

參數說明:

第一個參數表示輸入圖像。

第二個參數表示輸出的直方圖指針。

第三個參數操做mask, 肯定輸入圖像的哪一個象素被計數。

第四個參數表示累計標識。若是設置,則直方圖在開始時不被清零。這個特徵保證能夠爲多個圖像計算一個單獨的直方圖,或者在線更新直方圖。

函數說明:

這是個inline函數,函數內部會直接調用cvCalcArrHist( (CvArr**)image, hist, accumulate, mask );

 

 1 #include <opencv2/opencv.hpp>  
 2 #include <opencv2/legacy/compat.hpp>  
 3 using namespace std;
 4 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")  
 5 
 6 void FillWhite(IplImage *pImage)
 7 {
 8     cvRectangle(pImage, cvPoint(0, 0), cvPoint(pImage->width, pImage->height), CV_RGB(255, 255, 255), CV_FILLED);
 9 }
10 // 建立灰度圖像的直方圖  
11 CvHistogram* CreateGrayImageHist(IplImage **ppImage)
12 {
13     int nHistSize = 256;
14     float fRange[] = { 0, 255 };  //灰度級的範圍    
15     float *pfRanges[] = { fRange };
16     CvHistogram *pcvHistogram = cvCreateHist(1, &nHistSize, CV_HIST_ARRAY, pfRanges);
17     cvCalcHist(ppImage, pcvHistogram);
18     return pcvHistogram;
19 }
20 // 根據直方圖建立直方圖圖像  
21 IplImage* CreateHisogramImage(int nImageWidth, int nScale, int nImageHeight, CvHistogram *pcvHistogram)
22 {
23     IplImage *pHistImage = cvCreateImage(cvSize(nImageWidth * nScale, nImageHeight), IPL_DEPTH_8U, 1);
24     FillWhite(pHistImage);
25 
26     //統計直方圖中的最大直方塊  
27     float fMaxHistValue = 0;
28     cvGetMinMaxHistValue(pcvHistogram, NULL, &fMaxHistValue, NULL, NULL);
29 
30     //分別將每一個直方塊的值繪製到圖中  
31     int i;
32     for (i = 0; i < nImageWidth; i++)
33     {
34         float fHistValue = cvQueryHistValue_1D(pcvHistogram, i); //像素爲i的直方塊大小  
35         int nRealHeight = cvRound((fHistValue / fMaxHistValue) * nImageHeight);  //要繪製的高度  
36         cvRectangle(pHistImage,
37             cvPoint(i * nScale, nImageHeight - 1),
38             cvPoint((i + 1) * nScale - 1, nImageHeight - nRealHeight),
39             cvScalar(i, 0, 0, 0),
40             CV_FILLED
41             );
42     }
43     return pHistImage;
44 }
45 int main(int argc, char** argv)
46 {
47     const char *pstrWindowsSrcTitle = "原圖";
48     const char *pstrWindowsGrayTitle = "灰度圖";
49     const char *pstrWindowsHistTitle = "直方圖";
50 
51     // 從文件中加載原圖  
52     IplImage *pSrcImage = cvLoadImage("cyh.jpg", CV_LOAD_IMAGE_UNCHANGED);
53     IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
54     // 灰度圖  
55     cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
56 
57     // 灰度直方圖  
58     CvHistogram *pcvHistogram = CreateGrayImageHist(&pGrayImage);
59 
60     // 建立直方圖圖像  
61     int nHistImageWidth = 255;
62     int nHistImageHeight = 150;  //直方圖圖像高度  
63     int nScale = 2;
64     IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogram);
65 
66     // 顯示  
67     cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
68     cvNamedWindow(pstrWindowsGrayTitle, CV_WINDOW_AUTOSIZE);
69     cvNamedWindow(pstrWindowsHistTitle, CV_WINDOW_AUTOSIZE);
70     cvShowImage(pstrWindowsSrcTitle, pSrcImage);
71     cvShowImage(pstrWindowsGrayTitle, pGrayImage);
72     cvShowImage(pstrWindowsHistTitle, pHistImage);
73 
74     cvWaitKey(0);
75 
76     cvReleaseHist(&pcvHistogram);
77 
78     cvDestroyWindow(pstrWindowsSrcTitle);
79     cvDestroyWindow(pstrWindowsGrayTitle);
80     cvDestroyWindow(pstrWindowsHistTitle);
81     cvReleaseImage(&pSrcImage);
82     cvReleaseImage(&pGrayImage);
83     cvReleaseImage(&pHistImage);
84     return 0;
85 }

輸出:

 

九、灰度直方圖均衡化

主要函數介紹:

1)cvEqualizeHist

函數功能:直方圖均衡化,該函數能歸一化圖像亮度和加強對比度

函數原型:

/* equalizes histogram of 8-bit single-channel image */

CVAPI(void)  cvEqualizeHist( const CvArr* src, CvArr* dst );

第一個參數表示輸入圖像,必須爲灰度圖(8位,單通道圖)。

第二個參數表示輸出圖像

函數說明:

該函數採用以下法則對輸入圖像進行直方圖均衡化:

  1:計算輸入圖像的直方圖H。

  2:直方圖歸一化,所以直方塊和爲255。

  3:計算直方圖積分,H'(i) = Sum(H(j)) (0<=j<=i)。

  4:採用H'做爲查詢表:dst(x, y) = H'(src(x, y))進行圖像變換。

  1 #include <opencv2/opencv.hpp>  
  2 #include <opencv2/legacy/compat.hpp>  
  3 using namespace std;
  4 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")  
  5 void FillWhite(IplImage *pImage)
  6 {
  7     cvRectangle(pImage, cvPoint(0, 0), cvPoint(pImage->width, pImage->height), CV_RGB(255, 255, 255), CV_FILLED);
  8 }
  9 // 建立灰度圖像的直方圖  
 10 CvHistogram* CreateGrayImageHist(IplImage **ppImage)
 11 {
 12     int nHistSize = 256;
 13     float fRange[] = { 0, 255 };  //灰度級的範圍    
 14     float *pfRanges[] = { fRange };
 15     CvHistogram *pcvHistogram = cvCreateHist(1, &nHistSize, CV_HIST_ARRAY, pfRanges);
 16     cvCalcHist(ppImage, pcvHistogram);
 17     return pcvHistogram;
 18 }
 19 // 根據直方圖建立直方圖圖像  
 20 IplImage* CreateHisogramImage(int nImageWidth, int nScale, int nImageHeight, CvHistogram *pcvHistogram)
 21 {
 22     IplImage *pHistImage = cvCreateImage(cvSize(nImageWidth * nScale, nImageHeight), IPL_DEPTH_8U, 1);
 23     FillWhite(pHistImage);
 24 
 25     //統計直方圖中的最大直方塊  
 26     float fMaxHistValue = 0;
 27     cvGetMinMaxHistValue(pcvHistogram, NULL, &fMaxHistValue, NULL, NULL);
 28 
 29     //分別將每一個直方塊的值繪製到圖中  
 30     int i;
 31     for (i = 0; i < nImageWidth; i++)
 32     {
 33         float fHistValue = cvQueryHistValue_1D(pcvHistogram, i); //像素爲i的直方塊大小  
 34         int nRealHeight = cvRound((fHistValue / fMaxHistValue) * nImageHeight);  //要繪製的高度  
 35         cvRectangle(pHistImage,
 36             cvPoint(i * nScale, nImageHeight - 1),
 37             cvPoint((i + 1) * nScale - 1, nImageHeight - nRealHeight),
 38             cvScalar(i, 0, 0, 0),
 39             CV_FILLED
 40             );
 41     }
 42     return pHistImage;
 43 }
 44 int main(int argc, char** argv)
 45 {
 46     const char *pstrWindowsSrcTitle = "原圖";
 47     const char *pstrWindowsGrayTitle = "灰度圖";
 48     const char *pstrWindowsHistTitle = "直方圖";
 49     const char *pstrWindowsGrayEqualizeTitle = "灰度圖-均衡化後";
 50     const char *pstrWindowsHistEqualizeTitle = "直方圖-均衡化後";
 51 
 52     // 從文件中加載原圖  
 53     IplImage *pSrcImage = cvLoadImage("xh.jpg", CV_LOAD_IMAGE_UNCHANGED);
 54     IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
 55     IplImage *pGrayEqualizeImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
 56 
 57     // 灰度圖  
 58     cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
 59     // 直方圖圖像數據  
 60     int nHistImageWidth = 255;
 61     int nHistImageHeight = 150;
 62     int nScale = 2;
 63 
 64     // 灰度直方圖及直方圖圖像  
 65     CvHistogram *pcvHistogram = CreateGrayImageHist(&pGrayImage);
 66     IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogram);
 67 
 68     // 均衡化  
 69     cvEqualizeHist(pGrayImage, pGrayEqualizeImage);
 70 
 71     // 均衡化後的灰度直方圖及直方圖圖像  
 72     CvHistogram *pcvHistogramEqualize = CreateGrayImageHist(&pGrayEqualizeImage);
 73     IplImage *pHistEqualizeImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogramEqualize);
 74 
 75 
 76     // 顯示
 77     cvNamedWindow(pstrWindowsGrayTitle, CV_WINDOW_AUTOSIZE);
 78     cvNamedWindow(pstrWindowsHistTitle, CV_WINDOW_AUTOSIZE);
 79     cvNamedWindow(pstrWindowsGrayEqualizeTitle, CV_WINDOW_AUTOSIZE);
 80     cvNamedWindow(pstrWindowsHistEqualizeTitle, CV_WINDOW_AUTOSIZE);
 81     //顯示代碼….
 82     cvShowImage(pstrWindowsGrayTitle, pGrayImage);//顯示灰度圖
 83     cvShowImage(pstrWindowsHistTitle, pHistImage);//顯示灰度直方圖
 84     cvShowImage(pstrWindowsGrayEqualizeTitle, pGrayEqualizeImage);//顯示均衡化後的灰度圖
 85     cvShowImage(pstrWindowsHistEqualizeTitle, pHistEqualizeImage);//顯示均衡化後的灰度直方圖
 86 
 87     //顯示代碼….
 88     cvWaitKey(0);
 89 
 90     //回收資源代碼…
 91     cvDestroyWindow(pstrWindowsGrayTitle);
 92     cvDestroyWindow(pstrWindowsHistTitle);
 93     cvDestroyWindow(pstrWindowsGrayEqualizeTitle);
 94     cvDestroyWindow(pstrWindowsHistEqualizeTitle);
 95 
 96     cvReleaseImage(&pSrcImage);
 97     cvReleaseImage(&pHistImage);
 98     cvReleaseImage(&pGrayEqualizeImage);
 99     cvReleaseImage(&pHistEqualizeImage);
100 
101     return 0;

 輸出【均衡化後進行輪廓檢測效果會更佳】:

十、彩色直方圖均衡化

主要函數介紹:

1)cvSplit

函數功能:分割多通道數組成幾個單通道數組或者從數組中提取一個通道。

函數原型:

/* Splits a multi-channel array into the set of single-channel arrays or

   extracts particular [color] plane */

CVAPI(void)  cvSplit(

  const CvArr* src,

  CvArr* dst0,

  CvArr* dst1,

  CvArr* dst2,

  CvArr* dst3

);

參數說明:

第一個參數表示輸入的多通道數組即輸入圖像。

第二,三,四,五個參數分別表示輸出的單通道數組。

 

2)cvMerge

函數功能:分割多通道數組成幾個單通道數組或者從數組中提取一個通道。

函數原型:

/* Merges a set of single-channel arrays into the single multi-channel array

   or inserts one particular [color] plane to the array */

CVAPI(void)  cvMerge(

  const CvArr* src0,

  const CvArr* src1,

  const CvArr* src2,

  const CvArr* src3,

  CvArr* dst

);

參數說明:

第一,二,三,四個參數表示輸入的單通道數組。

第五個參數分別表示合併後的多通道數組即輸出圖像。

 

 1 #include <opencv2/opencv.hpp>  
 2 using namespace std;
 3 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")  
 4 //彩色圖像的直方圖均衡化  
 5 IplImage* EqualizeHistColorImage(IplImage *pImage)
 6 {
 7     IplImage *pEquaImage = cvCreateImage(cvGetSize(pImage), pImage->depth, 3);
 8 
 9     // 原圖像分紅各通道後再均衡化,最後合併即彩色圖像的直方圖均衡化  
10     const int MAX_CHANNEL = 4;
11     IplImage *pImageChannel[MAX_CHANNEL] = { NULL };
12 
13     int i;
14     for (i = 0; i < pImage->nChannels; i++)
15         pImageChannel[i] = cvCreateImage(cvGetSize(pImage), pImage->depth, 1);
16 
17     cvSplit(pImage, pImageChannel[0], pImageChannel[1], pImageChannel[2], pImageChannel[3]);
18 
19     for (i = 0; i < pImage->nChannels; i++)
20         cvEqualizeHist(pImageChannel[i], pImageChannel[i]);
21 
22     cvMerge(pImageChannel[0], pImageChannel[1], pImageChannel[2], pImageChannel[3], pEquaImage);
23 
24     for (i = 0; i < pImage->nChannels; i++)
25         cvReleaseImage(&pImageChannel[i]);
26 
27     return pEquaImage;
28 }
29 int main(int argc, char** argv)
30 {
31     const char *pstrWindowsSrcTitle = "原圖";
32     const char *pstrWindowsHisEquaTitle = "直方圖均衡化後";
33 
34     // 從文件中加載原圖  
35     IplImage *pSrcImage = cvLoadImage("01.jpg", CV_LOAD_IMAGE_UNCHANGED);
36     IplImage *pHisEquaImage = EqualizeHistColorImage(pSrcImage);
37 
38     cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
39     cvNamedWindow(pstrWindowsHisEquaTitle, CV_WINDOW_AUTOSIZE);
40     cvShowImage(pstrWindowsSrcTitle, pSrcImage);
41     cvShowImage(pstrWindowsHisEquaTitle, pHisEquaImage);
42 
43 
44     cvWaitKey(0);
45 
46     cvDestroyWindow(pstrWindowsSrcTitle);
47     cvDestroyWindow(pstrWindowsHisEquaTitle);
48     cvReleaseImage(&pSrcImage);
49     cvReleaseImage(&pHisEquaImage);
50     return 0;
51 }

輸出:

 

結語:【opencv入門篇】到此完結,但學習永遠不會中止。網絡最大的好處就是你幾乎能夠找到你想要的任何答案,只要你想去學。站在大牛的肩上,但願咱們能看得更遠!

 

新手上路,但願老司機能多多指教:)

 

主要參考:

http://blog.csdn.net/morewindows/article/category/1291764

相關文章
相關標籤/搜索