【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)处开始。
#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【下】的更多相关文章
- 【opencv入门篇】 10个程序快速上手opencv【上】
导言:本系列博客目的在于能够在vs快速上手opencv,理论知识涉及较少,大家有兴趣可以查阅其他博客深入了解相关的理论知识,本博客后续也会对图像方向的理论进一步分析,敬请期待:) PS:官方文档永远是 ...
- CSS快速入门基础篇,让你快速上手(附带代码案例)
1.什么是CSS 学习思路 CSS是什么 怎么去用CSS(快速上手) CSS选择器(难点也是重点) 网页美化(文字,阴影,超链接,列表,渐变等) 盒子模型 浮动 定位 网页动画(特效效果) 项目格式: ...
- 【Python五篇慢慢弹】快速上手学python
快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...
- 入门python:《Python编程快速上手让繁琐工作自动化》中英文PDF+代码
入门推荐学习<python编程快速上手>前6章是python的基础知识,通俗易懂地讲解基础,初学者容易犯错的地方,都会指出来.从第三章开始,每章都有一个实践项目,用来巩固前面所学的知识. ...
- 1.5快速上手OpenCV图像处理
在上一节中,已经完成了OPENCV的配置,在本节接触几个Opencv图像处理相关的程序,看看opencv用简洁的代码能够实现哪些有趣的图像效果. 1.第一个程序:图像显示 #include<op ...
- 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8组件结构全解析
转自: http://blog.csdn.net/poem_qianmo/article/details/19925819 本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:ht ...
- 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8 or OpenCV 2.4.9组件结构全解析
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/19925819 作者:毛星云 ...
- 【opencv入门篇】快速在VS上配置opencv
环境配置:win7-32 + opencv2.4.6 + vs2013 注意:无论电脑是32位还是64位,配置opencv库目录时选择x84文件夹!因为编译都是使用32位编译:如果选用X64,则程序运 ...
- Webpack 快速上手(下)
杏仁前端开发工程师,代码洁癖症早期,关注前端技术. 由于文章篇幅较长,为了更好的阅读体验,本文分为上.中.下三篇: 上篇介绍了什么是 webpack,为什么需要 webpack,webpack 的文件 ...
随机推荐
- 大数据(12) - Scala安装与IDE相关配置
一 Scala简述 统计世界top100大学计算机系年级前三名,从初中开始编程,学过20多种语言,最后认为Scala最难.好了,我们开始享受这个过程把:). 二 Scala安装与配置 Scala需 ...
- Ubuntu下安装SSH服务
判断是否安装ssh服务,可以通过如下命令进行: $ ssh localhost ssh: connect to host localhost port 22: Connection refused 如 ...
- 用javascript技术读取注册表中软件安装位置并启动本地软件
1.首先读取注册表中本地软件安装的位置,如果未安装则无就跳转到下载页面. 2.启动软件,关闭页面. 3.如报错提示. <SCRIPT language=javascript> <! ...
- Yarn概述
转自:http://liujiacai.net/blog/2014/09/07/yarn-intro/ Yarn是随着hadoop发展而催生的新框架,全称是Yet Another Resource N ...
- Unity基于DFGUI的TreeView设计
using UnityEngine; using System.Collections; public class Item { public string Id; public string Nam ...
- java内存溢出怎么解决
java.lang.OutOfMemoryError这个错误我相信大部分开发人员都有遇到过,产生该错误的原因大都出于以下原因:JVM内存过小.程序不严密,产生了过多的垃圾. 导致OutOfMemory ...
- oracle oci 调用 1
http://blog.163.com/earth_of_fire/blog/static/1368943200791211622278/(总结) http://blog.163.com/earth_ ...
- 【BZOJ】2555: SubString(后缀自动机)
http://www.lydsy.com/JudgeOnline/problem.php?id=2555 学到了如何快速维护right值orz (不过这仍然是暴力维护,可以卡到O(n) 首先我们在加一 ...
- leetcode:Pascal's Triangle
一. 题目 经典题目,杨辉三角,输入行数.生成杨辉三角的数组. 二. 分析 首先,我们知道有例如以下规律: 1.每一行的第一个数和最后一个数都为1 2.中间的数是上面数和上面数左边的数 ...
- asp.net 动态添加多个用户控件
动态添加多个相同用户控件,并使每个用户控件获取不同的内容. 用户控件代码: 代码WebControls using System; using System.Collections.Generic; ...