导言本系列博客目的在于能够在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)处开始。

 #include <opencv2/opencv.hpp>
using namespace std;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
IplImage *g_pGrayImage = NULL;
const char *pstrWindowsBinaryTitle = "二值图";
const char *pstrWindowsOutLineTitle = "轮廓图";
CvSeq *g_pcvSeq = NULL; void on_trackbar(int pos)
{
// 转为二值图
IplImage *pBinaryImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, );
cvThreshold(g_pGrayImage, pBinaryImage, pos, , CV_THRESH_BINARY);
// 显示二值图
cvShowImage(pstrWindowsBinaryTitle, pBinaryImage); CvMemStorage* cvMStorage = cvCreateMemStorage();
// 检索轮廓并返回检测到的轮廓的个数
cvFindContours(pBinaryImage, cvMStorage, &g_pcvSeq); IplImage *pOutlineImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, );
int _levels = ;
cvZero(pOutlineImage);
cvDrawContours(pOutlineImage, g_pcvSeq, CV_RGB(, , ), CV_RGB(, , ), _levels);
cvShowImage(pstrWindowsOutLineTitle, pOutlineImage); cvReleaseMemStorage(&cvMStorage);
cvReleaseImage(&pBinaryImage);
cvReleaseImage(&pOutlineImage);
} int main(int argc, char** argv)
{
const char *pstrWindowsSrcTitle = "原图";
const char *pstrWindowsToolBarName = "二值化"; // 从文件中加载原图
IplImage *pSrcImage = cvLoadImage("01.jpg", CV_LOAD_IMAGE_UNCHANGED);
// 显示原图
cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsSrcTitle, pSrcImage); // 转为灰度图
g_pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, );
cvCvtColor(pSrcImage, g_pGrayImage, CV_BGR2GRAY); // 创建二值图和轮廓图窗口
cvNamedWindow(pstrWindowsBinaryTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsOutLineTitle, CV_WINDOW_AUTOSIZE); // 滑动条
int nThreshold = ;
cvCreateTrackbar(pstrWindowsToolBarName, pstrWindowsBinaryTitle, &nThreshold, , on_trackbar); on_trackbar(); cvWaitKey(); cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsBinaryTitle);
cvDestroyWindow(pstrWindowsOutLineTitle);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&g_pGrayImage);
return ;
}

输出:

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()中将接收到的参数。

 #include <opencv2/opencv.hpp>
using namespace std;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
const char *pstrWindowsMouseDrawTitle = "鼠标绘图";
// 鼠标消息的回调函数
void on_mouse(int event, int x, int y, int flags, void* param)
{
static bool s_bMouseLButtonDown = false;
static CvPoint s_cvPrePoint = cvPoint(, ); switch (event)
{
case CV_EVENT_LBUTTONDOWN:
s_bMouseLButtonDown = true;
s_cvPrePoint = cvPoint(x, y);
break; case CV_EVENT_LBUTTONUP:
s_bMouseLButtonDown = false;
break; case CV_EVENT_MOUSEMOVE:
if (s_bMouseLButtonDown)
{
CvPoint cvCurrPoint = cvPoint(x, y);
cvLine((IplImage*)param, s_cvPrePoint, cvCurrPoint, CV_RGB(, , ), );
s_cvPrePoint = cvCurrPoint;
cvShowImage(pstrWindowsMouseDrawTitle, (IplImage*)param);
}
break;
}
}
int main()
{
const int MAX_WIDTH = , MAX_HEIGHT = ;
const char *pstrSaveImageName = "Draw.jpg"; IplImage *pSrcImage = cvCreateImage(cvSize(MAX_WIDTH, MAX_HEIGHT), IPL_DEPTH_8U, );
cvSet(pSrcImage, CV_RGB(, , )); //可以用cvSet()将图像填充成白色
cvNamedWindow(pstrWindowsMouseDrawTitle, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsMouseDrawTitle, pSrcImage); cvSetMouseCallback(pstrWindowsMouseDrawTitle, on_mouse, (void*)pSrcImage); int c;
do{
c = cvWaitKey();
switch ((char)c)
{
case 'r'://r重画
cvSet(pSrcImage, CV_RGB(, , ));
cvShowImage(pstrWindowsMouseDrawTitle, pSrcImage);
break; case 's'://s保存图像
cvSaveImage(pstrSaveImageName, pSrcImage);
break;
}
} while (c > && c != ); cvDestroyWindow(pstrWindowsMouseDrawTitle);
cvReleaseImage(&pSrcImage);
return ;
}

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

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, );
cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); // 人脸识别与标记
if (pHaarCascade != NULL)
{
CvScalar FaceCirclecolors[] =
{
{ { , , } },
{ { , , } },
{ { , , } },
{ { , , } },
{ { , , } },
{ { , , } },
{ { , , } },
{ { , , } }
}; CvMemStorage *pcvMStorage = cvCreateMemStorage();
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 = ; 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 % ], );
}
cvReleaseMemStorage(&pcvMStorage);
} const char *pstrWindowsTitle = "人脸识别 ";
cvNamedWindow(pstrWindowsTitle, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsTitle, pSrcImage); cvWaitKey(); cvDestroyWindow(pstrWindowsTitle);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&pGrayImage);
return ;
}

