zoukankan      html  css  js  c++  java
  • 【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 ypes_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
    ", 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

  • 相关阅读:
    ACM题目————最短路径问题
    ACM题目————已知前序和中序求后序
    ACM题目————数素数
    ACM题目————玩转二叉树
    ACM题目————二叉树的遍历
    ACM题目————士兵杀敌(四)
    ACM题目————士兵杀敌(三)
    ACM题目————星际之门(一)
    ACM第四站————最小生成树(克鲁斯卡尔算法)
    ACM第四站————最小生成树(普里姆算法)
  • 原文地址:https://www.cnblogs.com/always-chang/p/6170859.html
Copyright © 2011-2022 走看看