forked from Rightpoint/opencv
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request opencv#16366 from themechanicalcoder:features2D-tu…
…torial-python * Add python version of panorama_stitching_rotating_camera and perspective_correction * Updated code * added in the docs * added python code in the docs * docs change * Add java tutorial as well * Add toggle in documentation * Added the link for Java code * format code * Refactored code
- Loading branch information
1 parent
86e5e8d
commit 126b0d8
Showing
5 changed files
with
406 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
samples/java/tutorial_code/features2D/Homography/PanoramaStitchingRotatingCamera.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import org.opencv.core.*; | ||
import org.opencv.core.Range; | ||
import org.opencv.highgui.HighGui; | ||
import org.opencv.imgcodecs.Imgcodecs; | ||
import org.opencv.imgproc.Imgproc; | ||
|
||
|
||
class PanoramaStitchingRotatingCameraRun { | ||
void basicPanoramaStitching (String[] args) { | ||
String img1path = args[0], img2path = args[1]; | ||
Mat img1 = new Mat(), img2 = new Mat(); | ||
img1 = Imgcodecs.imread(img1path); | ||
img2 = Imgcodecs.imread(img2path); | ||
|
||
//! [camera-pose-from-Blender-at-location-1] | ||
Mat c1Mo = new Mat( 4, 4, CvType.CV_64FC1 ); | ||
c1Mo.put(0 ,0 ,0.9659258723258972, 0.2588190734386444, 0.0, 1.5529145002365112, | ||
0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443, | ||
-0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654, | ||
0, 0, 0, 1 ); | ||
//! [camera-pose-from-Blender-at-location-1] | ||
|
||
//! [camera-pose-from-Blender-at-location-2] | ||
Mat c2Mo = new Mat( 4, 4, CvType.CV_64FC1 ); | ||
c2Mo.put(0, 0, 0.9659258723258972, -0.2588190734386444, 0.0, -1.5529145002365112, | ||
-0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443, | ||
0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654, | ||
0, 0, 0, 1); | ||
//! [camera-pose-from-Blender-at-location-2] | ||
|
||
//! [camera-intrinsics-from-Blender] | ||
Mat cameraMatrix = new Mat(3, 3, CvType.CV_64FC1); | ||
cameraMatrix.put(0, 0, 700.0, 0.0, 320.0, 0.0, 700.0, 240.0, 0, 0, 1 ); | ||
//! [camera-intrinsics-from-Blender] | ||
|
||
//! [extract-rotation] | ||
Range rowRange = new Range(0,3); | ||
Range colRange = new Range(0,3); | ||
//! [extract-rotation] | ||
|
||
//! [compute-rotation-displacement] | ||
//c1Mo * oMc2 | ||
Mat R1 = new Mat(c1Mo, rowRange, colRange); | ||
Mat R2 = new Mat(c2Mo, rowRange, colRange); | ||
Mat R_2to1 = new Mat(); | ||
Core.gemm(R1, R2.t(), 1, new Mat(), 0, R_2to1 ); | ||
//! [compute-rotation-displacement] | ||
|
||
//! [compute-homography] | ||
Mat tmp = new Mat(), H = new Mat(); | ||
Core.gemm(cameraMatrix, R_2to1, 1, new Mat(), 0, tmp); | ||
Core.gemm(tmp, cameraMatrix.inv(), 1, new Mat(), 0, H); | ||
Scalar s = new Scalar(H.get(2, 2)[0]); | ||
Core.divide(H, s, H); | ||
System.out.println(H.dump()); | ||
//! [compute-homography] | ||
|
||
//! [stitch] | ||
Mat img_stitch = new Mat(); | ||
Imgproc.warpPerspective(img2, img_stitch, H, new Size(img2.cols()*2, img2.rows()) ); | ||
Mat half = new Mat(); | ||
half = new Mat(img_stitch, new Rect(0, 0, img1.cols(), img1.rows())); | ||
img1.copyTo(half); | ||
//! [stitch] | ||
|
||
Mat img_compare = new Mat(); | ||
Mat img_space = Mat.zeros(new Size(50, img1.rows()), CvType.CV_8UC3); | ||
List<Mat>list = new ArrayList<>(); | ||
list.add(img1); | ||
list.add(img_space); | ||
list.add(img2); | ||
Core.hconcat(list, img_compare); | ||
|
||
HighGui.imshow("Compare Images", img_compare); | ||
HighGui.imshow("Panorama Stitching", img_stitch); | ||
HighGui.waitKey(0); | ||
System.exit(0); | ||
} | ||
} | ||
|
||
public class PanoramaStitchingRotatingCamera { | ||
public static void main(String[] args) { | ||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME); | ||
new PanoramaStitchingRotatingCameraRun().basicPanoramaStitching(args); | ||
} | ||
} |
89 changes: 89 additions & 0 deletions
89
samples/java/tutorial_code/features2D/Homography/PerspectiveCorrection.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Random; | ||
|
||
import org.opencv.core.*; | ||
import org.opencv.calib3d.Calib3d; | ||
import org.opencv.highgui.HighGui; | ||
import org.opencv.imgcodecs.Imgcodecs; | ||
import org.opencv.imgproc.Imgproc; | ||
|
||
|
||
class PerspectiveCorrectionRun { | ||
void perspectiveCorrection (String[] args) { | ||
String img1Path = args[0], img2Path = args[1]; | ||
Mat img1 = Imgcodecs.imread(img1Path); | ||
Mat img2 = Imgcodecs.imread(img2Path); | ||
|
||
//! [find-corners] | ||
MatOfPoint2f corners1 = new MatOfPoint2f(), corners2 = new MatOfPoint2f(); | ||
boolean found1 = Calib3d.findChessboardCorners(img1, new Size(9, 6), corners1 ); | ||
boolean found2 = Calib3d.findChessboardCorners(img2, new Size(9, 6), corners2 ); | ||
//! [find-corners] | ||
|
||
if (!found1 || !found2) { | ||
System.out.println("Error, cannot find the chessboard corners in both images."); | ||
System.exit(-1); | ||
} | ||
|
||
//! [estimate-homography] | ||
Mat H = new Mat(); | ||
H = Calib3d.findHomography(corners1, corners2); | ||
System.out.println(H.dump()); | ||
//! [estimate-homography] | ||
|
||
//! [warp-chessboard] | ||
Mat img1_warp = new Mat(); | ||
Imgproc.warpPerspective(img1, img1_warp, H, img1.size()); | ||
//! [warp-chessboard] | ||
|
||
Mat img_draw_warp = new Mat(); | ||
List<Mat> list1 = new ArrayList<>(), list2 = new ArrayList<>() ; | ||
list1.add(img2); | ||
list1.add(img1_warp); | ||
Core.hconcat(list1, img_draw_warp); | ||
HighGui.imshow("Desired chessboard view / Warped source chessboard view", img_draw_warp); | ||
|
||
//! [compute-transformed-corners] | ||
Mat img_draw_matches = new Mat(); | ||
list2.add(img1); | ||
list2.add(img2); | ||
Core.hconcat(list2, img_draw_matches); | ||
Point []corners1Arr = corners1.toArray(); | ||
|
||
for (int i = 0 ; i < corners1Arr.length; i++) { | ||
Mat pt1 = new Mat(3, 1, CvType.CV_64FC1), pt2 = new Mat(); | ||
pt1.put(0, 0, corners1Arr[i].x, corners1Arr[i].y, 1 ); | ||
|
||
Core.gemm(H, pt1, 1, new Mat(), 0, pt2); | ||
double[] data = pt2.get(2, 0); | ||
Core.divide(pt2, new Scalar(data[0]), pt2); | ||
|
||
double[] data1 =pt2.get(0, 0); | ||
double[] data2 = pt2.get(1, 0); | ||
Point end = new Point((int)(img1.cols()+ data1[0]), (int)data2[0]); | ||
Imgproc.line(img_draw_matches, corners1Arr[i], end, RandomColor(), 2); | ||
} | ||
|
||
HighGui.imshow("Draw matches", img_draw_matches); | ||
HighGui.waitKey(0); | ||
//! [compute-transformed-corners] | ||
|
||
System.exit(0); | ||
} | ||
|
||
Scalar RandomColor () { | ||
Random rng = new Random(); | ||
int r = rng.nextInt(256); | ||
int g = rng.nextInt(256); | ||
int b = rng.nextInt(256); | ||
return new Scalar(r, g, b); | ||
} | ||
} | ||
|
||
public class PerspectiveCorrection { | ||
public static void main (String[] args) { | ||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME); | ||
new PerspectiveCorrectionRun().perspectiveCorrection(args); | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
samples/python/tutorial_code/features2D/Homography/panorama_stitching_rotating_camera.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
|
||
# Python 2/3 compatibility | ||
from __future__ import print_function | ||
|
||
import numpy as np | ||
import cv2 as cv | ||
|
||
def basicPanoramaStitching(img1Path, img2Path): | ||
img1 = cv.imread(cv.samples.findFile(img1Path)) | ||
img2 = cv.imread(cv.samples.findFile(img2Path)) | ||
|
||
# [camera-pose-from-Blender-at-location-1] | ||
c1Mo = np.array([[0.9659258723258972, 0.2588190734386444, 0.0, 1.5529145002365112], | ||
[ 0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443], | ||
[-0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654], | ||
[0, 0, 0, 1]],dtype=np.float64) | ||
# [camera-pose-from-Blender-at-location-1] | ||
|
||
# [camera-pose-from-Blender-at-location-2] | ||
c2Mo = np.array([[0.9659258723258972, -0.2588190734386444, 0.0, -1.5529145002365112], | ||
[-0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443], | ||
[0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654], | ||
[0, 0, 0, 1]],dtype=np.float64) | ||
# [camera-pose-from-Blender-at-location-2] | ||
|
||
# [camera-intrinsics-from-Blender] | ||
cameraMatrix = np.array([[700.0, 0.0, 320.0], [0.0, 700.0, 240.0], [0, 0, 1]], dtype=np.float32) | ||
# [camera-intrinsics-from-Blender] | ||
|
||
# [extract-rotation] | ||
R1 = c1Mo[0:3, 0:3] | ||
R2 = c2Mo[0:3, 0:3] | ||
#[extract-rotation] | ||
|
||
# [compute-rotation-displacement] | ||
R2 = R2.transpose() | ||
R_2to1 = np.dot(R1,R2) | ||
# [compute-rotation-displacement] | ||
|
||
# [compute-homography] | ||
H = cameraMatrix.dot(R_2to1).dot(np.linalg.inv(cameraMatrix)) | ||
H = H / H[2][2] | ||
# [compute-homography] | ||
|
||
# [stitch] | ||
img_stitch = cv.warpPerspective(img2, H, (img2.shape[1]*2, img2.shape[0])) | ||
img_stitch[0:img1.shape[0], 0:img1.shape[1]] = img1 | ||
# [stitch] | ||
|
||
img_space = np.zeros((img1.shape[0],50,3), dtype=np.uint8) | ||
img_compare = cv.hconcat([img1,img_space, img2]) | ||
|
||
cv.imshow("Final", img_compare) | ||
cv.imshow("Panorama", img_stitch) | ||
cv.waitKey(0) | ||
|
||
def main(): | ||
import argparse | ||
parser = argparse.ArgumentParser(description="Code for homography tutorial. Example 5: basic panorama stitching from a rotating camera.") | ||
parser.add_argument("-I1","--image1", help = "path to first image", default="Blender_Suzanne1.jpg") | ||
parser.add_argument("-I2","--image2", help = "path to second image", default="Blender_Suzanne2.jpg") | ||
args = parser.parse_args() | ||
print("Panorama Stitching Started") | ||
basicPanoramaStitching(args.image1, args.image2) | ||
print("Panorama Stitching Completed Successfully") | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Oops, something went wrong.