【opencv入门篇】 10个程序快速上手opencv【下】

导言本系列博客目的在于能够在vs快速上手opencv,理论知识涉及较少,大家有兴趣可以查阅其他博客深入了解相关的理论知识,本博客后续也会对图像方向的理论进一步分析,敬请期待:)

上篇传送:http://www.cnblogs.com/always-chang/p/6170727.html

学习思维导图:

5、图像轮廓检测

主要函数介绍:

1)cvFindContours

函数功能:对图像进行轮廓检测,这个函数将生成一条链表以保存检测出的各个轮廓信息,并传出指向这条链表表头的指针。

函数原型:

int cvFindContours(

  CvArr* image,

  CvMemStorage* storage,

  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 }

输出:

 

6、鼠标绘图

关键函数介绍

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 }

画的太丑,就不贴了。。。

 

7、人脸检测

使用人脸的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;
}

输出:

无遮挡背景干净:

三个人也可以:

有遮挡就不行了,与商业化的软件还是有很大差别的。。

 

 8、灰度直方图

主要函数介绍:

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 }

输出:

 

9、灰度直方图均衡化

主要函数介绍:

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;

 输出【均衡化后进行轮廓检测效果会更佳】:

10、彩色直方图均衡化

主要函数介绍:

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

 

posted @ 2016-12-13 18:22  Acelit  阅读(8665)  评论(0编辑  收藏  举报