Példaprogram
EpipolarGeometryExample.java
import org.opencv.core.*;
import org.opencv.calib3d.*;
import org.opencv.highgui.*;
import org.opencv.features2d.*;
import org.opencv.utils.*;
import org.opencv.imgproc.*;
import java.util.*;
import java.io.*;
class EpipolarGeometryExample {
static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
public static Comparator<DMatch> DMatchComparator = new Comparator<DMatch>() {
public int compare(DMatch match1, DMatch match2) {
if ( match1.distance < match2.distance) {
return -1;
}
if ( match1.distance > match2.distance) {
return 1;
}
return 0;
}
}; // END DMatchComparator
public static Comparator<KeyPoint> KeypointComparator = new Comparator<KeyPoint>() {
public int compare(KeyPoint keypoint1, KeyPoint keypoint2) {
if ( keypoint1.response < keypoint2.response) {
return -1;
}
if ( keypoint1.response > keypoint2.response) {
return 1;
}
return 0;
}
}; // END KeypointComparator
public static MatOfKeyPoint filterKeypoints(MatOfKeyPoint keypoints, int percent) {
KeyPoint[] keypointArray = keypoints.toArray();
Arrays.sort(keypointArray, EpipolarGeometryExample.KeypointComparator);
int nRelevantKeypoints = Math.max(8, percent * keypointArray.length / 100 );
KeyPoint[] relevantKeypointsArray = Arrays.copyOfRange(keypointArray, keypointArray.length - nRelevantKeypoints, keypointArray.length);
MatOfKeyPoint relevantKeypoints = new MatOfKeyPoint();
relevantKeypoints.fromArray(relevantKeypointsArray);
return relevantKeypoints;
} // END filterKeypoints()
public static void findStableMatches(MatOfKeyPoint refKeypoints, MatOfKeyPoint queryKeypoints, MatOfDMatch matches, MatOfDMatch stableMatches) {
int nRefKeypoints = refKeypoints.rows();
int nQueryKeypoints = queryKeypoints.rows();
double[][] matchingPairsTable = new double[nRefKeypoints][nQueryKeypoints];
for ( int u = 0; u < nRefKeypoints; u++) { /// initializing
for (int v = 0; v < nQueryKeypoints; v++ ) {
matchingPairsTable[u][v] = Double.MAX_VALUE;
}
}
List<DMatch> matchesList = matches.toList();
for (int j = 0; j < matchesList.size(); j++) {
DMatch currentMatch = matchesList.get(j);
int trainIdx = currentMatch.trainIdx;
int queryIdx = currentMatch.queryIdx; // note: queryIdx == j
double dist = currentMatch.distance;
matchingPairsTable[trainIdx][queryIdx] = dist;
}
/// stabil párosítás (Gale - Shapley algoritmusa) http://www.cs.elte.hu/~kiraly/Grafalg.pdf
int[] possibleQueriesToTrains = new int[nRefKeypoints];
for ( int j=0; j < nRefKeypoints; j++ ) {
possibleQueriesToTrains[j] = -1;
}
boolean newPairFound = true;
do {
newPairFound = false;
for ( int q = 0; q < nQueryKeypoints; q++ ) {
//List<DMatch> currentMatches = kMatchesList.get(q).toList(); // it is already increasing order
DMatch currentMatch = matchesList.get(q);
int trainIdx = currentMatch.trainIdx;
double dist = currentMatch.distance;
if (matchingPairsTable[trainIdx][q] == Double.MAX_VALUE) {
continue;
}
if ( possibleQueriesToTrains[trainIdx] == -1 ) {
possibleQueriesToTrains[trainIdx] = q;
newPairFound = true;
} else {
if ( possibleQueriesToTrains[trainIdx] > dist ) {
matchingPairsTable[trainIdx][possibleQueriesToTrains[trainIdx]] = Double.MAX_VALUE;
possibleQueriesToTrains[trainIdx] = q;
newPairFound = true;
}
}
}
} while (newPairFound == true);
List<DMatch> goodMatchesList = new ArrayList<DMatch>();
for ( int t = 0; t < nRefKeypoints; t++ ) {
if ( possibleQueriesToTrains[t] > -1 ) {
goodMatchesList.add(new DMatch(possibleQueriesToTrains[t], t, (float) matchingPairsTable[t][possibleQueriesToTrains[t]] ));
}
}
stableMatches.fromList(goodMatchesList);
} // END findStableMatches() --- note: not tested yet as method
public static void drawMatchingPairs(MatOfPoint2f points1, MatOfPoint2f points2, Mat img1, Mat img2, Mat resultImg) {
resultImg.create(Math.max(img1.rows(), img2.rows()), img1.cols()+img2.cols(), CvType.CV_8U );
/** copy images side-by-side into one images **/
img1.copyTo(resultImg.submat(new Range(0,img1.rows()), new Range(0,img1.cols())));
img2.copyTo(resultImg.submat(new Range(0,img2.rows()), new Range(img1.cols(), img1.cols()+ img2.cols())));
List<Point> p1List = points1.toList();
List<Point> p2List = points2.toList();
Imgproc.cvtColor(resultImg, resultImg, Imgproc.COLOR_GRAY2BGR);
for (int i = 0; i < points1.rows(); i++) {
double r = Math.random()*255;
double g = Math.random()*255;
double b = Math.random()*255;
Point p1 = p1List.get(i);
Point p2 = p2List.get(i);
//p2.y = p2.y + img1.cols();
Core.line(resultImg, new Point(p1.x, p1.y), new Point(p2.x+img1.cols(), p2.y), new Scalar(r,g,b), 2);
}
} // END drawMatchingPairs()
public static void main(String[] args) {
String photosDir = "jatek/";
String queryFile = photosDir + "jatek4.jpg";
String referenceFile = photosDir + "jatek3.jpg";
/**
* loading images
**/
Mat queryImage = Highgui.imread(queryFile, Highgui.CV_LOAD_IMAGE_GRAYSCALE);
Mat referenceImage = Highgui.imread(referenceFile, Highgui.CV_LOAD_IMAGE_GRAYSCALE);
/**
* extract SIFT feature points
**/
FeatureDetector siftDetector = FeatureDetector.create(FeatureDetector.SIFT);
DescriptorExtractor siftDescriptor = DescriptorExtractor.create(DescriptorExtractor.SIFT);
// -- we preserve only a percent of the detected keypoints ---
int percentOfKeypoints = 80;
MatOfKeyPoint referenceKeypoints = new MatOfKeyPoint();
siftDetector.detect(referenceImage, referenceKeypoints);
referenceKeypoints = EpipolarGeometryExample.filterKeypoints(referenceKeypoints, percentOfKeypoints);
Mat referenceDescriptor = new Mat();
siftDescriptor.compute(referenceImage, referenceKeypoints, referenceDescriptor);
MatOfKeyPoint queryKeypoints = new MatOfKeyPoint();
siftDetector.detect(queryImage, queryKeypoints);
queryKeypoints = EpipolarGeometryExample.filterKeypoints(queryKeypoints, percentOfKeypoints);
Mat queryDescriptor = new Mat();
siftDescriptor.compute(queryImage, queryKeypoints, queryDescriptor);
int nRefKeypoints = referenceDescriptor.rows(); // = referenceSiftKeypoints.toList().size();
int nQueryKeypoints = queryDescriptor.rows();
/**
* Matches feature points
**/
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);
List<MatOfDMatch> kMatchesList = new ArrayList<MatOfDMatch>();
matcher.knnMatch(queryDescriptor, referenceDescriptor, kMatchesList, 1);
List<DMatch> matchesList = new ArrayList<DMatch>();
List<DMatch> goodMatchesList = new ArrayList<DMatch>();
for (int i = 0; i < kMatchesList.size(); i++) {
MatOfDMatch match_i = kMatchesList.get(i);
List<DMatch> matches_i = match_i.toList();
matchesList.addAll(matches_i);
}
DMatch[] matchesArray = matchesList.toArray(new DMatch[0]);
Arrays.sort(matchesArray, EpipolarGeometryExample.DMatchComparator);
for (int j = 0; j < (int)(40 * matchesArray.length / 100); j++) {
goodMatchesList.add(matchesArray[j]);
System.out.println("distance[" + j +"]: " + matchesArray[j].distance);
}
MatOfDMatch goodMatches = new MatOfDMatch();
goodMatches.fromList(goodMatchesList);
Mat img_with_matches = new Mat();
Features2d.drawMatches(
queryImage, queryKeypoints,
referenceImage, referenceKeypoints,
goodMatches, img_with_matches);
Highgui.imwrite("reference_match_to_"+ new File(queryFile).getName(), img_with_matches);
/*** Compute fundamental matrix ***/
Mat F = new Mat();
MatOfPoint2f quepoints = new MatOfPoint2f();
MatOfPoint2f refpoints = new MatOfPoint2f();
List<Point> quePointList = new ArrayList<Point>();
List<Point> refPointList = new ArrayList<Point>();
List<Point3> quePoint3fList = new ArrayList<Point3>();
List<Point3> refPoint3fList = new ArrayList<Point3>();
List<KeyPoint> refKeypointList = referenceKeypoints.toList();
List<KeyPoint> queKeypointList = queryKeypoints.toList();
for (int t = 0; t < goodMatchesList.size(); t++) {
DMatch m = goodMatchesList.get(t);
int trainIdx = m.trainIdx;
int queryIdx = m.queryIdx;
Point refPt = refKeypointList.get(trainIdx).pt;
Point quePt = queKeypointList.get(queryIdx).pt;
refPointList.add(refPt);
quePointList.add(quePt);
refPoint3fList.add(new Point3(refPt.x, refPt.y, 1.0));
quePoint3fList.add(new Point3(quePt.x, quePt.y, 1.0));
}
quepoints.fromList(quePointList);
refpoints.fromList(refPointList);
F = Calib3d.findFundamentalMat(refpoints, quepoints, Calib3d.FM_8POINT,3,0.99);
Mat newRefPointMat = new Mat();
Mat newQuePointMat = new Mat();
Mat quePointMat = Converters.vector_Point2f_to_Mat(quePointList);
Mat refPointMat = Converters.vector_Point2f_to_Mat(refPointList);
// -- geometrical correction of matching point pairs with the help of fundamental matrix ----
Calib3d.correctMatches(F, refPointMat.t(), quePointMat.t(), newRefPointMat, newQuePointMat);
MatOfPoint2f newRefpoints = new MatOfPoint2f(newRefPointMat.t());
MatOfPoint2f newQuepoints = new MatOfPoint2f(newQuePointMat.t());
F = Calib3d.findFundamentalMat(newRefpoints, newQuepoints, Calib3d.FM_8POINT,3,0.99);
quePointMat = newQuePointMat;
refPointMat = newRefPointMat;
refpoints = newRefpoints;
quepoints = newQuepoints;
System.out.println(F.dump());
Mat quePoint3fMat = new Mat();
Mat refPoint3fMat = new Mat();
Calib3d.convertPointsToHomogeneous(quePointMat, quePoint3fMat);
Calib3d.convertPointsToHomogeneous(refPointMat, refPoint3fMat);
Mat queLines = new Mat();
Mat refLines = new Mat();
Calib3d.computeCorrespondEpilines(refPoint3fMat, 1, F, queLines);
Calib3d.computeCorrespondEpilines(quePoint3fMat, 2, F, refLines);
System.out.println(queLines.dump()); // queLines contains (a,b,c) in ax+by+c = 0;
System.out.println("pontok mentése tömbbe");
Mat img2WithEpilines = queryImage.clone();
Imgproc.cvtColor(img2WithEpilines, img2WithEpilines, Imgproc.COLOR_GRAY2BGR);
System.out.println("kép mentése epilines_1");
Highgui.imwrite("epilines_"+ (new File(queryFile)).getName(), img2WithEpilines);
for (int r = 0; r < queLines.rows()-1; r++) {
double[] queLinesCoeff = queLines.get(r,0) ;
double a = queLinesCoeff[0];
double b = queLinesCoeff[1];
double c = queLinesCoeff[2];
Point p0 = new Point(0, -c/b);
Point p1 = new Point(img2WithEpilines.cols(), -(c+a*img2WithEpilines.cols()) / b);
Core.line(img2WithEpilines, p0,p1, new Scalar(255.0,0.0, 255.0));
}
System.out.println("kép mentése epilines_1");
Highgui.imwrite("epilines_"+ (new File(queryFile)).getName(), img2WithEpilines);
Mat img1WithEpilines = referenceImage.clone();
Imgproc.cvtColor(img1WithEpilines, img1WithEpilines, Imgproc.COLOR_GRAY2BGR);
for (int r = 0; r < refLines.rows()-1; r++) {
double[] refLinesCoeff = refLines.get(r,0) ;
double a = refLinesCoeff[0];
double b = refLinesCoeff[1];
double c = refLinesCoeff[2];
Point p0 = new Point(0, -c/b);
Point p1 = new Point(img1WithEpilines.cols(), -(c+a*img1WithEpilines.cols()) / b);
Core.line(img1WithEpilines, p0,p1, new Scalar(255.0,0.0, 255.0));
}
System.out.println("kép mentése epilines_1");
Highgui.imwrite("epilines_"+ (new File(referenceFile)).getName(), img1WithEpilines);
/// ------ rectification ------
Mat H1 = new Mat();
Mat H2 = new Mat();
Mat rectifiedImg1 = img1WithEpilines.clone();
Mat rectifiedImg2 = img2WithEpilines.clone();
Calib3d.stereoRectifyUncalibrated(refpoints, quepoints, F, queryImage.size(), H1, H2, 3);
//Imgproc.warpPerspective(queryImage, rectifiedImg2, H2, img2WithEpilines.size() );
Imgproc.warpPerspective(img2WithEpilines, rectifiedImg2, H2, img2WithEpilines.size() );
//Imgproc.warpPerspective(referenceImage, rectifiedImg1, H1, img1WithEpilines.size() );
Imgproc.warpPerspective(img1WithEpilines, rectifiedImg1, H1, img1WithEpilines.size() );
Highgui.imwrite("rectified_"+ (new File(queryFile)).getName(), rectifiedImg2);
Highgui.imwrite("rectified_ref_to_"+ (new File(queryFile)).getName(), rectifiedImg1);
} // END main
}
EpipolarGeometryExample.java
Licensed under the Creative Commons Attribution Non-commercial Share Alike License 4.0