输出:

无遮挡背景干净:

三个人也可以:

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

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 );

 #include <opencv2/opencv.hpp>
#include <opencv2/legacy/compat.hpp>
using namespace std;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") void FillWhite(IplImage *pImage)
{
cvRectangle(pImage, cvPoint(, ), cvPoint(pImage->width, pImage->height), CV_RGB(, , ), CV_FILLED);
}
// 创建灰度图像的直方图
CvHistogram* CreateGrayImageHist(IplImage **ppImage)
{
int nHistSize = ;
float fRange[] = { , }; //灰度级的范围
float *pfRanges[] = { fRange };
CvHistogram *pcvHistogram = cvCreateHist(, &nHistSize, CV_HIST_ARRAY, pfRanges);
cvCalcHist(ppImage, pcvHistogram);
return pcvHistogram;
}
// 根据直方图创建直方图图像
IplImage* CreateHisogramImage(int nImageWidth, int nScale, int nImageHeight, CvHistogram *pcvHistogram)
{
IplImage *pHistImage = cvCreateImage(cvSize(nImageWidth * nScale, nImageHeight), IPL_DEPTH_8U, );
FillWhite(pHistImage); //统计直方图中的最大直方块
float fMaxHistValue = ;
cvGetMinMaxHistValue(pcvHistogram, NULL, &fMaxHistValue, NULL, NULL); //分别将每个直方块的值绘制到图中
int i;
for (i = ; i < nImageWidth; i++)
{
float fHistValue = cvQueryHistValue_1D(pcvHistogram, i); //像素为i的直方块大小
int nRealHeight = cvRound((fHistValue / fMaxHistValue) * nImageHeight); //要绘制的高度
cvRectangle(pHistImage,
cvPoint(i * nScale, nImageHeight - ),
cvPoint((i + ) * nScale - , nImageHeight - nRealHeight),
cvScalar(i, , , ),
CV_FILLED
);
}
return pHistImage;
}
int main(int argc, char** argv)
{
const char *pstrWindowsSrcTitle = "原图";
const char *pstrWindowsGrayTitle = "灰度图";
const char *pstrWindowsHistTitle = "直方图"; // 从文件中加载原图
IplImage *pSrcImage = cvLoadImage("cyh.jpg", CV_LOAD_IMAGE_UNCHANGED);
IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, );
// 灰度图
cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); // 灰度直方图
CvHistogram *pcvHistogram = CreateGrayImageHist(&pGrayImage); // 创建直方图图像
int nHistImageWidth = ;
int nHistImageHeight = ; //直方图图像高度
int nScale = ;
IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogram); // 显示
cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsGrayTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsHistTitle, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsSrcTitle, pSrcImage);
cvShowImage(pstrWindowsGrayTitle, pGrayImage);
cvShowImage(pstrWindowsHistTitle, pHistImage); cvWaitKey(); cvReleaseHist(&pcvHistogram); cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsGrayTitle);
cvDestroyWindow(pstrWindowsHistTitle);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&pGrayImage);
cvReleaseImage(&pHistImage);
return ;
}

输出:

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))进行图像变换。

 #include <opencv2/opencv.hpp>
