Opencv应用非常的广泛,最近一段时间在学习它。 基于WEB开发的大型程序,主流是使用Java进行开发,而java处理底层的东西时速度不理想,于是通过Java调用C开发的库文件变得很流行,JavaCV就是在这个大的环境下产生了。JavaCV它实现了java和OpenCV的关联,为Java程序员提供了一个很好的处理图像和视频的API。JavaCV开发环境的搭配就不在这个地方多口舌了,Google,Baidu都有。
下面是基于Camshift算法实现了摄像头下对运动物体的跟踪用JavaCV来实现:
import com.googlecode.javacpp.Pointer;
import com.googlecode.javacv.cpp.opencv_highgui.CvCapture;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import static com.googlecode.javacv.cpp.opencv_video.*;
public class JavaCVCamShift{
IplImage frame, image , hsv , hue , mask , backproject , histimg ;
IplImage[] imageArray;
//用HSV中的Hue分量进行跟踪
CvHistogram hist ;
//直方图类
int x1=0,y1=0,x2=0,y2=0;//选取对象的坐标
int backproject_mode = 0;
int select_object = 0;
int track_object = 0;
int show_hist = 1;
CvPoint origin;
CvPoint cp1,cp2;
CvRect selection;
CvRect track_window;
CvBox2D track_box;
float[] max_val=new float[1];
int[] hdims = {16};
//划分直方图bins的个数,越多越精确
float[][] hranges_arr = {{0,180}};
//像素值的范围
float[][] hranges = hranges_arr;
//用于初始化CvHistogram类
CvConnectedComp track_comp;
public JavaCVCamShift()
{
imageArray=new IplImage[1];
CvCapture capture= cvCreateCameraCapture(0);
cvNamedWindow("imageName",CV_WINDOW_AUTOSIZE);
Pointer pointer=null;
cvSetMouseCallback("imageName",new mouseClike(),pointer);
track_comp=new CvConnectedComp();
while(true)
{
frame=cvQueryFrame(capture);
if(frame==null)break;
if( image==null )
//image为空,表明刚开始还未对image操作过,先建立一些缓冲区
{
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 );
//分配直方图空间
}
cvCopy(frame,image);
cvCvtColor( image, hsv, CV_BGR2HSV );
if( track_object !=0)
//track_object非零,表示有需要跟踪的物体
{
double _vmin = 10.0, _vmax = 256.0,smin=30.0;
cvInRangeS( hsv, cvScalar(0.0,smin,Math.min(_vmin,_vmax),0.0), cvScalar(180.0,256.0,Math.max(_vmin,_vmax),0.0), mask );
//,只处理像素值为H:0~180,S:smin~256,V:vmin~vmax之间的部分制作掩膜板
cvSplit( hsv, hue, null, null, null );
//分离H分量
imageArray[0]=hue;
if( track_object < 0 )
//如果需要跟踪的物体还没有进行属性提取,则进行选取框类的图像属性提取
{
cvSetImageROI( imageArray[0],selection );
//设置原选择框为ROI
cvSetImageROI( mask,selection );
//设置掩膜板选择框为ROI
cvCalcHist( imageArray,hist,0,mask );
//得到选择框内且满足掩膜板内的直方图
cvGetMinMaxHistValue( hist, null, max_val, null, null );
cvConvertScale( hist.bins(), hist.bins(),max_val[0]>0 ? (double)255/ max_val[0]:0.0,0 );
// 对直方图的数值转为0~255
cvResetImageROI( imageArray[0] );
//去除ROI
cvResetImageROI( mask );
//去除ROI
track_window = selection;
track_object = 1;
//置track_object为1,表明属性提取完成
}
cvCalcBackProject( imageArray, backproject, hist );
//计算hue的反向投影图
cvAnd( backproject, mask, backproject, null );
//得到掩膜内的反向投影
cvCamShift(backproject, track_window,
cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
track_comp,track_box);
//使用MeanShift算法对backproject中的内容进行搜索,返回跟踪结果
track_window = track_comp.rect();
//得到跟踪结果的矩形框
cp1=cvPoint(track_window.x(),track_window.y());
cp2=cvPoint(track_window.x()+track_window.width(),track_window.y()+track_window.height());
if( image.origin()>0 )
track_box.angle(-track_box.angle());
cvRectangle(frame,cp1,cp2, CV_RGB(0,255,0),3,CV_AA,0);
}
if( select_object==1 && selection.width() > 0 && selection.height() > 0 )
//如果正处于物体选择,画出选择框
{
cvSetImageROI( frame, selection );
cvXorS(frame,cvScalarAll(255),frame,null );
cvResetImageROI( frame );
}
cvShowImage("imageName",frame);
int c=cvWaitKey(33);
if(c==27) break;
}
cvReleaseCapture(capture);
cvDestroyWindow("imageName");
}
public static void main(String[] args) {
new JavaCVCamShift();
}
class mouseClike extends CvMouseCallback
{
public void call(int event,int x, int y,int flags, Pointer param)
//鼠标回调函数,该函数用鼠标进行跟踪目标的选择
{
if( image==null )
return;
if( image.origin()!=0 )
y = image.height() - y;
//如果图像原点坐标在左下,则将其改为左上
if( select_object==1 )
//select_object为1,表示在用鼠标进行目标选择
//此时对矩形类selection用当前的鼠标位置进行设置
{
selection.x(Math.min(x,origin.x()));
selection.y(Math.min(y,origin.y()));
selection.width(selection.x() + Math.abs(x - origin.x()));
selection.height(selection.y() + Math.abs(y - origin.y()));
selection.x(Math.max(selection.x(),0));
selection.y(Math.max(selection.y(),0 ));
selection.width(Math.min( selection.width(), image.width() ));
selection.height(Math.min( selection.height(), image.height()));
selection.width(selection.width()-selection.x());
selection.height( selection.height()-selection.y());
}
switch( event )
{
case CV_EVENT_LBUTTONDOWN:
//鼠标按下,开始点击选择跟踪物体
origin = cvPoint(x,y);
selection = cvRect(0,0,0,0);
select_object = 1;
break;
case CV_EVENT_LBUTTONUP:
//鼠标松开,完成选择跟踪物体
select_object = 0;
if( selection.width() > 0 && selection.height() > 0 )
//如果选择物体有效,则打开跟踪功能
track_object = -1;
break;
}
}
}
}
使用JavaCV我们要注意的是,Google并没有给我们一些API参考文档,调用函数的名称和参数可能与OpenCV有一定的出入,(回调函数的使用改变很大),需要我们多看看一些JavaCV自带的例子。JavaCV环境的搭配和测试请参考: