admin 管理员组文章数量: 1086019
2024年4月16日发(作者:mysqldump where)
基于opencv的use摄像头视频采集程序 ...................................................................................... 1
基于opencv的两个摄像头数据采集 ............................................................................................. 3
能激发你用代码做视频的冲动程序 ............................................................................................... 6
图像反转(就是把黑的变白,白的变黑) ................................................................................. 11
图像格式的转换 ............................................................................................................................. 12
从摄像头或者AVI文件中得到视频流,对视频流进行边缘检测 ............................................ 14
采用Canny算子进行边缘检测 .................................................................................................... 15
角点检测......................................................................................................................................... 18
图像的旋转加缩放(效果很拽,用地球做就像谷歌地球似的) ............................................. 21
Log-Polar极坐标变换 ................................................................................................................... 22
对图像进行形态学操作(图像的开闭,腐蚀和膨胀运算) ..................................................... 25
用不同的核进行图像的二维滤波 ................................................................................................. 28
图像域的填充 ................................................................................................................................. 31
寻找轮廓实现视频流的运动目标检测(超推荐一下) ............................................................. 35
采用金字塔方法进行图像分割 ..................................................................................................... 40
图像的亮度变换 ............................................................................................................................. 43
单通道图像的直方图 ..................................................................................................................... 46
计算和显示彩色图像的二维色调-饱和度图像............................................................................ 48
图像的直方图均匀化 ..................................................................................................................... 51
用Hongh变换检测线段 ................................................................................................................ 53
利用Hough变换检测圆(是圆不是椭圆) ................................................................................ 57
距离变换......................................................................................................................................... 59
椭圆曲线拟合 ................................................................................................................................. 64
由点集序列或数组创建凸外形 ..................................................................................................... 68
Delaunay三角形和Voronoi划分的迭代式构造 .......................................................................... 71
利用背景建模检测运动物体(推荐) ......................................................................................... 78
运动模板检测(摄像头) ............................................................................................................. 81
显示如何利用Camshift算法进行彩色目标的跟踪 .................................................................... 87
基于opencv的use摄像头视频采集程序
准备工作:你得把opencv库装到电脑上,并把各种头文件,源文件,lib库都
连到vc上,然后设置一下系统环境变量,这里这方面就不说了,好像我前面的
文章有说过,不懂也可百度一下。
建立一个基于WIN32控制台的工程CameraUSB,在新建一个c++元文件,写代码:
#include "cxcore.h"
#include "cvcam.h"
#include "windows.h"
#include "highgui.h"
void callback(IplImage* image);
int main()
{
int ncams=cvcamGetCamerasCount( );//返回可以访问的摄像头数目
HWND MyWin;
// 设置系统属性
cvcamSetProperty(0, CVCAM_PROP_ENABLE, CVCAMTRUE); //选择第一个摄像
头
//camera
cvcamSetProperty(0, CVCAM_PROP_RENDER, CVCAMTRUE); //We'll
render stream
// 在本例中
// 假设创建一个窗口,并且窗口的ID是在变量 MyWin 中定义
// MyWin 是窗口 HWND 的类型
MyWin=(HWND)cvGetWindowHandle("CameraUSB window");
cvcamSetProperty(0,CVCAM_PROP_WINDOW,&MyWin); // Selects a
window for
//video rendering
//回调函数将处理每一帧
cvcamSetProperty(0,CVCAM_PROP_CALLBACK,callback);
cvcamInit( );
cvcamStart( );
// 现在程序开始工作
cvWaitKey(0);
cvcamStop( );
cvcamExit( );
return 0;
}
// 在图像中画兰色水平线
void callback(IplImage* image)
{
IplImage* image1 = image;
int i,j;
assert (image);
for(i=0; i
{
for(j=(image1->widthStep)*i;
j<(image1->widthStep)*(i+1);
j+=image1->nChannels)
{
image1->imageData[j] = (char)255;
}
image1->imageData[j+1] = 0;
image1->imageData[j+2] = 0;
}
}
嘿嘿,就这么简单就完事了。
不懂可留言问
基于opencv的两个摄像头数据采集
实现功能:同时采集两路USB摄像头数据,并显示,具有图片保存功能(点击左
键保存图片,并暂停视频;右键继续视频)。步骤就不说了,很简单,直接放代
码了:
#include
#include
#include
#include "stdio.h"
#include
void StereoCallback(IplImage *frame1,IplImage *frame2);
void onMouse1(int Event,int x,int y,int flags,void *param);
void onMouse2(int Event,int x,int y,int flags,void *param);
IplImage *image1,*image2;
char *strleft[4]={"","","",""};
char
*strright[4]={"","","",""};
void main()
{
HWND CaptureWindow1=0; //不赋值也行
HWND CaptureWindow2=0;
//int ncams=cvcamGetCamerasCount(); //获取摄像头的个数,在这里可有可无
//用对话框的形式来选取摄像头
int *CameraNumber;
int nSelected = cvcamSelectCamera(&CameraNumber);
/* //灰色图像
image1=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,1);
image2=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,1);
*/
//彩色图像
image1=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,3);
image2=cvCreateImage(cvSize(320,240),IPL_DEPTH_8U,3);
//初始化两个摄像头
cvNamedWindow("cvcam1 Window",1);
CaptureWindow1=(HWND)cvGetWindowHandle("cvcam1
Window");
cvcamSetProperty(CameraNumber[0], CVCAM_PROP_ENABLE,
CVCAMTRUE);
cvcamSetProperty(CameraNumber[0], CVCAM_PROP_RENDER,
CVCAMTRUE);
cvcamSetProperty(CameraNumber[0], CVCAM_PROP_WINDOW,
&CaptureWindow1);
// cvSetMouseCallback("cvcam1 Window",onMouse1,0);
cvNamedWindow("cvcam2 Window",1);
CaptureWindow2=(HWND)cvGetWindowHandle("cvcam2
Window");
cvcamSetProperty(CameraNumber[1], CVCAM_PROP_ENABLE,
CVCAMTRUE);
cvcamSetProperty(CameraNumber[1], CVCAM_PROP_RENDER,
CVCAMTRUE);
cvcamSetProperty(CameraNumber[1], CVCAM_PROP_WINDOW,
&CaptureWindow2);
// cvSetMouseCallback("cvcam2 Window",onMouse2,0);
//让两个摄像头同步
cvcamSetProperty(CameraNumber[0],CVCAM_STEREO_CALLBACK,(void*)&S
tereoCallback);
//启动程序
cvcamInit();
cvcamStart();
cvSetMouseCallback("cvcam1 Window",onMouse1,0);
cvSetMouseCallback("cvcam2 Window",onMouse2,0);
cvWaitKey(0);
cvcamStop();
free(CameraNumber);
cvcamExit();
cvDestroyWindow("cvcam1 Window");
cvDestroyWindow("cvcam2 Window");
}
void StereoCallback(IplImage* frame1,IplImage *frame2)
{
/* //把图像转换成灰度图并保存到image中
cvCvtColor(frame1,image1,CV_RGB2GRAY);
cvCvtColor(frame2,image2,CV_RGB2GRAY);
*/
//拷贝图像到全局变量image中 该函数这样用存在问题
// cvCopy(frame1,image1);
// cvCopy(frame2,image2);
image1=cvCloneImage(frame1);
image2=cvCloneImage(frame2);
//对截取的图像翻转
cvFlip(image1,image1,0);
cvFlip(image2,image2,0);
}
void onMouse1(int Event,int x,int y,int flags,void *param)
{
static int num=0;
if(Event==CV_EVENT_LBUTTONDOWN)
{
if(num==4)num=0;//只是固定定义了保存4张图片,为了不让程序非法而
设置的复原
cvcamPause();
//图像保存
cvSaveImage(strleft[num],image1);
// cvSaveImage(strright[num],image2);
// cvSaveImage("",image1);
// cvSaveImage("",image2);
}
if(Event==CV_EVENT_RBUTTONDOWN)
{
cvcamResume();
num++;
}
}
void onMouse2(int Event,int x,int y,int flags,void *param)
{
static int num=0;
if(Event==CV_EVENT_LBUTTONDOWN)
{
if(num==4)num=0;//只是固定定义了保存4张图片,为了不让程序非法而
设置的复原
cvcamPause();
//图像保存
// cvSaveImage(strleft[num],image1);
cvSaveImage(strright[num],image2);
// cvSaveImage("",image1);
// cvSaveImage("",image2);
}
}
if(Event==CV_EVENT_RBUTTONDOWN)
{
cvcamResume();
num++;
}
能激发你用代码做视频的冲动程序
这个程序是基于opencv的,连接库就不说了,直接建立一个基于win32的控制
台程序,写代码就OK了。
/* 程序名:
功能:展示OpenCV的图像绘制功能
*/
#include "cv.h"
#include "highgui.h"
#include
#include
#define NUMBER 100
#define DELAY 5
char wndname[] = "Drawing Demo";
CvScalar random_color(CvRNG* rng) //函数 cvRNG 初始化随机数生成器并返
回其状态,RNG 随机数生成器
{
int icolor = cvRandInt(rng); //函数 cvRandInt 返回均匀分布的随
机 32-bit 无符号整型值并更新 RNG 状态
return CV_RGB(icolor&255, (icolor>>8)&255, (icolor>>16)&255); //
创建 一个色彩值
}
int main( int argc, char** argv )
{
int line_type = CV_AA; // change it to 8 to see non-antialiased
graphics
int i;
CvPoint pt1,pt2; //基于二维整形坐标轴的点
double angle;
CvSize sz; //矩形框大小,以像素为精度
CvPoint ptt[6];
CvPoint* pt[2];
int arr[2];
CvFont font;
CvRNG rng;
int width = 1000, height = 700;
int width3 = width*3, height3 = height*3;
CvSize text_size;
int ymin = 0;
// Load the source image
IplImage* image = cvCreateImage( cvSize(width,height), 8, 3 );
IplImage* image2;
// Create a window
cvNamedWindow(wndname, 1 );
cvZero( image ); //#define cvZero cvSetZero void
cvSetZero( CvArr* arr ); arr 要被清空数组
cvShowImage(wndname,image);
rng = cvRNG((unsigned)-1);
pt[0] = &(ptt[0]);
pt[1] = &(ptt[3]);
arr[0] = 3;
arr[1] = 3;
for (i = 0; i< NUMBER; i++)
{
pt1.x=cvRandInt(&rng) % width3 - width;
pt1.y=cvRandInt(&rng) % height3 - height;
pt2.x=cvRandInt(&rng) % width3 - width;
pt2.y=cvRandInt(&rng) % height3 - height;
cvLine( image, pt1, pt2, random_color(&rng),
cvRandInt(&rng)%10, line_type, 0 );//绘制连接两个点的线段
cvShowImage(wndname,image);
cvWaitKey(DELAY);
}
for (i = 0; i< NUMBER; i++)
{
pt1.x=cvRandInt(&rng) % width3 - width;
pt1.y=cvRandInt(&rng) % height3 - height;
pt2.x=cvRandInt(&rng) % width3 - width;
pt2.y=cvRandInt(&rng) % height3 - height;
cvRectangle( image,pt1, pt2, random_color(&rng),
cvRandInt(&rng)%10-1, line_type, 0 );//绘制简单、指定粗细或者带填充的
矩形
cvShowImage(wndname,image);
cvWaitKey(DELAY);
}
for (i = 0; i< NUMBER; i++)
{
pt1.x=cvRandInt(&rng) % width3 - width;
pt1.y=cvRandInt(&rng) % height3 - height;
=cvRandInt(&rng)%200;
=cvRandInt(&rng)%200;
angle = (cvRandInt(&rng)%1000)*0.180;
cvEllipse( image, pt1, sz, angle, angle - 100, angle + 200,
random_color(&rng),
cvRandInt(&rng)%10-1, line_type, 0 );//函数cvEllipse用来绘制或者填充
一个简单的椭圆弧或椭圆扇形
cvShowImage(wndname,image);
cvWaitKey(DELAY);
}
for (i = 0; i< NUMBER; i++)
{
pt[0][0].x=cvRandInt(&rng) % width3 - width;
pt[0][0].y=cvRandInt(&rng) % height3 - height;
pt[0][1].x=cvRandInt(&rng) % width3 - width;
pt[0][1].y=cvRandInt(&rng) % height3 - height;
pt[0][2].x=cvRandInt(&rng) % width3 - width;
pt[0][2].y=cvRandInt(&rng) % height3 - height;
pt[1][0].x=cvRandInt(&rng) % width3 - width;
pt[1][0].y=cvRandInt(&rng) % height3 - height;
pt[1][1].x=cvRandInt(&rng) % width3 - width;
pt[1][1].y=cvRandInt(&rng) % height3 - height;
pt[1][2].x=cvRandInt(&rng) % width3 - width;
pt[1][2].y=cvRandInt(&rng) % height3 - height;
cvPolyLine( image, pt, arr, 2, 1, random_color(&rng),
cvRandInt(&rng)%10, line_type, 0 );//函数cvPolyLine 绘制一个简单的或
多样的多角曲线
cvShowImage(wndname,image);
cvWaitKey(DELAY);
}
for (i = 0; i< NUMBER; i++)
{
pt[0][0].x=cvRandInt(&rng) % width3 - width;
pt[0][0].y=cvRandInt(&rng) % height3 - height;
pt[0][1].x=cvRandInt(&rng) % width3 - width;
pt[0][1].y=cvRandInt(&rng) % height3 - height;
pt[0][2].x=cvRandInt(&rng) % width3 - width;
pt[0][2].y=cvRandInt(&rng) % height3 - height;
pt[1][0].x=cvRandInt(&rng) % width3 - width;
pt[1][0].y=cvRandInt(&rng) % height3 - height;
pt[1][1].x=cvRandInt(&rng) % width3 - width;
pt[1][1].y=cvRandInt(&rng) % height3 - height;
pt[1][2].x=cvRandInt(&rng) % width3 - width;
pt[1][2].y=cvRandInt(&rng) % height3 - height;
cvFillPoly( image, pt, arr, 2, random_color(&rng),
line_type, 0 );//函数cvFillPoly用于一个单独被多变形轮廓所限定的区域内
进行填充
cvShowImage(wndname,image);
cvWaitKey(DELAY);
}
for (i = 0; i< NUMBER; i++)
{
pt1.x=cvRandInt(&rng) % width3 - width;
pt1.y=cvRandInt(&rng) % height3 - height;
cvCircle( image, pt1, cvRandInt(&rng)%300,
random_color(&rng),
cvRandInt(&rng)%10-1, line_type,
0 );//函数cvCircle绘制或填充一个给定圆心和半径的圆
cvShowImage(wndname,image);
cvWaitKey(DELAY);
}
for (i = 1; i< NUMBER; i++)
{
pt1.x=cvRandInt(&rng) % width3 - width;
pt1.y=cvRandInt(&rng) % height3 - height;
cvInitFont( &font, cvRandInt(&rng) % 8,
(cvRandInt(&rng)%100)*0.05+0.1,
(cvRandInt(&rng)%100)*0.05+0.1,
(cvRandInt(&rng)%5)*0.1, cvRound(cvRandInt(&rng)%10),
line_type );//字体结构初始化。函数 cvRound, cvFloor, cvCeil 用一种舍入
方法将输入浮点数转换成整数。 cvRound 返回和参数最接近的整数值
cvPutText( image, "Northeast Petroleum University!", pt1,
&font, random_color(&rng));//在图像中加入文本
cvShowImage(wndname,image);
cvWaitKey(DELAY);
}
cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX, 3, 3, 0.0, 5,
line_type );
cvGetTextSize( "Opencv forever!", &font, &text_size, &ymin );//
设置字符串文本的宽度和高度
pt1.x = (width - text_)/2;
pt1.y = (height + text_)/2;
image2 = cvCloneImage(image);
for( i = 0; i < 255; i++ )
{
cvSubS( image2, cvScalarAll(i), image, 0 );//函数 cvSubS
从原数组的每个元素中减去一个数量
cvPutText( image, "shentuhongfeng forever!", pt1,
&font, CV_RGB(255,i,i));
cvShowImage(wndname,image);
cvWaitKey(DELAY);
}
// Wait for a key stroke; the same function arranges events
processing
cvWaitKey(0);
cvReleaseImage(&image);
cvReleaseImage(&image2);
cvDestroyWindow(wndname);
return 0;
}
效果图:太帅了
图像反转(就是把黑的变白,白的变黑)
黑的变白了,白的变黑了
源码:
#include
#include
#include
#include
int main(int argc,char* argv[])
{
IplImage* img=0;
int height,width,step,channels;
UCHAR* data;
int i,j,k;
if(argc<2)
{
printf("Usage:InvImage
exit(0);
}
img=cvLoadImage(argv[1]);
if(!img)
{
printf("Could not load image file:%sn",argv[1]);
exit(0);
}
height=img->height;
width=img->width;
step=img->widthStep;
channels=img->nChannels;
data=(UCHAR*)img->imageData;
printf("Processing a%d*%d image with %d
channelsn",height,width,channels);
cvNamedWindow("mainWin",CV_WINDOW_AUTOSIZE);
cvMoveWindow("mainWin",100,100);
for(i=0;i for(j=0;j for(k=0;k data[i*step+j*channels+k]=255-data[i*step+j*channels+k]; cvShowImage("mainWin",img); cvWaitKey(0); cvReleaseImage(&img); return 0; } 图像格式的转换 首先要准备一张图片,和几个txt文档,把txt文档的扩展名改成一个你要把图 片转换成的格式 我用的原始图片是jpg的,txt改成bmp的 使用时,运行-cmd-cd 转到你的目录- 运行就能把图 像转换成了 源码如下: /* 程序名:convert.c 功能:图像格式的转换 */ #include #include #include int main( int argc, char** argv ) { IplImage* src; // -1: the loaded image will be loaded as is (with number of channels depends on the file). if(argc != 3) { printf("CONV: Image format convertion, support JPG,BMP,TIF,PNG,PPMn"); printf("Usage: conv srcImage dstImagen"); return 0; } if( ( strstr(argv[1],".jpg")==NULL && strstr(argv[1],".bmp")==NULL && strstr(argv[1],".tif")==NULL && strstr(argv[1],".png")==NULL && strstr(argv[1],".ppm")==NULL ) || ( strstr(argv[2],".jpg")==NULL && strstr(argv[2],".bmp")==NULL && strstr(argv[2],".tif")==NULL && strstr(argv[2],".png")==NULL && strstr(argv[2],".ppm")==NULL )) //strstr(a, b)的用法是不是在a数组 内查看是否有b数组。。。没有则输出NULL { printf("WARNING: CONV only support JPG,BMP,TIF,PPM,TGA and PPMn"); } else { if( (src=cvLoadImage(argv[1], -1))!= 0 ) { cvSaveImage( argv[2], src); cvReleaseImage(&src); printf("n Convert successfully.n"); } else { printf("n*** Read or write image fails *** n"); } } return 0; } 发现了个小问题: 原来的jpg图像只有102KB转换成bmp后变成549KB ,在运行程序把这个bmp 转成jpg又只有81KB。这真是汗死我了 从摄像头或者AVI文件中得到视频流,对视频流进行边缘检 测 /* 程序名称:laplace.c 功能:从摄像头或者AVI文件中得到视频流,对视频流进行边缘检测,并输出结 果。 */ #include "cv.h" #include "highgui.h" #include #include int main( int argc, char** argv ) { IplImage* laplace = 0; IplImage* colorlaplace = 0; IplImage* planes[3] = { 0, 0, 0 }; // 多个图像面 CvCapture* capture = 0; // 下面的语句说明在命令行执行程序时,如果指定AVI文件,那么处理 从 // AVI文件读取的视频流,如果不指定输入变量,那么处理从摄像头获取 // 的视频流 if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); else if( argc == 2 ) capture = cvCaptureFromAVI( argv[1] ); if( !capture ) { fprintf(stderr,"Could not "); return -1; } cvNamedWindow( "Laplacian", 0 ); // 循环捕捉,直到用户按键跳出循环体 for(;;) { IplImage* frame = 0; int i; frame = cvQueryFrame( capture ); if( !frame ) break; if( !laplace ) { for( i = 0; i < 3; i++ ) planes[i] = cvCreateImage( cvSize(frame->width,frame->height), 8, 1 ); laplace = cvCreateImage( cvSize(frame->width,frame->height), IPL_DEPTH_16S, 1 ); colorlaplace = cvCreateImage( cvSize(frame->width,frame->height), 8, 3 ); } cvCvtPixToPlane( frame, planes[0], planes[1], planes[2], 0 ); for( i = 0; i < 3; i++ ) { cvLaplace( planes[i], laplace, 3 ); // 3: aperture_size cvConvertScaleAbs( laplace, planes[i], 1, 0 ); // planes[] = ABS(laplace) } cvCvtPlaneToPix( planes[0], planes[1], planes[2], 0, colorlaplace ); colorlaplace->origin = frame->origin; cvShowImage("Laplacian", colorlaplace ); } if( cvWaitKey(10) >= 0 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow("Laplacian"); return 0; 采用Canny算子进行边缘检测 #include "cv.h" #include "highgui.h" char wndname[] = "Edge"; char tbarname[] = "Threshold"; int edge_thresh = 1; IplImage *image = 0, *cedge = 0, *gray = 0, *edge = 0; // 定义跟踪条的 callback 函数 void on_trackbar(int h) { cvSmooth( gray, edge, CV_BLUR, 3, 3, 0 ); cvNot( gray, edge ); } // 对灰度图像进行边缘检测 cvCanny(gray, edge, (float)edge_thresh, (float)edge_thresh*3, 3); cvZero( cedge ); // copy edge points cvCopy( image, cedge, edge ); // 显示图像 cvShowImage(wndname, cedge); int main( int argc, char** argv ) { char* filename = argc == 2 ? argv[1] : (char*)""; if( (image = cvLoadImage( filename, 1)) == 0 ) return -1; // Create the output image cedge = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 3); // 将彩色图像转换为灰度图像 gray = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1); edge = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1); cvCvtColor(image, gray, CV_BGR2GRAY); // Create a window cvNamedWindow(wndname, 1); // create a toolbar cvCreateTrackbar(tbarname, wndname, &edge_thresh, 100, on_trackbar); // Show the image on_trackbar(1); // Wait for a key stroke; the same function arranges events processing cvWaitKey(0); cvReleaseImage(&image); cvReleaseImage(&gray); cvReleaseImage(&edge); cvDestroyWindow(wndname); return 0; } /*******代码中的函数说明 1、cvSmooth,其函数声明为: cvSmooth( const void* srcarr, void* dstarr, int smoothtype,int param1, int param2, double param3 ) cvSmooth函数的作用是对图象做各种方法的图象平滑。其中,srcarr为输入图 象;dstarr为输出图象; param1为平滑操作的第一个参数;param2为平滑操作的第二个参数(如果param2 值为0,则表示它被设为param1); param3是对应高斯参数的标准差。 参数smoothtype是图象平滑的方法选择,主要的平滑方法有以下五种: CV_BLUR_NO_SCALE:简单不带尺度变换的模糊,即对每个象素在 param1×param2 领域求和。 CV_BLUR:对每个象素在param1×param2邻域求和并做尺度变换 1/ (param1?param2)。 CV_GAUSSIAN:对图像进行核大小为param1×param2的高斯卷积。 CV_MEDIAN:对图像进行核大小为param1×param1 的中值滤波(邻域必须是方 的)。 CV_BILATERAL:双向滤波,应用双向 3x3 滤波,彩色设置为param1,空间设置 为param2。 2、void cvNot(const CvArr* src,CvArr* dst); 函数cvNot()会将src中的每一个元素的每一位取反,然后把结果赋给dst。 因此,一个值为0x00的8位图像将被映射到0xff,而值为0x83的图像将被映 射到0x7c。 3、void cvCanny( const CvArr* image, CvArr* edges, double threshold1,double threshold2, int aperture_size=3 ); 采用 Canny 算法做边缘检测 image 输入图像 edges 输出的边缘图像 threshold1 第一个阈值 threshold2 第二个阈值 aperture_size Sobel 算子内核大小 4、void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL ); 在使用这个函数之前,你必须用cvCreateImage()一类的函数先开一段内存, 然后传递给dst。 cvCopy会把src中的数据复制到dst的内存中。 5、cvCreateTrackbar 创建trackbar并将它添加到指定的窗口。 int cvCreateTrackbar( const char* trackbar_name, const char* window_name, int* value, int count, CvTrackbarCallback on_change ); trackbar_name 被创建的trackbar名字。 window_name 窗口名字,这个窗口将为被创建trackbar的父对象。 value 整数指针,它的值将反映滑块的位置。这个变量指定创建时的滑块位置。 count 滑块位置的最大值。最小值一直是0。 on_change 每次滑块位置被改变的时候,被调用函数的指针。这个函数应该被声明为void Foo(int); 如果没有回调函数,这个值可以设为NULL。 函数cvCreateTrackbar用指定的名字和范围来创建trackbar(滑块或者范围控 制),指定与trackbar位置同步的变量, 并且指定当trackbar位置被改变的时候调用的回调函数。被创建的trackbar 显示在指定窗口的顶端。 */ 角点检测 原始图: 处理后图: 源代码: #include #include "cv.h" #include "highgui.h" #define max_corners 100 int main( int argc, char** argv ) { int cornerCount=max_corners; CvPoint2D32f corners[max_corners]; IplImage *srcImage = 0, *grayImage = 0, *corners1 = 0, *corners2 = 0; int i; CvScalar color = CV_RGB(255,0,0); char* filename = argc == 2 ? argv[1] : (char*)""; // 注 意相对路径 cvNamedWindow( "image", 1 ); // create HighGUI window with name "image" //Load the image to be processed srcImage = cvLoadImage(filename, 1); grayImage = cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_8U, 1); //copy the source image to copy image after converting the format cvCvtColor(srcImage, grayImage, CV_BGR2GRAY); //create empty images of same size as the copied images corners1= cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_32F, 1); corners2= cvCreateImage(cvGetSize(srcImage),IPL_DEPTH_32F, 1); cvGoodFeaturesToTrack (grayImage, corners1, corners2, corners, &cornerCount, 0.05, 5, 0, 3, // block size 0, // not use harris 0.4 ); printf("num corners found: %dn", cornerCount); // draw circles at each corner location in the gray image and //print out a list the corners if(cornerCount>0) { for (i=0; i { cvCircle(srcImage, cvPoint((int)(corners[i].x), (int)(corners[i].y)), 6, color, 2, CV_AA, 0); } } } cvShowImage( "image", srcImage ); cvReleaseImage(&srcImage); cvReleaseImage(&grayImage); cvReleaseImage(&corners1); cvReleaseImage(&corners2); cvWaitKey(0); // wait for key. The function has return 0; 友情链接一下,这是别人写的: /xiaoduo170/blog/item/ l 图像的旋转加缩放(效果很拽,用地球做就像谷歌地球似的) #include "cv.h" #include "highgui.h" #include "math.h" int main( int argc, char** argv ) { IplImage* src; /* the first command line parameter must be image file name */ if( argc==2 && (src = cvLoadImage(argv[1], -1))!=0) { IplImage* dst = cvCloneImage( src ); int delta = 1; int angle = 0; int opt = 1; // 1: 旋转加缩放 // 0: 仅仅旋转 double factor; cvNamedWindow( "src", 1 ); cvShowImage( "src", src ); for(;;) { float m[6]; // Matrix m looks like: // // [ m0 m1 m2 ] ===> [ A11 A12 b1 ] // [ m3 m4 m5 ] [ A21 A22 b2 ] // CvMat M = cvMat( 2, 3, CV_32F, m ); int w = src->width; int h = src->height; if(opt) // 旋转加缩放 factor = (cos(angle*CV_PI/180.) + 1.05)*2; else // 仅仅旋转 factor = 1; m[0] = (float)(factor*cos(-angle*2*CV_PI/180.)); m[1] = (float)(factor*sin(-angle*2*CV_PI/180.)); m[3] = -m[1]; m[4] = m[0]; // 将旋转中心移至图像中间 m[2] = w*0.5f; m[5] = h*0.5f; // dst(x,y) = A * src(x,y) + b cvGetQuadrangleSubPix( src, dst, &M);//提取象素四边形,使用子象 素精度 cvNamedWindow( "dst", 1 ); cvShowImage( "dst", dst ); if( cvWaitKey(5) == 27 ) break; angle =(int) (angle + delta) % 360; } // for-loop } return 0; } Log-Polar极坐标变换 原始图: 效果图:(正变换) 反变换: 正反变换只是函数中一个参数的不同,具体看你所需要的应用。 cvLogPolar函数可以用来模拟人类的中央视觉(foveal vision),并可以用于 物体跟踪方面的尺度及旋转不变模板的快速匹配。 源代码: #include #include int main(int argc, char** argv) { IplImage* src; if( argc == 2 && (src=cvLoadImage(argv[1],1)) != 0 ) { IplImage* dst = cvCreateImage( cvSize(256,256), 8, 3 ); IplImage* src2 = cvCreateImage( cvGetSize(src), 8, 3 ); cvLogPolar( src, dst, cvPoint2D32f(src->width/2,src->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS ); cvLogPolar( dst, src2, cvPoint2D32f(src->width/2,src->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS+CV_WARP_INVERSE_MAP ); cvNamedWindow( "log-polar", 1 ); cvShowImage( "log-polar", dst ); cvNamedWindow( "inverse log-polar", 1 ); cvShowImage( "inverse log-polar", src2 ); cvWaitKey(); } return 0; } 对图像进行形态学操作(图像的开闭,腐蚀和膨胀运算) 效果图:(什么东东长这么丑啊,汗) #include #include #include #include IplImage* src = 0; IplImage* dst = 0; IplConvKernel* element = 0; int element_shape = CV_SHAPE_RECT; //the address of variable which receives trackbar position update int max_iters = 10; int open_close_pos = 0; int erode_dilate_pos = 0; // callback function for open/close trackbar void OpenClose(int pos) { int n = open_close_pos - max_iters; int an = n > 0 ? n : -n; element = cvCreateStructuringElementEx( an*2+1, an*2+1, an, an, element_shape, 0 ); if( n < 0 ) { cvErode(src,dst,element,1); cvDilate(dst,dst,element,1); } else { cvDilate(src,dst,element,1); cvErode(dst,dst,element,1); } cvReleaseStructuringElement(&element); cvShowImage("Open/Close",dst); } // callback function for erode/dilate trackbar void ErodeDilate(int pos) { int n = erode_dilate_pos - max_iters; int an = n > 0 ? n : -n; element = cvCreateStructuringElementEx( an*2+1, an*2+1, an, an, element_shape, 0 ); if( n < 0 ) { cvErode(src,dst,element,1); } else { cvDilate(src,dst,element,1); } cvReleaseStructuringElement(&element); cvShowImage("Erode/Dilate",dst); } int main( int argc, char** argv ) { char* filename = argc == 2 ? argv[1] : (char*)""; if( (src = cvLoadImage(filename,1)) == 0 ) return -1; printf( "Hot keys: n" "tESC - quit the programn" "tr - use rectangle structuring elementn" "te - use elliptic structuring elementn" "tc - use cross-shaped structuring elementn" "tENTER - loop through all the optionsn" ); dst = cvCloneImage(src); //create windows for output images cvNamedWindow("Open/Close",1); cvNamedWindow("Erode/Dilate",1); open_close_pos = erode_dilate_pos = max_iters; cvCreateTrackbar("iterations", "Open/Close",&open_close_pos,max_iters*2+1,OpenClose); cvCreateTrackbar("iterations", "Erode/Dilate",&erode_dilate_pos,max_iters*2+1,ErodeDilate); for(;;) { int c; OpenClose(open_close_pos); ErodeDilate(erode_dilate_pos); c = cvWaitKey(0); if( (char)c == 27 ) break; if( (char)c == 'e' ) element_shape = CV_SHAPE_ELLIPSE; else if( (char)c == 'r' ) element_shape = CV_SHAPE_RECT; else if( (char)c == 'c' ) element_shape = CV_SHAPE_CROSS; else if( (char)c == 'n' ) element_shape = (element_shape + 1) % 3; } //release images cvReleaseImage(&src); cvReleaseImage(&dst); //destroy windows cvDestroyWindow("Open/Close"); cvDestroyWindow("Erode/Dilate"); return 0; } 用不同的核进行图像的二维滤波 函数cvSmooth实现各种方法的图形平滑。 一般来说,图像平滑主要是为了消除噪声。图像的常见噪声主要有加性噪声、乘 性噪声和量化噪声等。由于图像的能量主要集在低频部分,而噪声所在频段主要 在高频段,因此通常都是采用低通滤波的方法消除噪声。 函数cvFilter2D对图像做卷积运算。 对图像进行线性滤波,支持替换方式操作。当核运算部份超出输入图像时,边界 外面的像素值等于离它最近的图像像素值。 效果图: 源代码: // Filtering for Image with variaty filtering kernel // // CV_PREWITT_3x3_V A gradient filter (vertical Prewitt operator). // -1 0 1 // -1 0 1 // -1 0 1 // CV_PREWITT_3x3_H A gradient filter (horizontal Prewitt operator). // 1 1 1 // 0 0 0 // -1 -1 -1 // CV_SOBEL_3x3_V A gradient filter (vertical Sobel operator). // -1 0 1 // -2 0 2 // -1 0 1 // CV_SOBEL_3x3_H A gradient filter (horizontal Sobel operator). // 1 2 1 // 0 0 0 // -1 -2 -1 // CV_LAPLACIAN_3x3 A 3x3 Laplacian highpass filter. // -1 -1 -1 // -1 8 -1 // -1 -1 -1 // CV_LAPLACIAN_3x3 A 3x3 Laplacian highpass filter (another kernel) // This kernel is similar with function: cvLaplace with aperture_size=1 // 0 1 0 // 1 -4 1 // 0 1 0 注:直接用cvFilter2D得到的结果与 用cvLaplace得到的结果 // 略有不同 // CV_LAPLACIAN_5x5 A 5x5 Laplacian highpass filter. // -1 -3 -4 -3 -1 // -3 0 6 0 -3 // -4 6 20 6 -4 // -3 0 6 0 -3 // -1 -3 -4 -3 -1 // CV_GAUSSIAN_3x3 A 3x3 Gaussian lowpass filter. // This filter uses the kernel A/16,where // 1 2 1 // A = 2 4 2 // 1 2 1 // These filter coefficients correspond to a 2-dimensional Gaussian // distribution with standard deviation 0.85. // // CV_GAUSSIAN_5x5 A 5x5 Gaussian lowpass filter. // This filter uses the kernel A/571,where // 2 7 12 7 2 // 7 31 52 31 7 // A = 12 52 127 52 12 // 7 31 52 31 7 // 2 7 12 7 2 #include #include #include int main( int argc, char** argv ) { IplImage *src = 0, *dst = 0, *dst2 = 0; /*float k[9] = { 0, 1, 0, 1,-4, 1, 0, 1, 0}; */ float k[9] = { 1.f/16, 2.f/16, 1.f/16, 2.f/16, 4.f/16, 2.f/16, 1.f/16, 2.f/16, 1.f/16}; 这里高斯核滤波器归一化 CvMat Km; //cvInitMatHeader( &Km, 3, 3, CV_32FC1, k, CV_AUTOSTEP ); Km = cvMat( 3, 3, CV_32F, k ); // 0: force to gray image src = cvLoadImage("", 0); dst = cvCloneImage( src ); cvNamedWindow("src", 0); cvShowImage("src",src); cvNamedWindow("filtering", 0); cvFilter2D( src, dst, &Km, cvPoint(-1,-1)); cvShowImage("filtering",dst); cvWaitKey(0); cvReleaseImage( &src ); cvReleaseImage( &dst ); return 0; } // 图像域的填充 效果图: 源代码: #include "cv.h" #include "highgui.h" #include #include IplImage* color_img0; IplImage* mask; IplImage* color_img; IplImage* gray_img0 = NULL; IplImage* gray_img = NULL; int ffill_case = 1; int lo_diff = 20, up_diff = 20; int connectivity = 4; int is_color = 1; int is_mask = 0; int new_mask_val = 255; void on_mouse( int event, int x, int y, int flags, void* param ) { if( !color_img ) return; switch( event ) { case CV_EVENT_LBUTTONDOWN: { CvPoint seed = cvPoint(x,y); int lo = ffill_case == 0 ? 0 : lo_diff; int up = ffill_case == 0 ? 0 : up_diff; int flags = connectivity + (new_mask_val << 8) + (ffill_case == 1 ? CV_FLOODFILL_FIXED_RANGE : 0); int b = rand() & 255, g = rand() & 255, r = rand() & 255; CvConnectedComp comp; if( is_mask ) cvThreshold( mask, mask, 1, 128, CV_THRESH_BINARY ); if( is_color ) { CvScalar color = CV_RGB( r, g, b ); cvFloodFill( color_img, seed, color, CV_RGB( lo, lo, lo ), CV_RGB( up, up, up ), &comp, flags, is_mask ? mask : NULL ); cvShowImage( "image", color_img ); } else { CvScalar brightness = cvRealScalar((r*2 + g*7 + b + 5)/10); cvFloodFill( gray_img, seed, brightness, cvRealScalar(lo), cvRealScalar (up), &comp, flags, is_mask ? mask : NULL ); cvShowImage( "image", gray_img ); } printf("%g pixels were repaintedn", ); } } if( is_mask ) cvShowImage( "mask", mask ); } break; int main( int argc, char** argv ) { char* filename = argc >= 2 ? argv[1] : (char*)""; if( (color_img0 = cvLoadImage(filename,1)) == 0 ) return 0; printf( "Hot keys: n" "tESC - quit the programn" "tc - switch color/grayscale moden" "tm - switch mask moden" "tr - restore the original imagen" "ts - use null-range floodfilln" "tf - use gradient floodfill with fixed(absolute) rangen" "tg - use gradient floodfill with floating(relative) rangen" "t4 - use 4-connectivity moden" "t8 - use 8-connectivity moden" ); color_img = cvCloneImage( color_img0 ); gray_img0 = cvCreateImage( cvSize(color_img->width, color_img->height), 8, 1 ); cvCvtColor( color_img, gray_img0, CV_BGR2GRAY ); gray_img = cvCloneImage( gray_img0 ); mask = cvCreateImage( cvSize(color_img->width + 2, color_img->height + 2), 8, 1 ); cvNamedWindow( "image", 0 ); cvCreateTrackbar( "lo_diff", "image", &lo_diff, 255, NULL ); cvCreateTrackbar( "up_diff", "image", &up_diff, 255, NULL ); cvSetMouseCallback( "image", on_mouse, 0 ); for(;;) { int c; if( is_color ) cvShowImage( "image", color_img ); else cvShowImage( "image", gray_img ); c = cvWaitKey(0); switch( (char) c ) { case 'x1b': printf("Exiting ...n"); goto exit_main; case 'c': if( is_color ) { printf("Grayscale mode is setn"); cvCvtColor( color_img, gray_img, CV_BGR2GRAY ); is_color = 0; } else { printf("Color mode is setn"); cvCopy( color_img0, color_img, NULL ); cvZero( mask ); is_color = 1; } break; case 'm': if( is_mask ) { cvDestroyWindow( "mask" ); is_mask = 0; } else { cvNamedWindow( "mask", 0 ); cvZero( mask ); cvShowImage( "mask", mask ); is_mask = 1; } break; case 'r': printf("Original image is restoredn"); cvCopy( color_img0, color_img, NULL ); is setn"); } exit_main: cvCopy( gray_img0, gray_img, NULL ); cvZero( mask ); break; case 's': printf("Simple floodfill mode is setn"); ffill_case = 0; break; case 'f': printf("Fixed Range floodfill mode is setn"); ffill_case = 1; break; case 'g': printf("Gradient (floating range) floodfill mode ffill_case = 2; break; case '4': printf("4-connectivity mode is setn"); connectivity = 4; break; case '8': printf("8-connectivity mode is setn"); connectivity = 8; break; } cvDestroyWindow( "test" ); cvReleaseImage( &gray_img ); cvReleaseImage( &gray_img0 ); cvReleaseImage( &color_img ); cvReleaseImage( &color_img0 ); cvReleaseImage( &mask ); return 1; } 寻找轮廓实现视频流的运动目标检测(超推荐一下) 效果视频我上传了,浏览网址(个人感觉很牛,有点像生化危机里的一个场景): /m/a2epo8/2 如果上面的卡,可以连这个,就是有点发散图形: / 也不说什么了,直接给代码吧(有一句话想说,实际上如果你是拿来做实际项目 的,可能并不要学习里面的算法,直接利用里面的模板,也就是外接的调用函数 就可以了): #include "cv.h" #include "highgui.h" #include #include #include #include #include // various tracking parameters (in seconds) const double MHI_DURATION = 0.5; const double MAX_TIME_DELTA = 0.5; const double MIN_TIME_DELTA = 0.05; const int N = 3; // const int CONTOUR_MAX_AERA = 16; // ring image buffer IplImage **buf = 0; int last = 0; // temporary images IplImage *mhi = 0; // MHI: motion history image CvFilter filter = CV_GAUSSIAN_5x5; CvConnectedComp *cur_comp, min_comp; CvConnectedComp comp; CvMemStorage *storage; CvPoint pt[4]; // 参数: // img – 输入视频帧 // dst – 检测结果 void update_mhi( IplImage* img, IplImage* dst, int diff_threshold ) { double timestamp = clock()/100.; // get current time in seconds CvSize size = cvSize(img->width,img->height); // get current frame size int i, j, idx1, idx2; IplImage* silh; uchar val; float temp; IplImage* pyr = cvCreateImage( cvSize(( & -2)/2, ( & -2)/2), 8, 1 ); CvMemStorage *stor; CvSeq *cont, *result, *squares; CvSeqReader reader; if( !mhi || mhi->width != || mhi->height != ) { if( buf == 0 ) { buf = (IplImage**)malloc(N*sizeof(buf[0])); memset( buf, 0, N*sizeof(buf[0])); } for( i = 0; i < N; i++ ) { cvReleaseImage( &buf[i] ); buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 ); cvZero( buf[i] ); } cvReleaseImage( &mhi ); mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 ); cvZero( mhi ); // clear MHI at the beginning } // end of if(mhi) cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale idx1 = last; idx2 = (last + 1) % N; // index of (last - (N-1))th frame last = idx2; // 做帧差 silh = buf[idx2]; cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames // 对差图像做二值化 cvThreshold( silh, silh, 30, 255, CV_THRESH_BINARY ); // and threshold it cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI cvCvtScale( mhi, dst, 255./MHI_DURATION, (MHI_DURATION - timestamp)*255./MHI_DURATION ); cvCvtScale( mhi, dst, 255./MHI_DURATION, 0 ); // 中值滤波,消除小的噪声 cvSmooth( dst, dst, CV_MEDIAN, 3, 0, 0, 0 ); // 向下采样,去掉噪声 cvPyrDown( dst, pyr, 7 ); cvDilate( pyr, pyr, 0, 1 ); // 做膨胀操作,消除目标的不连续空洞 cvPyrUp( pyr, dst, 7 ); // // 下面的程序段用来找到轮廓 // // Create dynamic structure and sequence. stor = cvCreateMemStorage(0); cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint) , stor); // 找到所有轮廓 cvFindContours( dst, stor, &cont, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); /* for(;cont;cont = cont->h_next) { // Number point must be more than or equal to 6 (for cvFitEllipse_32f). if( cont->total < 6 ) continue; // Draw current contour. cvDrawContours(img,cont,CV_RGB(255,0,0),CV_RGB(255,0,0 ),0,1, 8, cvPoint(0,0)); } // end of for-loop: "cont" */ // 直接使用CONTOUR中的矩形来画轮廓 for(;cont;cont = cont->h_next) { CvRect r = ((CvContour*)cont)->rect; if( * > CONTOUR_MAX_AERA) // 面积小的方形抛弃掉 { cvRectangle( img, cvPoint(r.x,r.y), cvPoint(r.x + , r.y + ), CV_RGB(255,0,0), 1, CV_AA,0); } } // free memory cvReleaseMemStorage(&stor); cvReleaseImage( &pyr ); } int main(int argc, char** argv) { IplImage* motion = 0; CvCapture* capture = 0; //视频获取结构 if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) //原型:extern int isdigit(char c); //用法:#include 当c为数字0-9时,返回非零值,否则返回零。 capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); else if( argc == 2 ) capture = cvCaptureFromAVI( argv[1] ); if( capture ) { cvNamedWindow( "Motion", 1 ); for(;;) { IplImage* image; if( !cvGrabFrame( capture )) //从摄像头或者视频 文件中抓取帧 break; image = cvRetrieveFrame( capture ); //取回由函 数cvGrabFrame抓取的图像,返回由函数cvGrabFrame 抓取的图像的指针 if( image ) { if( !motion ) { motion = cvCreateImage( cvSize(image->width,image->height), 8, 1 ); cvZero( motion ); motion->origin = image->origin; ///* 0 - 顶—左结构, 1 - 底—左结构 (Windows bitmaps 风格) */ } } update_mhi( image, motion, 60 ); cvShowImage( "Motion", image ); } if( cvWaitKey(10) >= 0 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow( "Motion" ); } return 0; 采用金字塔方法进行图像分割 图像分割指的是将数字图像细分为多个图像子区域的过程,在OpenCv中实现了 三种跟图像分割相关的算法,它们分别是:分水岭分割算法、金字塔分割算法以 及均值漂移分割算法。 分水岭分割算法 分水岭分割算法需要您或者先前算法提供标记,该标记用于指定哪些大 致区域是目标,哪些大致区域是背景等等;分水岭分割算法的分割效果严重依赖 于提供的标记。OpenCv中的函数cvWatershed实现了该算法 金字塔分割算法 金字塔分割算法由cvPrySegmentation所实现,该函数的使用很简单; 需要注意的是图像的尺寸以及金字塔的层数,图像的宽度和高度必须能被2整 除,能够被2整除的次数决定了金字塔的最大层数 均值漂移分割算法 均值漂移分割算法由cvPryMeanShiftFiltering所实现,均值漂移分割 的金字塔层数只能介于[1,7]之间 友情链接一下,个人感觉比较好的这方面博客: /xrwang/archive/2010/02/28/ ml 效果图: #include "cv.h" #include "highgui.h" #include IplImage* image[2] = { 0, 0 }, *image0 = 0, *image1 = 0; CvSize size; int w0, h0,i; int threshold1, threshold2; int l,level = 4; int sthreshold1, sthreshold2; int l_comp; int block_size = 1000; float parameter; double threshold; double rezult, min_rezult; CvFilter filter = CV_GAUSSIAN_5x5; CvConnectedComp *cur_comp, min_comp; CvSeq *comp; CvMemStorage *storage; CvPoint pt1, pt2; void ON_SEGMENT(int a) { cvPyrSegmentation(image0, image1, storage, &comp, level, threshold1+1, threshold2+1); /*l_comp = comp->total; } i = 0; min_ = cvScalarAll(0); while(i { cur_comp = (CvConnectedComp*)cvGetSeqElem ( comp, i ); if(fabs(255- min_[0])> fabs(255- cur_comp->[0]) && fabs(min_[1])> fabs(cur_comp->[1]) && fabs(min_[2])> fabs(cur_comp->[2]) ) min_comp = *cur_comp; i++; }*/ cvShowImage("Segmentation", image1); int main( int argc, char** argv ) { char* filename = argc == 2 ? argv[1] : (char*)""; if( (image[0] = cvLoadImage( filename, 1)) == 0 ) return -1; cvNamedWindow("Source", 0); cvShowImage("Source", image[0]); cvNamedWindow("Segmentation", 0); storage = cvCreateMemStorage ( block_size ); image[0]->width &= -(1< image[0]->height &= -(1< image0 = cvCloneImage( image[0] ); image1 = cvCloneImage( image[0] ); // 对彩色图像进行分割 l = 1; threshold1 =255; threshold2 =30; ON_SEGMENT(1); sthreshold1 = cvCreateTrackbar("Threshold1", "Segmentation", &threshold1, 255, ON_SEGMENT); sthreshold2 = cvCreateTrackbar("Threshold2", "Segmentation", &threshold2, 255, ON_SEGMENT); cvShowImage("Segmentation", image1); cvWaitKey(0); cvDestroyWindow("Segmentation"); cvDestroyWindow("Source"); cvReleaseMemStorage(&storage ); cvReleaseImage(&image[0]); cvReleaseImage(&image0); cvReleaseImage(&image1); return 0; } 图像的亮度变换 郁闷,以前用过MatLab,很长时间没用了,都不知道怎么使了,据说做这个效 果很不错。 效果图: 源代码: #include "cv.h" #include "highgui.h" /* src and dst are grayscale, 8-bit images; Default input value: [low, high] = [0,1]; X-Direction [bottom, top] = [0,1]; Y-Direction gamma ; if adjust successfully, return 0, otherwise, return non-zero. */ int ImageAdjust(IplImage* src, IplImage* dst, double low, double high, // X方向:low and high are the intensities of src double bottom, double top, // Y方向:mapped to bottom and top of dst double gamma ) { if( low<0 && low>1 && high <0 && high>1&& bottom<0 && bottom>1 && top<0 && top>1 && low>high) return -1; double low2 = low*255; double high2 = high*255; double bottom2 = bottom*255; double top2 = top*255; double err_in = high2 - low2; double err_out = top2 - bottom2; int x,y; double val; // intensity transform for( y = 0; y < src->height; y++) { for (x = 0; x < src->width; x++) { val = ((uchar*)(src->imageData + src->widthStep*y))[x]; val = pow((val - low2)/err_in, gamma) * err_out + bottom2; if(val>255) val=255; if(val<0) val=0; // Make sure src is in the range [low,high] ((uchar*)(dst->imageData + dst->widthStep*y))[x] = (uchar) val; } } return 0; } int main( int argc, char** argv ) { IplImage *src = 0, *dst = 0; if( argc != 2 || (src=cvLoadImage(argv[1], 0)) == NULL) // force to gray image return -1; cvNamedWindow( "src", 1 ); cvNamedWindow( "result", 1 ); // Image adjust dst = cvCloneImage(src); // 输入参数 [0,0.5] 和 [0.5,1], gamma=1 if( ImageAdjust( src, dst, 0, 0.5, 0.5, 1, 1)!=0) return -1; cvShowImage( "src", src ); cvShowImage( "result", dst ); cvWaitKey(0); cvDestroyWindow("src"); cvDestroyWindow("result"); cvReleaseImage( &src ); cvReleaseImage( &dst ); return 0; } 单通道图像的直方图 原始图: 效果图: 源代码: #include "cv.h" #include "highgui.h" #include #include int main( int argc, char** argv ) { IplImage *src = 0; IplImage *histimg = 0; CvHistogram *hist = 0; int hdims = 50; // 划分HIST的个数,越高越精确 float hranges_arr[] = {0,255}; float* hranges = hranges_arr; int bin_w; float max_val; int i; if( argc != 2 || (src=cvLoadImage(argv[1], 0)) == NULL) // force to gray image return -1; cvNamedWindow( "Histogram", 0 ); cvNamedWindow( "src", 0); hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); // 计算直方图 histimg = cvCreateImage( cvSize(320,200), 8, 3 ); cvZero( histimg ); cvCalcHist( &src, hist, 0, 0 ); // 计算直方图 cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 ); // 只找最大值 cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 ); // 缩放 bin 到区间 [0,255] cvZero( histimg ); bin_w = histimg->width / hdims; // hdims: 条的个数,则 bin_w 为 条的宽度 // 画直方图 for( i = 0; i < hdims; i++ ) { double val = ( cvGetReal1D(hist->bins,i)*histimg->height/255 ); CvScalar color = CV_RGB(255,255,0); //(hsv2rgb(i*180.f/hdims); cvRectangle( histimg, cvPoint(i*bin_w,histimg->height), cvPoint((i+1)*bin_w,(int)(histimg->height - val)), color, 1, 8, 0 ); } cvShowImage( "src", src); cvShowImage( "Histogram", histimg ); cvWaitKey(0); } cvDestroyWindow("src"); cvDestroyWindow("Histogram"); cvReleaseImage( &src ); cvReleaseImage( &histimg ); cvReleaseHist ( &hist ); return 0; 计算和显示彩色图像的二维色调-饱和度图像 对这篇内容很郁闷,不知道以后用来干什么,声明一下,哥不是搞图像处理的。 (业余爱好) 效果图:(好好的一张图,给处理成人不像人,鬼不像鬼) #include #include int main( int argc, char** argv ) { IplImage* src; if( argc == 2 && (src=cvLoadImage(argv[1], 1))!= 0) { IplImage* h_plane = cvCreateImage( cvGetSize(src), 8, 1 ); IplImage* s_plane = cvCreateImage( cvGetSize(src), 8, 1 ); IplImage* v_plane = cvCreateImage( cvGetSize(src), 8, 1 ); IplImage* planes[] = { h_plane, s_plane }; IplImage* hsv = cvCreateImage( cvGetSize(src), 8, 3 ); int h_bins = 30, s_bins = 32; int hist_size[] = {h_bins, s_bins}; float h_ranges[] = { 0, 180 }; /* hue varies from 0 (~0°red) to 180 (~360°red again) */ float s_ranges[] = { 0, 255 }; /* saturation varies from 0 (black-gray-white) to 255 (pure spectrum color) */ float* ranges[] = { h_ranges, s_ranges }; int scale = 10; IplImage* hist_img = cvCreateImage( cvSize(h_bins*scale,s_bins*scale), 8, 3 ); CvHistogram* hist; float max_value = 0; int h, s; 1 ); cvCvtColor( src, hsv, CV_BGR2HSV ); cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 ); hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, cvCalcHist( planes, hist, 0, 0 ); cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 ); cvZero( hist_img ); for( h = 0; h < h_bins; h++ ) { for( s = 0; s < s_bins; s++ ) { float bin_val = cvQueryHistValue_2D( hist, h, s ); int intensity = cvRound(bin_val*255/max_value); cvRectangle( hist_img, cvPoint( h*scale, s*scale ), cvPoint( (h+1)*scale - 1, (s+1)*scale - 1), CV_RGB(intensity,intensity,inten sity), CV_FILLED ); } } cvNamedWindow( "Source", 1 ); cvShowImage( "Source", src ); cvNamedWindow( "H-S Histogram", 1 ); cvShowImage( "H-S Histogram", hist_img ); cvWaitKey(0); } } 图像的直方图均匀化 直方图均衡化算法可以归一化图像的亮度,并增强图像的对比度 效果图: 源代码: #include "cv.h" #include "highgui.h" #define HDIM 256 // bin of HIST, default = 256 int main( int argc, char** argv ) { IplImage *src = 0, *dst = 0; CvHistogram *hist = 0; int n = HDIM; double nn[HDIM]; uchar T[HDIM]; CvMat *T_mat; int x; int sum = 0; // sum of pixels of the source image 图像中象素点 的总和 double val = 0; if( argc != 2 || (src=cvLoadImage(argv[1], 0)) == NULL) // force to gray image return -1; cvNamedWindow( "source", 1 ); cvNamedWindow( "result", 1 ); // 计算直方图 hist = cvCreateHist( 1, &n, CV_HIST_ARRAY, 0, 1 ); cvCalcHist( &src, hist, 0, 0 ); // Create Accumulative Distribute Function of histgram val = 0; for ( x = 0; x < n; x++) { val = val + cvGetReal1D (hist->bins, x); nn[x] = val; } // 归一化直方图 sum = src->height * src->width; for( x = 0; x < n; x++ ) { T[x] = (uchar) (255 * nn[x] / sum); // range is [0,255] } // Using look-up table to perform intensity transform for source image dst = cvCloneImage( src ); T_mat = cvCreateMatHeader( 1, 256, CV_8UC1 ); cvSetData( T_mat, T, 0 ); // 直接调用内部函数完成 look-up-table 的过程 cvLUT( src, dst, T_mat ); cvShowImage( "source", src ); cvShowImage( "result", dst ); cvWaitKey(0); cvDestroyWindow("source"); cvDestroyWindow("result"); cvReleaseImage( &src ); cvReleaseImage( &dst ); cvReleaseHist ( &hist ); return 0; } 用Hongh变换检测线段 效果图(郁闷这么和我想的不一样啊,这是什么东东): 这幅还像点东东: 源代码: /* 这是一个命令行程序,以图像作为文件输入变量 编译时选择“#if 1”或“#if 0”,可以使用标准和概率HOUGH变换两种 方法 */ #include #include #include int main(int argc, char** argv) { IplImage* src; if( argc == 2 && (src=cvLoadImage(argv[1], 0))!= 0) { IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 ); IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 ); CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* lines = 0; int i; cvCanny( src, dst, 50, 200, 3 ); cvCvtColor( dst, color_dst, CV_GRAY2BGR ); #if 1 1, CV_PI/180, 150, 0, 0 ); 8 ); #else float* line = (float*)cvGetSeqElem(lines,i); float rho = line[0]; float theta = line[1]; CvPoint pt1, pt2; double a = cos(theta), b = sin(theta); if( fabs(a) < 0.001 ) { pt1.x = pt2.x = cvRound(rho); pt1.y = 0; pt2.y = color_dst->height; } else if( fabs(b) < 0.001 ) { pt1.y = pt2.y = cvRound(rho); pt1.x = 0; pt2.x = color_dst->width; } else { pt1.x = 0; pt1.y = cvRound(rho/b); pt2.x = cvRound(rho/a); pt2.y = 0; } cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, for( i = 0; i < lines->total; i++ ) { } lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 80, 30, 10 ); for( i = 0; i < lines->total; i++ ) { CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i); cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 ); } #endif cvNamedWindow( "Source", 1 ); cvShowImage( "Source", src ); cvNamedWindow( "Hough", 1 ); cvShowImage( "Hough", color_dst ); cvWaitKey(0); } } 利用Hough变换检测圆(是圆不是椭圆) 原始图: 效果图: 汗,不是到那个小圆是不是圆,怎么没检测出来,我的东东,怎么搞的 源代码: #include #include #include int main(int argc, char** argv) { IplImage* img; if( argc == 2 && (img=cvLoadImage(argv[1], 1))!= 0) { IplImage* gray = cvCreateImage( cvGetSize(img), 8, 1 ); CvMemStorage* storage = cvCreateMemStorage(0); cvCvtColor( img, gray, CV_BGR2GRAY ); cvSmooth( gray, gray, CV_GAUSSIAN, 9, 9 ); // smooth it, otherwise a lot of false circles may be detected CvSeq* circles = cvHoughCircles( gray, storage, CV_HOUGH_GRADIENT, 2, gray->height/4, 200, 100 ); int i; for( i = 0; i < circles->total; i++ ) { float* p = (float*)cvGetSeqElem( circles, i ); cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 3, CV_RGB(0,255,0), -1, 8, 0 ); cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), cvRound(p[2]), CV_RGB(255,0,0), 3, 8, 0 ); } cvNamedWindow( "circles", 1 ); cvShowImage( "circles", img ); cvWaitKey(0); } return 0; } 距离变换 原图: 处理后的图: 没搞明白这是怎么个距离变换,连图都不一样了这么还叫距离变换,望知道这不 剩赐教。 源代码: #include "cv.h" #include "highgui.h" #include char wndname[] = "Distance transform"; char tbarname[] = "Threshold"; int mask_size = CV_DIST_MASK_5; int build_voronoi = 0; int edge_thresh = 100; // The output and temporary images IplImage* dist = 0; IplImage* dist8u1 = 0; IplImage* dist8u2 = 0; IplImage* dist8u = 0; IplImage* dist32s = 0; IplImage* gray = 0; IplImage* edge = 0; IplImage* labels = 0; // threshold trackbar callback void on_trackbar( int dummy ) { static const uchar colors[][3] = { {0,0,0}, {255,0,0}, {255,128,0}, {255,255,0}, {0,255,0}, {0,128,255}, {0,255,255}, {0,0,255}, {255,0,255} }; int msize = mask_size; cvThreshold( gray, edge, (float)edge_thresh, (float)edge_thresh, CV_THRESH_BINARY ); if( build_voronoi ) msize = CV_DIST_MASK_5; cvDistTransform( edge, dist, CV_DIST_L2, msize, NULL, build_voronoi ? labels : NULL ); if( !build_voronoi ) { // begin "painting" the distance transform result cvConvertScale( dist, dist, 5000.0, 0 ); cvPow( dist, dist, 0.5 ); cvConvertScale( dist, dist32s, 1.0, 0.5 ); cvAndS( dist32s, cvScalarAll(255), dist32s, 0 ); cvConvertScale( dist32s, dist8u1, 1, 0 ); cvConvertScale( dist32s, dist32s, -1, 0 ); cvAddS( dist32s, cvScalarAll(255), dist32s, 0 ); cvConvertScale( dist32s, dist8u2, 1, 0 ); cvMerge( dist8u1, dist8u2, dist8u2, 0, dist8u ); // end "painting" the distance transform result } else { int i, j; for( i = 0; i < labels->height; i++ ) { int* ll = (int*)(labels->imageData + i*labels->widthStep); float* dd = (float*)(dist->imageData + i*dist->widthStep); uchar* d = (uchar*)(dist8u->imageData + i*dist8u->widthStep); for( j = 0; j < labels->width; j++ ) { int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1; int b = cvRound(colors[idx][0]); int g = cvRound(colors[idx][1]); int r = cvRound(colors[idx][2]); d[j*3] = (uchar)b; d[j*3+1] = (uchar)g; d[j*3+2] = (uchar)r; } } } cvShowImage( wndname, dist8u ); } int main( int argc, char** argv ) { char* filename = argc == 2 ? argv[1] : (char*)""; if( (gray = cvLoadImage( filename, 0 )) == 0 ) return -1; printf( "Hot keys: n" "tESC - quit the programn" "t3 - use 3x3 maskn" "t5 - use 5x5 maskn" "t0 - use precise distance transformn" "tv - switch Voronoi diagram mode on/offn" "tENTER - loop through all the modesn" ); dist = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32F, 1 ); dist8u1 = cvCloneImage( gray ); dist8u2 = cvCloneImage( gray ); dist8u = cvCreateImage( cvGetSize(gray), IPL_DEPTH_8U, 3 ); dist32s = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 ); edge = cvCloneImage( gray ); labels = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 ); cvNamedWindow( wndname, 1 ); cvCreateTrackbar( tbarname, wndname, &edge_thresh, 255, on_trackbar ); for(;;) { int c; // Call to update the view on_trackbar(0); c = cvWaitKey(0); if( (char)c == 27 ) break; if( (char)c == '3' ) mask_size = CV_DIST_MASK_3; else if( (char)c == '5' ) mask_size = CV_DIST_MASK_5; else if( (char)c == '0' ) mask_size = CV_DIST_MASK_PRECISE; else if( (char)c == 'v' ) build_voronoi ^= 1; else if( (char)c == 'n' ) { if( build_voronoi ) { build_voronoi = 0; mask_size = CV_DIST_MASK_3; } } } else if( mask_size == CV_DIST_MASK_3 ) mask_size = CV_DIST_MASK_5; else if( mask_size == CV_DIST_MASK_5 ) mask_size = CV_DIST_MASK_PRECISE; else if( mask_size == CV_DIST_MASK_PRECISE ) build_voronoi = 1; } cvReleaseImage( &gray ); cvReleaseImage( &edge ); cvReleaseImage( &dist ); cvReleaseImage( &dist8u ); cvReleaseImage( &dist8u1 ); cvReleaseImage( &dist8u2 ); cvReleaseImage( &dist32s ); cvReleaseImage( &labels ); cvDestroyWindow( wndname ); return 0; 椭圆曲线拟合 程序首先发现图像轮廓,然后用椭圆逼近它 效果图: 还是用ps的魔棒工具感觉更好。 源代码: #include "cv.h" #include "highgui.h" int slider_pos = 70; IplImage *image02 = 0, *image03 = 0, *image04 = 0; void process_image(int h); int main( int argc, char** argv ) { const char* filename = argc == 2 ? argv[1] : (char*)""; // 读入图像,强制为灰度图像 if( (image03 = cvLoadImage(filename, 0)) == 0 ) return -1; // Create the destination images image02 = cvCloneImage( image03 ); image04 = cvCloneImage( image03 ); // Create windows. cvNamedWindow("Source", 1); cvNamedWindow("Result", 1); // Show the image. cvShowImage("Source", image03); // Create toolbars. HighGUI use. cvCreateTrackbar( "Threshold", "Result", &slider_pos, 255, process_image ); process_image(0); // Wait for a key stroke; the same function arranges events processing cvWaitKey(0); cvReleaseImage(&image02); cvReleaseImage(&image03); cvDestroyWindow("Source"); cvDestroyWindow("Result"); return 0; } // Define trackbar callback functon. This function find contours, // draw it and approximate it by ellipses. void process_image(int h) { CvMemStorage* stor; CvSeq* cont; CvBox2D32f* box; CvPoint* PointArray; CvPoint2D32f* PointArray2D32f; // 创建动态结构序列 stor = cvCreateMemStorage(0); cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint) , stor); // 二值话图像. cvThreshold( image03, image02, slider_pos, 255, CV_THRESH_BINARY ); // 寻找所有轮廓. cvFindContours( image02, stor, &cont, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(0,0)); // Clear images. IPL use. cvZero(image02); cvZero(image04); // 本循环绘制所有轮廓并用椭圆拟合. for(;cont;cont = cont->h_next) { int i; // Indicator of cycle. int count = cont->total; // This is number point in contour CvPoint center; CvSize size; // Number point must be more than or equal to 6 (for cvFitEllipse_32f). if( count < 6 ) continue; // Alloc memory for contour point set. PointArray = (CvPoint*)malloc( count*sizeof(CvPoint) ); PointArray2D32f= (CvPoint2D32f*)malloc( count*sizeof(CvPoint2D32f) ); // Alloc memory for ellipse data. box = (CvBox2D32f*)malloc(sizeof(CvBox2D32f)); // Get contour point set. cvCvtSeqToArray(cont, PointArray, CV_WHOLE_SEQ); // Convert CvPoint set to CvBox2D32f set. for(i=0; i { PointArray2D32f[i].x = (float)PointArray[i].x; PointArray2D32f[i].y = (float)PointArray[i].y; } //拟合当前轮廓. cvFitEllipse(PointArray2D32f, count, box); // 绘制当前轮廓. cvDrawContours(image04,cont,CV_RGB(255,255,255), CV_RGB(255,255,255),0,1,8,cvPoint(0,0)); // Convert ellipse data from float to integer representation. center.x = cvRound(box->center.x); center.y = cvRound(box->center.y); = cvRound(box->*0.5); = cvRound(box->*0.5); box->angle = -box->angle; // Draw ellipse. cvEllipse(image04, center, size, box->angle, 0, 360, CV_RGB(0,0,255), 1, CV_AA, 0); // Free memory. free(PointArray); free(PointArray2D32f); free(box); } // Show image. HighGUI use. cvShowImage( "Result", image04 ); } 由点集序列或数组创建凸外形 不过说 看效果图就能明白原理: 源代码: #include "cv.h" #include "highgui.h" #include #define ARRAY 0 /* switch between array/sequence method by replacing 0<=>1 */ int main( int argc, char** argv ) { IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 ); cvNamedWindow( "hull", 1 ); #if !ARRAY CvMemStorage* storage = cvCreateMemStorage(); #endif for(;;) { int i, count = rand()%100 + 1, hullcount; CvPoint pt0; #if !ARRAY CvSeq* ptseq = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage ); CvSeq* hull; for( i = 0; i < count; i++ ) { pt0.x = rand() % (img->width/2) + img->width/4; pt0.y = rand() % (img->height/2) + img->height/4; cvSeqPush( ptseq, &pt0 ); } hull = cvConvexHull2( ptseq, 0, CV_CLOCKWISE, 0 ); hullcount = hull->total; #else CvPoint* points = (CvPoint*)malloc( count * sizeof(points[0])); int* hull = (int*)malloc( count * sizeof(hull[0])); CvMat point_mat = cvMat( 1, count, CV_32SC2, points ); CvMat hull_mat = cvMat( 1, count, CV_32SC1, hull ); #endif #if !ARRAY #else #endif for( i = 0; i < count; i++ ) { pt0.x = rand() % (img->width/2) + img->width/4; pt0.y = rand() % (img->height/2) + img->height/4; points[i] = pt0; } cvConvexHull2( &point_mat, &hull_mat, CV_CLOCKWISE, 0 ); hullcount = hull_; cvZero( img ); for( i = 0; i < count; i++ ) { pt0 = *CV_GET_SEQ_ELEM( CvPoint, ptseq, i ); pt0 = points[i]; cvCircle( img, pt0, 2, CV_RGB( 255, 0, 0 ), CV_FILLED ); } #if !ARRAY pt0 = **CV_GET_SEQ_ELEM( CvPoint*, hull, hullcount - 1 ); #else pt0 = points[hull[hullcount-1]]; #endif #if !ARRAY i ); #else #endif for( i = 0; i < hullcount; i++ ) { CvPoint pt = **CV_GET_SEQ_ELEM( CvPoint*, hull, CvPoint pt = points[hull[i]]; cvLine( img, pt0, pt, CV_RGB( 0, 255, 0 )); pt0 = pt; } cvShowImage( "hull", img ); int key = cvWaitKey(0); if( key == 27 ) // 'ESC' break; #if !ARRAY cvClearMemStorage( storage ); #else free( points ); free( hull ); #endif } } Delaunay三角形和Voronoi划分的迭代式构造 汗,这题目,我都晕了,什么东东呢。 效果图:(实际是个动画一样的东东,最终效果我截下了) 很欣赏这种main函数的写法,就两句,精辟,嘿嘿 源代码: #include "cv.h" #include "highgui.h" #include /* the script demostrates iterative construction of delaunay triangulation and voronoi tesselation */ CvSubdiv2D* init_delaunay( CvMemStorage* storage, CvRect rect ) { CvSubdiv2D* subdiv; subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*subdiv), sizeof(C vSubdiv2DPoint), sizeof(C vQuadEdge2D), storage ); cvInitSubdivDelaunay2D( subdiv, rect ); return subdiv; } void draw_subdiv_point( IplImage* img, CvPoint2D32f fp, CvScalar color ) { cvCircle( img, cvPoint(cvRound(fp.x), cvRound(fp.y)), 3, color, CV_FILLED, 8, 0 ); } void draw_subdiv_edge( IplImage* img, CvSubdiv2DEdge edge, CvScalar color ) { CvSubdiv2DPoint* org_pt; CvSubdiv2DPoint* dst_pt; CvPoint2D32f org; CvPoint2D32f dst; CvPoint iorg, idst; org_pt = cvSubdiv2DEdgeOrg(edge); dst_pt = cvSubdiv2DEdgeDst(edge); if( org_pt && dst_pt ) { org = org_pt->pt; dst = dst_pt->pt; iorg = cvPoint( cvRound( org.x ), cvRound( org.y )); idst = cvPoint( cvRound( dst.x ), cvRound( dst.y )); cvLine( img, iorg, idst, color, 1, CV_AA, 0 ); } } void draw_subdiv( IplImage* img, CvSubdiv2D* subdiv, CvScalar delaunay_color, CvScalar voronoi_color ) { CvSeqReader reader; int i, total = subdiv->edges->total; int elem_size = subdiv->edges->elem_size; cvStartReadSeq( (CvSeq*)(subdiv->edges), &reader, 0 ); for( i = 0; i < total; i++ ) { CvQuadEdge2D* edge = (CvQuadEdge2D*)(); if( CV_IS_SET_ELEM( edge )) { draw_subdiv_edge( img, (CvSubdiv2DEdge)edge + 1, voronoi_color ); draw_subdiv_edge( img, (CvSubdiv2DEdge)edge, delaunay_color ); } CV_NEXT_SEQ_ELEM( elem_size, reader ); } } void locate_point( CvSubdiv2D* subdiv, CvPoint2D32f fp, IplImage* img, CvScalar active_color ) { CvSubdiv2DEdge e; CvSubdiv2DEdge e0 = 0; CvSubdiv2DPoint* p = 0; cvSubdiv2DLocate( subdiv, fp, &e0, &p ); if( e0 ) { e = e0; do } { draw_subdiv_edge( img, e, active_color ); e = cvSubdiv2DGetEdge(e,CV_NEXT_AROUND_LEFT); } while( e != e0 ); draw_subdiv_point( img, fp, active_color ); } void draw_subdiv_facet( IplImage* img, CvSubdiv2DEdge edge ) { CvSubdiv2DEdge t = edge; int i, count = 0; CvPoint* buf = 0; // count number of edges in facet do { count++; t = cvSubdiv2DGetEdge( t, CV_NEXT_AROUND_LEFT ); } while (t != edge ); buf = (CvPoint*)malloc( count * sizeof(buf[0])); // gather points t = edge; for( i = 0; i < count; i++ ) { CvSubdiv2DPoint* pt = cvSubdiv2DEdgeOrg( t ); if( !pt ) break; buf[i] = cvPoint( cvRound(pt->pt.x), cvRound(pt->pt.y)); t = cvSubdiv2DGetEdge( t, CV_NEXT_AROUND_LEFT ); } if( i == count ) { CvSubdiv2DPoint* pt = cvSubdiv2DEdgeDst( cvSubdiv2DRotateEdge( edge, 1 )); cvFillConvexPoly( img, buf, count, CV_RGB(rand()&255,rand()&255,rand()&255), CV_AA, 0 ); cvPolyLine( img, &buf, &count, 1, 1, CV_RGB(0,0,0), 1, CV_AA, 0); draw_subdiv_point( img, pt->pt, CV_RGB(0,0,0)); } free( buf ); } void paint_voronoi( CvSubdiv2D* subdiv, IplImage* img ) { CvSeqReader reader; int i, total = subdiv->edges->total; int elem_size = subdiv->edges->elem_size; cvCalcSubdivVoronoi2D( subdiv ); cvStartReadSeq( (CvSeq*)(subdiv->edges), &reader, 0 ); for( i = 0; i < total; i++ ) { CvQuadEdge2D* edge = (CvQuadEdge2D*)(); 1 )); if( CV_IS_SET_ELEM( edge )) { CvSubdiv2DEdge e = (CvSubdiv2DEdge)edge; // left draw_subdiv_facet( img, cvSubdiv2DRotateEdge( e, // right draw_subdiv_facet( img, cvSubdiv2DRotateEdge( e, 3 )); } CV_NEXT_SEQ_ELEM( elem_size, reader ); } } void run(void) { char win[] = "source"; int i; CvRect rect = { 0, 0, 600, 600 }; CvMemStorage* storage; CvSubdiv2D* subdiv; IplImage* img; CvScalar active_facet_color, delaunay_color, voronoi_color, bkgnd_color; active_facet_color = CV_RGB( 255, 0, 0 ); delaunay_color = CV_RGB( 0,0,0); voronoi_color = CV_RGB(0, 180, 0); bkgnd_color = CV_RGB(255,255,255); img = cvCreateImage( cvSize(,), 8, 3 ); cvSet( img, bkgnd_color, 0 ); cvNamedWindow( win, 1 ); storage = cvCreateMemStorage(0); subdiv = init_delaunay( storage, rect ); printf("Delaunay triangulation will be build now interactively.n" "To stop the process, press any keynn"); for( i = 0; i < 200; i++ ) { CvPoint2D32f fp = cvPoint2D32f( (float)(rand()%(-10)+5), (float)(rand()%(-10)+5)); locate_point( subdiv, fp, img, active_facet_color ); cvShowImage( win, img ); if( cvWaitKey( 100 ) >= 0 ) break; cvSubdivDelaunay2DInsert( subdiv, fp ); cvCalcSubdivVoronoi2D( subdiv ); cvSet( img, bkgnd_color, 0 ); draw_subdiv( img, subdiv, delaunay_color, voronoi_color ); cvShowImage( win, img ); if( cvWaitKey( 100 ) >= 0 ) break; } cvSet( img, bkgnd_color, 0 ); paint_voronoi( subdiv, img ); cvShowImage( win, img ); cvWaitKey(0); cvReleaseMemStorage( &storage ); cvReleaseImage(&img); cvDestroyWindow( win ); } int main( int argc, char** argv ) { run(); return 0; } 利用背景建模检测运动物体(推荐) 效果图(截的时候前两个图没截出来),视频是一个交通路面的视频(自己可以 去下个): 大家就看个大概吧: 源代码: #include #include #include int main( int argc, char** argv ) { //声明IplImage指针 IplImage* pFrame = NULL; IplImage* pFrImg = NULL; IplImage* pBkImg = NULL; CvMat* pFrameMat = NULL; CvMat* pFrMat = NULL; CvMat* pBkMat = NULL; CvCapture* pCapture = NULL; int nFrmNum = 0; //创建窗口 cvNamedWindow("video", 1); cvNamedWindow("background",1); cvNamedWindow("foreground",1); //使窗口有序排列 cvMoveWindow("video", 30, 0); cvMoveWindow("background", 360, 0); cvMoveWindow("foreground", 690, 0); if( argc != 2 ) { fprintf(stderr, "Usage: bkgrd return -1; } //打开视频文件 if( !(pCapture = cvCaptureFromFile(argv[1]))) { fprintf(stderr, "Can not open video file %sn", argv[1]); return -2; } //逐帧读取视频 while(pFrame = cvQueryFrame( pCapture )) { nFrmNum++; //如果是第一帧,需要申请内存,并初始化 if(nFrmNum == 1) { pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1); pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1); pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); //转化成单通道图像再处理 cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY); cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); cvConvert(pFrImg, pFrameMat); cvConvert(pFrImg, pFrMat); cvConvert(pFrImg, pBkMat); } else { cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); cvConvert(pFrImg, pFrameMat); //先做高斯滤波,以平滑图像 //cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0); //当前帧跟背景图相减 cvAbsDiff(pFrameMat, pBkMat, pFrMat); //二值化前景图 cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY); //进行形态学滤波,去掉噪音 //cvErode(pFrImg, pFrImg, 0, 1); //cvDilate(pFrImg, pFrImg, 0, 1); //更新背景 cvRunningAvg(pFrameMat, pBkMat, 0.003, 0); //将背景转化为图像格式,用以显示 cvConvert(pBkMat, pBkImg); //显示图像 cvShowImage("video", pFrame); cvShowImage("background", pBkImg); cvShowImage("foreground", pFrImg); //如果有按键事件,则跳出循环 //此等待也为cvShowImage函数提供时间完成显示 //等待时间可以根据CPU速度调整 if( cvWaitKey(2) >= 0 ) break; } // end of if-else } // end of while-loop //销毁窗口 cvDestroyWindow("video"); cvDestroyWindow("background"); cvDestroyWindow("foreground"); //释放图像和矩阵 cvReleaseImage(&pFrImg); cvReleaseImage(&pBkImg); cvReleaseMat(&pFrameMat); cvReleaseMat(&pFrMat); cvReleaseMat(&pBkMat); return 0; } 运动模板检测(摄像头) 效果图:(太黑了) 源代码: #include "cv.h" #include "highgui.h" #include #include #include #include // various tracking parameters (in seconds) const double MHI_DURATION = 0.5; const double MAX_TIME_DELTA = 0.5; const double MIN_TIME_DELTA = 0.05; // 用于运动检测的循环帧数,与机器速度以及FPS设置有关 const int N = 2; // ring image buffer IplImage **buf = 0; int last = 0; // temporary images IplImage *mhi = 0; // MHI: motion history image IplImage *orient = 0; // orientation IplImage *mask = 0; // valid orientation mask IplImage *segmask = 0; // motion segmentation map CvMemStorage* storage = 0; // temporary storage // parameters: // img - input video frame // dst - resultant motion picture // args - optional parameters void update_mhi( IplImage* img, IplImage* dst, int diff_threshold ) { double timestamp = clock()/1000.; // get current time in seconds CvSize size = cvSize(img->width,img->height); // get current frame size int i, idx1 = last, idx2; IplImage* silh; CvSeq* seq; CvRect comp_rect; double count; double angle; CvPoint center; double magnitude; CvScalar color; // allocate images at the beginning or // reallocate them if the frame size is changed if( !mhi || mhi->width != || mhi->height != ) { if( buf == 0 ) } { buf = (IplImage**)malloc(N*sizeof(buf[0])); memset( buf, 0, N*sizeof(buf[0])); } for( i = 0; i < N; i++ ) { cvReleaseImage( &buf[i] ); buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 ); cvZero( buf[i] ); } cvReleaseImage( &mhi ); cvReleaseImage( &orient ); cvReleaseImage( &segmask ); cvReleaseImage( &mask ); mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 ); cvZero( mhi ); // clear MHI at the beginning orient = cvCreateImage( size, IPL_DEPTH_32F, 1 ); segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 ); mask = cvCreateImage( size, IPL_DEPTH_8U, 1 ); cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale idx2 = (last + 1) % N; // index of (last - (N-1))th frame last = idx2; silh = buf[idx2]; // 相邻两帧的差 cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames // 对差图像做二值化 cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // and threshold it cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI // convert MHI to blue 8u image // cvCvtScale的第四个参数 shift = (MHI_DURATION - timestamp)*255./MHI_DURATION // 控制帧差的消失速率 cvCvtScale( mhi, mask, 255./MHI_DURATION, (MHI_DURATION - timestamp)*255./MHI_DURATION ); cvZero( dst ); cvCvtPlaneToPix(mask, 0, 0, 0, dst ); // B,G,R,0 -> dist : convert to BLUE image // 计算运动的梯度方向以及正确的方向掩模mask // Filter size = 3 cvCalcMotionGradient( mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3 ); if( !storage ) storage = cvCreateMemStorage(0); else cvClearMemStorage(storage); // 运动分割: 获得运动部件的连续序列 // segmask is marked motion components map. It is not used further seq = cvSegmentMotion( mhi, segmask, storage, timestamp, MAX_TIME_DELTA ); // iterate through the motion components, // One more iteration (i == -1) corresponds to the whole image (global motion) for( i = 0; i < seq->total; i++ ) { if( i < 0 ) { // case of the whole image,对整幅图像做 操作 comp_rect = cvRect( 0, 0, , ); color = CV_RGB(255,255,255); // white color magnitude = 100; // 画线长度以及圆半径的大小控 制 } else { // i-th motion component comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect; // 去掉小的部分 if( comp_ + comp_ < 100 ) continue; color = CV_RGB(255,0,0); // red color magnitude = 30; //if(seq->total > 0) MessageBox(NULL,"Motion Detected",NULL,0); } // select component ROI cvSetImageROI( silh, comp_rect ); cvSetImageROI( mhi, comp_rect ); cvSetImageROI( orient, comp_rect ); cvSetImageROI( mask, comp_rect ); // 在选择的区域内, 计算运动方向 angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION); angle = 360.0 - angle; // adjust for images with top-left origin // 在轮廓内计算点数 // Norm(L1) = sum of total pixel values count = cvNorm( silh, 0, CV_L1, 0 ); // The function cvResetImageROI releases image ROI cvResetImageROI( mhi ); cvResetImageROI( orient ); cvResetImageROI( mask ); cvResetImageROI( silh ); // check for the case of little motion if( count < comp_*comp_ * 0.05 ) // five percent of pixel continue; // draw a clock with arrow indicating the direction center = cvPoint( (comp_rect.x + comp_/2), (comp_rect.y + comp_/2) ); cvCircle( dst, center, cvRound(magnitude*1.2), color, 3, CV_AA, 0 ); cvLine( dst, center, cvPoint( cvRound( center.x + magnitude*cos(angle*CV_PI/180)), cvRound( center.y - magnitude*sin(angle*CV_PI/180))), color, 3, CV_AA, 0 ); } } int main(int argc, char** argv) { IplImage* motion = 0; CvCapture* capture = 0; if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); else if( argc == 2 ) capture = cvCaptureFromAVI( argv[1] ); if( capture ) { cvNamedWindow( "Motion", 1 ); for(;;) { IplImage* image; if( !cvGrabFrame( capture )) break; image = cvRetrieveFrame( capture ); if( image ) { if( !motion ) { motion = cvCreateImage( cvSize(image->width,image->height), 8, 3 ); cvZero( motion ); motion->origin = image->origin; } } update_mhi( image, motion, 60 ); cvShowImage( "Motion", motion ); } if( cvWaitKey(10) >= 0 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow( "Motion" ); return 0; } 显示如何利用Camshift算法进行彩色目标的跟踪 没看出来有跟踪效果,是不是哥摄像头太拉了或得加强一下理论知识的学习: 穿的有点寒碜,嘿嘿 源代码: #include "cv.h" #include "highgui.h" #include #include IplImage *image = 0, *hsv = 0, *hue = 0, *mask = 0, *backproject = 0, *histimg = 0; CvHistogram *hist = 0; int backproject_mode = 0; int select_object = 0; int track_object = 0; int show_hist = 1; CvPoint origin; CvRect selection; CvRect track_window; CvBox2D track_box; // tracking 返回的区域 box,带角度 CvConnectedComp track_comp; int hdims = 48; // 划分HIST的个数,越高越精确 float hranges_arr[] = {0,180}; float* hranges = hranges_arr; int vmin = 10, vmax = 256, smin = 30; void on_mouse( int event, int x, int y, int flags ) { if( !image ) return; if( image->origin ) y = image->height - y; if( select_object ) { selection.x = MIN(x,origin.x); selection.y = MIN(y,origin.y); = selection.x + CV_IABS(x - origin.x); = selection.y + CV_IABS(y - origin.y); selection.x = MAX( selection.x, 0 ); selection.y = MAX( selection.y, 0 ); = MIN( , image->width ); = MIN( , image->height ); -= selection.x; -= selection.y; } switch( event ) { case CV_EVENT_LBUTTONDOWN: origin = cvPoint(x,y); selection = cvRect(x,y,0,0); select_object = 1; break; case CV_EVENT_LBUTTONUP: select_object = 0; if( > 0 && > 0 ) track_object = -1; #ifdef _DEBUG printf("n # 鼠标的选择区域:"); printf("n X = %d, Y = %d, Width = %d, Height = %d", selection.x, selection.y, , ); #endif break; } } CvScalar hsv2rgb( float hue ) { int rgb[3], p, sector; static const int sector_data[][3]= {{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}}; hue *= 0.333333333333333333333f; sector = cvFloor(hue); p = cvRound(255*(hue - sector)); p ^= sector & 1 ? 255 : 0; rgb[sector_data[sector][0]] = 255; rgb[sector_data[sector][1]] = 0; rgb[sector_data[sector][2]] = p; #ifdef _DEBUG printf("n # Convert HSV to RGB:"); printf("n HUE = %f", hue); printf("n R = %d, G = %d, B = %d", rgb[0],rgb[1],rgb[2]); #endif return cvScalar(rgb[2], rgb[1], rgb[0],0); } int main( int argc, char** argv ) { CvCapture* capture = 0; IplImage* frame = 0; if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); else if( argc == 2 ) capture = cvCaptureFromAVI( argv[1] ); if( !capture ) { fprintf(stderr,"Could not "); return -1; } printf( "Hot keys: n" "tESC - quit the programn" "tc - stop the trackingn" "tb - switch to/from backprojection viewn" "th - show/hide object histogramn" "To initialize tracking, select the object with mousen" ); //cvNamedWindow( "Histogram", 1 ); cvNamedWindow( "CamShiftDemo", 1 ); cvSetMouseCallback( "CamShiftDemo", on_mouse, NULL ); // on_mouse 自定义事件 cvCreateTrackbar( "Vmin", "CamShiftDemo", &vmin, 256, 0 ); cvCreateTrackbar( "Vmax", "CamShiftDemo", &vmax, 256, 0 ); cvCreateTrackbar( "Smin", "CamShiftDemo", &smin, 256, 0 ); for(;;) { int i, bin_w, c; frame = cvQueryFrame( capture ); if( !frame ) break; if( !image ) { /* allocate all the buffers */ image = cvCreateImage( cvGetSize(frame), 8, 3 ); image->origin = frame->origin; hsv = cvCreateImage( cvGetSize(frame), 8, 3 ); hue = cvCreateImage( cvGetSize(frame), 8, 1 ); mask = cvCreateImage( cvGetSize(frame), 8, 1 ); backproject = cvCreateImage( cvGetSize(frame), 8, 1 ); hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); // 计算直方图 histimg = cvCreateImage( cvSize(320,200), 8, 3 ); cvZero( histimg ); } cvCopy( frame, image, 0 ); cvCvtColor( image, hsv, CV_BGR2HSV ); // 彩色空间转换 BGR to HSV if( track_object ) { int _vmin = vmin, _vmax = vmax; cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0), cvScalar(180,256,MAX(_ vmin,_vmax),0), mask ); // 得到二值的MASK cvSplit( hsv, hue, 0, 0, 0 ); // 只提取 HUE 分 量 if( track_object < 0 ) { float max_val = 0.f; cvSetImageROI( hue, selection ); // 得 到选择区域 for ROI cvSetImageROI( mask, selection ); // 得 到选择区域 for mask cvCalcHist( &hue, hist, 0, mask ); // 计 算直方图 cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 ); // 只找最大值 cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 ); // 缩放 bin 到区间 [0,255] cvResetImageROI( hue ); // remove ROI cvResetImageROI( mask ); track_window = selection; track_object = 1; cvZero( histimg ); bin_w = histimg->width / hdims; // hdims: 条的个数,则 bin_w 为条的宽度 // 画直方图 for( i = 0; i < hdims; i++ ) { int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 ); CvScalar color = hsv2rgb(i*180.f/hdims); cvRectangle( histimg, cvPoint(i*bin_w,histimg->height), cvPo int((i+1)*bin_w,histimg->height - val), colo r, -1, 8, 0 ); } } cvCalcBackProject( &hue, backproject, hist ); // 使用 back project 方法 cvAnd( backproject, mask, backproject, 0 ); // calling CAMSHIFT 算法模块 cvCamShift( backproject, track_window, cvTermCriteria( CV_TER MCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ), &track_comp, &track_box ); track_window = track_; if( backproject_mode ) cvCvtColor( backproject, image, CV_GRAY2BGR ); // 使用backproject灰度图像 if( image->origin ) track_ = -track_; cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 ); } if( select_object && > 0 && > 0 ) { cvSetImageROI( image, selection ); cvXorS( image, cvScalarAll(255), image, 0 ); cvResetImageROI( image ); } cvShowImage( "CamShiftDemo", image ); cvShowImage( "Histogram", histimg ); } c = cvWaitKey(10); if( c == 27 ) break; // exit from for-loop switch( c ) { case 'b': backproject_mode ^= 1; break; case 'c': track_object = 0; cvZero( histimg ); break; case 'h': show_hist ^= 1; if( !show_hist ) cvDestroyWindow( "Histogram" ); else cvNamedWindow( "Histogram", 1 ); break; default: ; } cvReleaseCapture( &capture ); cvDestroyWindow("CamShiftDemo"); return 0; }
版权声明:本文标题:图像处理经典算法及OpenCV程序_图文 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1713214668a624261.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论