#include <opencv2/legacy/compat.hpp>
using namespace std;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
void FillWhite(IplImage *pImage)
{
cvRectangle(pImage, cvPoint(, ), cvPoint(pImage->width, pImage->height), CV_RGB(, , ), CV_FILLED);
}
// 创建灰度图像的直方图
CvHistogram* CreateGrayImageHist(IplImage **ppImage)
{
int nHistSize = ;
float fRange[] = { , }; //灰度级的范围
float *pfRanges[] = { fRange };
CvHistogram *pcvHistogram = cvCreateHist(, &nHistSize, CV_HIST_ARRAY, pfRanges);
cvCalcHist(ppImage, pcvHistogram);
return pcvHistogram;
}
// 根据直方图创建直方图图像
IplImage* CreateHisogramImage(int nImageWidth, int nScale, int nImageHeight, CvHistogram *pcvHistogram)
{
IplImage *pHistImage = cvCreateImage(cvSize(nImageWidth * nScale, nImageHeight), IPL_DEPTH_8U, );
FillWhite(pHistImage); //统计直方图中的最大直方块
float fMaxHistValue = ;
cvGetMinMaxHistValue(pcvHistogram, NULL, &fMaxHistValue, NULL, NULL); //分别将每个直方块的值绘制到图中
int i;
for (i = ; i < nImageWidth; i++)
{
float fHistValue = cvQueryHistValue_1D(pcvHistogram, i); //像素为i的直方块大小
int nRealHeight = cvRound((fHistValue / fMaxHistValue) * nImageHeight); //要绘制的高度
cvRectangle(pHistImage,
cvPoint(i * nScale, nImageHeight - ),
cvPoint((i + ) * nScale - , nImageHeight - nRealHeight),
cvScalar(i, , , ),
CV_FILLED
);
}
return pHistImage;
}
int main(int argc, char** argv)
{
const char *pstrWindowsSrcTitle = "原图";
const char *pstrWindowsGrayTitle = "灰度图";
const char *pstrWindowsHistTitle = "直方图";
const char *pstrWindowsGrayEqualizeTitle = "灰度图-均衡化后";
const char *pstrWindowsHistEqualizeTitle = "直方图-均衡化后"; // 从文件中加载原图
IplImage *pSrcImage = cvLoadImage("xh.jpg", CV_LOAD_IMAGE_UNCHANGED);
IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, );
IplImage *pGrayEqualizeImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, ); // 灰度图
cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
// 直方图图像数据
int nHistImageWidth = ;
int nHistImageHeight = ;
int nScale = ; // 灰度直方图及直方图图像
CvHistogram *pcvHistogram = CreateGrayImageHist(&pGrayImage);
IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogram); // 均衡化
cvEqualizeHist(pGrayImage, pGrayEqualizeImage); // 均衡化后的灰度直方图及直方图图像
CvHistogram *pcvHistogramEqualize = CreateGrayImageHist(&pGrayEqualizeImage);
IplImage *pHistEqualizeImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogramEqualize); // 显示
cvNamedWindow(pstrWindowsGrayTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsHistTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsGrayEqualizeTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsHistEqualizeTitle, CV_WINDOW_AUTOSIZE);
//显示代码….
cvShowImage(pstrWindowsGrayTitle, pGrayImage);//显示灰度图
cvShowImage(pstrWindowsHistTitle, pHistImage);//显示灰度直方图
cvShowImage(pstrWindowsGrayEqualizeTitle, pGrayEqualizeImage);//显示均衡化后的灰度图
cvShowImage(pstrWindowsHistEqualizeTitle, pHistEqualizeImage);//显示均衡化后的灰度直方图 //显示代码….
cvWaitKey(); //回收资源代码…
cvDestroyWindow(pstrWindowsGrayTitle);
cvDestroyWindow(pstrWindowsHistTitle);
cvDestroyWindow(pstrWindowsGrayEqualizeTitle);
cvDestroyWindow(pstrWindowsHistEqualizeTitle); cvReleaseImage(&pSrcImage);
cvReleaseImage(&pHistImage);
cvReleaseImage(&pGrayEqualizeImage);
cvReleaseImage(&pHistEqualizeImage); return ;

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

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

);

参数说明:

第一,二,三,四个参数表示输入的单通道数组。

第五个参数分别表示合并后的多通道数组即输出图像。

 #include <opencv2/opencv.hpp>
using namespace std;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
//彩色图像的直方图均衡化
IplImage* EqualizeHistColorImage(IplImage *pImage)
{
IplImage *pEquaImage = cvCreateImage(cvGetSize(pImage), pImage->depth, ); // 原图像分成各通道后再均衡化,最后合并即彩色图像的直方图均衡化
const int MAX_CHANNEL = ;
IplImage *pImageChannel[MAX_CHANNEL] = { NULL }; int i;
for (i = ; i < pImage->nChannels; i++)
pImageChannel[i] = cvCreateImage(cvGetSize(pImage), pImage->depth, ); cvSplit(pImage, pImageChannel[], pImageChannel[], pImageChannel[], pImageChannel[]); for (i = ; i < pImage->nChannels; i++)
cvEqualizeHist(pImageChannel[i], pImageChannel[i]); cvMerge(pImageChannel[], pImageChannel[], pImageChannel[], pImageChannel[], pEquaImage); for (i = ; i < pImage->nChannels; i++)
cvReleaseImage(&pImageChannel[i]); return pEquaImage;
}
int main(int argc, char** argv)
{
const char *pstrWindowsSrcTitle = "原图";
const char *pstrWindowsHisEquaTitle = "直方图均衡化后"; // 从文件中加载原图
IplImage *pSrcImage = cvLoadImage("01.jpg", CV_LOAD_IMAGE_UNCHANGED);
IplImage *pHisEquaImage = EqualizeHistColorImage(pSrcImage); cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsHisEquaTitle, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsSrcTitle, pSrcImage);
cvShowImage(pstrWindowsHisEquaTitle, pHisEquaImage); cvWaitKey(); cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsHisEquaTitle);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&pHisEquaImage);
return ;
}

