导言:本系列博客目的在于能够在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入门篇】到此完结,但学习永远不会停止。网络最大的好处就是你几乎可以找到你想要的任何答案,只要你想去学。站在大牛的肩上,希望我们能看得更远!
新手上路,希望老司机能多多指教:)
主要参考: