* Copyright (C) 2009,2010,2011,2012 Samuel Audet
*
* This file is part of JavaCV.
*
* JavaCV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version (subject to the "Classpath" exception
* as provided in the LICENSE.txt file that accompanied this code).
*
* JavaCV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JavaCV. If not, see
*
*
* Adapted from the find_obj.cpp sample in the source package of OpenCV 2.3.1:
*
* A Demo to OpenCV Implementation of SURF
* Further Information Refer to "SURF: Speed-Up Robust Feature"
* Author: Liu Liu
* liuliu.1987+opencv@gmail.com
*/
package com.googlecode.javacv;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.logging.Logger;
importstatic com.googlecode.javacv.cpp.opencv_calib3d.*;
importstatic com.googlecode.javacv.cpp.opencv_core.*;
importstatic com.googlecode.javacv.cpp.opencv_flann.*;
importstatic com.googlecode.javacv.cpp.opencv_highgui.*;
importstatic com.googlecode.javacv.cpp.opencv_imgproc.*;
importstatic com.googlecode.javacv.cpp.opencv_legacy.*;
/**
*
* @author Samuel Audet
*
* ObjectFinder does not work out-of-the-box under Android, because it lacks the standard
* java.beans.beancontext package. We can work around it by doing the following *BEFORE*
* following the instructions in the README.txt file:
*
* 1. Remove BaseChildSettings.class and BaseSettings.class from javacv.jar
* 2. Follow the instructions in the README.txt file
* 3. In your project, define empty classes BaseChildSettings and BaseSettings under the com.googlecode.javacv package name
*/
publicclassObjectFinder{
publicObjectFinder(IplImage objectImage){
settings =newSettings();
settings.objectImage = objectImage;
setSettings(settings);
}
publicObjectFinder(Settings settings){
setSettings(settings);
}
publicstaticclassSettingsextendsBaseChildSettings{
IplImage objectImage =null;
CvSURFParams parameters = cvSURFParams(500,1);
double distanceThreshold =0.6;
int matchesMin =4;
double ransacReprojThreshold =1.0;
boolean useFLANN =false;
publicIplImage getObjectImage(){
return objectImage;
}
publicvoid setObjectImage(IplImage objectImage){
this.objectImage = objectImage;
}
publicboolean isExtended(){
return parameters.extended()!=0;
}
publicvoid setExtended(boolean extended){
parameters.extended(extended ?1:0);
}
publicboolean isUpright(){
return parameters.upright()!=0;
}
publicvoid setUpright(boolean upright){
parameters.upright(upright ?1:0);
}
publicdouble getHessianThreshold(){
return parameters.hessianThreshold();
}
publicvoid setHessianThreshold(double hessianThreshold){
parameters.hessianThreshold(hessianThreshold);
}
publicint getnOctaves(){
return parameters.nOctaves();
}
publicvoid setnOctaves(int nOctaves){
parameters.nOctaves(nOctaves);
}
publicint getnOctaveLayers(){
return parameters.nOctaveLayers();
}
publicvoid setnOctaveLayers(int nOctaveLayers){
parameters.nOctaveLayers(nOctaveLayers);
}
publicdouble getDistanceThreshold(){
return distanceThreshold;
}
publicvoid setDistanceThreshold(double distanceThreshold){
this.distanceThreshold = distanceThreshold;
}
publicint getMatchesMin(){
return matchesMin;
}
publicvoid setMatchesMin(int matchesMin){
this.matchesMin = matchesMin;
}
publicdouble getRansacReprojThreshold(){
return ransacReprojThreshold;
}
publicvoid setRansacReprojThreshold(double ransacReprojThreshold){
this.ransacReprojThreshold = ransacReprojThreshold;
}
publicboolean isUseFLANN(){
return useFLANN;
}
publicvoid setUseFLANN(boolean useFLANN){
this.useFLANN = useFLANN;
}
}
privateSettings settings;
publicSettings getSettings(){
return settings;
}
publicvoid setSettings(Settings settings){
this.settings = settings;
CvSeq keypoints =newCvSeq(null), descriptors =newCvSeq(null);
cvClearMemStorage(storage);
cvExtractSURF(settings.objectImage,null, keypoints, descriptors, storage, settings.parameters,0);
int total = descriptors.total();
int size = descriptors.elem_size();
objectKeypoints =newCvSURFPoint[total];
objectDescriptors =newFloatBuffer[total];
for(int i =0; i < total; i++){
objectKeypoints[i]=newCvSURFPoint(cvGetSeqElem(keypoints, i));
objectDescriptors[i]= cvGetSeqElem(descriptors, i).capacity(size).asByteBuffer().asFloatBuffer();
}
if(settings.useFLANN){
int length = objectDescriptors[0].capacity();
objectMat =CvMat.create(total, length, CV_32F,1);
imageMat =CvMat.create(total, length, CV_32F,1);
indicesMat =CvMat.create(total, 2, CV_32S,1);
distsMat =CvMat.create(total, 2, CV_32F,1);
flannIndex =newIndex();
indexParams =newKDTreeIndexParams(4);// using 4 randomized kdtrees
searchParams =newSearchParams(64,0,true);// maximum number of leafs checked
}
pt1 =CvMat.create(1, total, CV_32F,2);
pt2 =CvMat.create(1, total, CV_32F,2);
mask =CvMat.create(1, total, CV_8U, 1);
H =CvMat.create(3,3);
ptpairs =newArrayList
logger.info(total +" object descriptors");
}
privatestaticfinalLogger logger =Logger.getLogger(ObjectFinder.class.getName());
privateCvMemStorage storage =CvMemStorage.create();
privateCvMemStorage tempStorage =CvMemStorage.create();
privateCvSURFPoint[] objectKeypoints =null, imageKeypoints =null;
privateFloatBuffer[] objectDescriptors =null, imageDescriptors =null;
privateCvMat objectMat, imageMat, indicesMat, distsMat;
privateIndex flannIndex =null;
privateIndexParams indexParams =null;
privateSearchParams searchParams =null;
privateCvMat pt1 =null, pt2 =null, mask =null, H =null;
privateArrayList
publicdouble[] find(IplImage image){
CvSeq keypoints =newCvSeq(null), descriptors =newCvSeq(null);
cvClearMemStorage(tempStorage);
cvExtractSURF(image,null, keypoints, descriptors, tempStorage, settings.parameters,0);
int total = descriptors.total();
int size = descriptors.elem_size();
imageKeypoints =newCvSURFPoint[total];
imageDescriptors =newFloatBuffer[total];
for(int i =0; i < total; i++){
imageKeypoints[i]=newCvSURFPoint(cvGetSeqElem(keypoints, i));
imageDescriptors[i]= cvGetSeqElem(descriptors, i).capacity(size).asByteBuffer().asFloatBuffer();
}
logger.info(total +" image descriptors");
int w = settings.objectImage.width();
int h = settings.objectImage.height();
double[] srcCorners ={0,0, w,0, w, h, 0, h};
double[] dstCorners = locatePlanarObject(objectKeypoints, objectDescriptors,
imageKeypoints, imageDescriptors, srcCorners);
return dstCorners;
}
privatedouble compareSURFDescriptors(FloatBuffer d1,FloatBuffer d2,double best){
double totalCost =0;
assert (d1.capacity()== d2.capacity()&& d1.capacity()%4==0);
for(int i =0; i < d1.capacity(); i +=4){
double t0 = d1.get(i )- d2.get(i );
double t1 = d1.get(i+1)- d2.get(i+1);
double t2 = d1.get(i+2)- d2.get(i+2);
double t3 = d1.get(i+3)- d2.get(i+3);
totalCost += t0*t0 + t1*t1 + t2*t2 + t3*t3;
if(totalCost > best)
break;
}
return totalCost;
}
privateint naiveNearestNeighbor(FloatBuffer vec,int laplacian,
CvSURFPoint[] modelKeypoints,FloatBuffer[] modelDescriptors){
int neighbor =-1;
double d, dist1 =1e6, dist2 =1e6;
for(int i =0; i < modelDescriptors.length; i++){
CvSURFPoint kp = modelKeypoints[i];
FloatBuffer mvec = modelDescriptors[i];
if(laplacian != kp.laplacian())
continue;
d = compareSURFDescriptors(vec, mvec, dist2);
if(d < dist1){
dist2 = dist1;
dist1 = d;
neighbor = i;
}elseif(d < dist2){
dist2 = d;
}
}
if(dist1 < settings.distanceThreshold*dist2)
return neighbor;
return-1;
}
privatevoid findPairs(CvSURFPoint[] objectKeypoints,FloatBuffer[] objectDescriptors,
CvSURFPoint[] imageKeypoints,FloatBuffer[] imageDescriptors){
for(int i =0; i < objectDescriptors.length; i++){
CvSURFPoint kp = objectKeypoints[i];
FloatBuffer descriptor = objectDescriptors[i];
int nearestNeighbor = naiveNearestNeighbor(descriptor, kp.laplacian(), imageKeypoints, imageDescriptors);
if(nearestNeighbor >=0){
ptpairs.add(i);
ptpairs.add(nearestNeighbor);
}
}
}
privatevoid flannFindPairs(FloatBuffer[] objectDescriptors, FloatBuffer[] imageDescriptors){
int length = objectDescriptors[0].capacity();
if(imageMat.rows()< imageDescriptors.length){
imageMat =CvMat.create(imageDescriptors.length, length, CV_32F,1);
}
int imageRows = imageMat.rows();
imageMat.rows(imageDescriptors.length);
// copy descriptors
FloatBuffer objectBuf = objectMat.getFloatBuffer();
for(int i =0; i < objectDescriptors.length; i++){
objectBuf.put(objectDescriptors[i]);
}
FloatBuffer imageBuf = imageMat.getFloatBuffer();
for(int i =0; i < imageDescriptors.length; i++){
imageBuf.put(imageDescriptors[i]);
}
// find nearest neighbors using FLANN
flannIndex.build(imageMat, indexParams, FLANN_DIST_L2);
flannIndex.knnSearch(objectMat, indicesMat, distsMat,2, searchParams);
IntBuffer indicesBuf = indicesMat.getIntBuffer();
FloatBuffer distsBuf = distsMat.getFloatBuffer();
for(int i =0; i < objectDescriptors.length; i++){
if(distsBuf.get(2*i)< settings.distanceThreshold*distsBuf.get(2*i+1)){
ptpairs.add(i);
ptpairs.add(indicesBuf.get(2*i));
}
}
imageMat.rows(imageRows);
}
/* a rough implementation for object location */
privatedouble[] locatePlanarObject(CvSURFPoint[] objectKeypoints,FloatBuffer[] objectDescriptors,
CvSURFPoint[] imageKeypoints,FloatBuffer[] imageDescriptors,double[] srcCorners){
ptpairs.clear();
if(settings.useFLANN){
flannFindPairs(objectDescriptors, imageDescriptors);
}else{
findPairs(objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors);
}
int n = ptpairs.size()/2;
logger.info(n +" matching pairs found");
if(n < settings.matchesMin){
returnnull;
}
pt1 .cols(n);
pt2 .cols(n);
mask.cols(n);
for(int i =0; i < n; i++){
CvPoint2D32f p1 = objectKeypoints[ptpairs.get(2*i)].pt();
pt1.put(2*i, p1.x()); pt1.put(2*i+1, p1.y());
CvPoint2D32f p2 = imageKeypoints[ptpairs.get(2*i+1)].pt();
pt2.put(2*i, p2.x()); pt2.put(2*i+1, p2.y());
}
if(cvFindHomography(pt1, pt2, H, CV_RANSAC, settings.ransacReprojThreshold, mask)==0){
returnnull;
}
if(cvCountNonZero(mask)< settings.matchesMin){
returnnull;
}
double[] h = H.get();
double[] dstCorners =newdouble[srcCorners.length];
for(int i =0; i < srcCorners.length/2; i++){
double x = srcCorners[2*i], y = srcCorners[2*i +1];
double Z =1/(h[6]*x + h[7]*y + h[8]);
double X =(h[0]*x + h[1]*y + h[2])*Z;
double Y =(h[3]*x + h[4]*y + h[5])*Z;
dstCorners[2*i ]= X;
dstCorners[2*i +1]= Y;
}
pt1 .cols(objectDescriptors.length);
pt2 .cols(objectDescriptors.length);
mask.cols(objectDescriptors.length);
return dstCorners;
}
publicstaticvoid main(String[] args)throwsException{
// Logger.getLogger("com.googlecode.javacv").setLevel(Level.OFF);
String objectFilename = args.length ==2? args[0]:"/usr/share/opencv/samples/c/box.png";
String sceneFilename = args.length ==2? args[1]:"/usr/share/opencv/samples/c/box_in_scene.png";
IplImage object = cvLoadImage(objectFilename, CV_LOAD_IMAGE_GRAYSCALE);
IplImage image = cvLoadImage(sceneFilename, CV_LOAD_IMAGE_GRAYSCALE);
if(object ==null|| image ==null){
System.err.println("Can not load "+ objectFilename +" and/or "+ sceneFilename);
System.exit(-1);
}
IplImage objectColor =IplImage.create(object.width(), object.height(),8,3);
cvCvtColor(object, objectColor, CV_GRAY2BGR);
IplImage correspond =IplImage.create(image.width(), object.height()+ image.height(),8,1);
cvSetImageROI(correspond, cvRect(0,0, object.width(), object.height()));
cvCopy(object, correspond);
cvSetImageROI(correspond, cvRect(0, object.height(), correspond.width(), correspond.height()));
cvCopy(image, correspond);
cvResetImageROI(correspond);
ObjectFinder.Settings settings =newObjectFinder.Settings();
settings.objectImage = object;
settings.useFLANN =true;
settings.ransacReprojThreshold =5;
ObjectFinder finder =newObjectFinder(settings);
long start =System.currentTimeMillis();
double[] dst_corners = finder.find(image);
System.out.println("Finding time = "+(System.currentTimeMillis()- start)+" ms");
if(dst_corners != null){
for(int i =0; i <4; i++){
int j =(i+1)%4;
int x1 =(int)Math.round(dst_corners[2*i ]);
int y1 =(int)Math.round(dst_corners[2*i +1]);
int x2 =(int)Math.round(dst_corners[2*j ]);
int y2 =(int)Math.round(dst_corners[2*j +1]);
cvLine(correspond, cvPoint(x1, y1 + object.height()),
cvPoint(x2, y2 + object.height()),
CvScalar.WHITE,1,8,0);
}
}
for(int i =0; i < finder.ptpairs.size(); i +=2){
CvPoint2D32f pt1 = finder.objectKeypoints[finder.ptpairs.get(i)].pt();
CvPoint2D32f pt2 = finder.imageKeypoints[finder.ptpairs.get(i+1)].pt();
cvLine(correspond, cvPointFrom32f(pt1),
cvPoint(Math.round(pt2.x()),Math.round(pt2.y()+object.height())),
CvScalar.WHITE,1,8,0);
}
CanvasFrame objectFrame =newCanvasFrame("Object");
CanvasFrame correspondFrame =newCanvasFrame("Object Correspond");
correspondFrame.showImage(correspond);
for(int i =0; i < finder.objectKeypoints.length; i++){
CvSURFPoint r = finder.objectKeypoints[i];
CvPoint center = cvPointFrom32f(r.pt());
int radius =Math.round(r.size()*1.2f/9*2);
cvCircle(objectColor, center, radius,CvScalar.RED,1,8,0);
}
objectFrame.showImage(objectColor);
objectFrame.waitKey();
objectFrame.dispose();
correspondFrame.dispose();
}
}
Copyright © 2011 - All Rights Reserved - Softron.in
Template by Softron Technology