输出:

结语:【opencv入门篇】到此完结,但学习永远不会停止。网络最大的好处就是你几乎可以找到你想要的任何答案,只要你想去学。站在大牛的肩上,希望我们能看得更远!

新手上路,希望老司机能多多指教:)

主要参考:

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

【opencv入门篇】 10个程序快速上手opencv【下】的更多相关文章

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

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

  2. CSS快速入门基础篇,让你快速上手(附带代码案例)

    1.什么是CSS 学习思路 CSS是什么 怎么去用CSS(快速上手) CSS选择器(难点也是重点) 网页美化(文字,阴影,超链接,列表,渐变等) 盒子模型 浮动 定位 网页动画(特效效果) 项目格式: ...

  3. 【Python五篇慢慢弹】快速上手学python

    快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...

  4. 入门python:《Python编程快速上手让繁琐工作自动化》中英文PDF+代码

    入门推荐学习<python编程快速上手>前6章是python的基础知识,通俗易懂地讲解基础,初学者容易犯错的地方,都会指出来.从第三章开始,每章都有一个实践项目,用来巩固前面所学的知识. ...

  5. 1.5快速上手OpenCV图像处理

    在上一节中,已经完成了OPENCV的配置,在本节接触几个Opencv图像处理相关的程序,看看opencv用简洁的代码能够实现哪些有趣的图像效果. 1.第一个程序:图像显示 #include<op ...

  6. 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8组件结构全解析

    转自: http://blog.csdn.net/poem_qianmo/article/details/19925819 本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:ht ...

  7. 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8 or OpenCV 2.4.9组件结构全解析

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/19925819 作者:毛星云 ...

  8. 【opencv入门篇】快速在VS上配置opencv

    环境配置:win7-32 + opencv2.4.6 + vs2013 注意:无论电脑是32位还是64位,配置opencv库目录时选择x84文件夹!因为编译都是使用32位编译:如果选用X64,则程序运 ...

  9. Webpack 快速上手(下)

    杏仁前端开发工程师,代码洁癖症早期,关注前端技术. 由于文章篇幅较长,为了更好的阅读体验,本文分为上.中.下三篇: 上篇介绍了什么是 webpack,为什么需要 webpack,webpack 的文件 ...

随机推荐

  1. jquery清空textarea等输入框

    转载自:http://blog.csdn.net/dyllove98/article/details/8870307 完整示例:http://www.keleyi.com/keleyi/phtml/c ...

  2. [转]PHP 5.3.0以上推荐使用mysqlnd驱动

    我们一般的使用场景,比较少关注PHP版本的问题,而且市面上提供的PHP运行环境都还是5.2系列的. 原文:http://zhangxugg-163-com.iteye.com/blog/1894990 ...

  3. Linux网络编程wait()和waitpid()的讲解

    本文讲的是关于wait和waitpid两者的区别与联系.为避免僵尸进程的产生,无论我们什么时候创建子进程时,主进程都需要等待子进程返回,以便对子进程进行清理.为此,我们在服务器程序中添加SIGCHLD ...

  4. am335x -- kio 控制接口

    //example #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include < ...

  5. 2018-11-17 js的this引起的血案

    js的this. 昨天测试,删除商品会报错,马上去测了一把,的确会报错.为毛线呢? SubOrderItem: function (orderitem) { if (orderitem.ordernu ...

  6. 概率论 - BZOJ - 4001 TJOI2015

    TJOI2015 Problem's Link ---------------------------------------------------------------------------- ...

  7. 关于Unity中的transform组件(三)

    game_root节点下右一个Cube子节点,和一个Sphere节点,脚本挂载在game_root下 四元数:(1)Quaternion rot (2)this.cube.rotation 欧拉角:V ...

  8. iBATIS SQL Maps

    让我们重回到车辆管理系统和张三的故事中. 在 iBATIS SQL Maps 的世界里也存在 one-to-many.many-to-one 的关系,想必你已经对这些概念驾轻就熟了.好!还是每个 Pe ...

  9. 10条建议帮助你创建更好的jQuery插件

    本文总结了帮助你创建更好jQuery插件的10条建议.分享给大家供大家参考.具体说明如下: 在开发过很多 jQuery 插件以后,我慢慢的摸索出了一套开发jQuery插件比较标准的结构和模式.这样我就 ...

  10. Unity中用触摸控制物体旋转和放大

    using UnityEngine;using System.Collections;using System.IO; public class ScaleAndRotate : MonoBehavi ...