From 6549db81a18f2f258f00d561787f00c59c225164 Mon Sep 17 00:00:00 2001 From: Simon Garnier Date: Wed, 25 Oct 2023 10:35:08 -0400 Subject: [PATCH] Add camera calibration functions + 90-degree rotations + doc fixes --- DESCRIPTION | 6 +- NAMESPACE | 7 + R/calib3d.R | 347 ++++++++++++++++++++ R/transform.R | 138 +++++++- R/zzz.R | 1 + docs/404.html | 2 +- docs/LICENSE-text.html | 2 +- docs/articles/index.html | 2 +- docs/articles/z1_install.html | 2 +- docs/articles/z2_io.html | 2 +- docs/articles/z3_basic.html | 2 +- docs/articles/z4_inplace.html | 2 +- docs/articles/z5_gpu.html | 2 +- docs/articles/z6_queue.html | 2 +- docs/authors.html | 8 +- docs/index.html | 2 +- docs/news/index.html | 2 +- docs/pkgdown.yml | 2 +- docs/reference/CLAHE.html | 2 +- docs/reference/Image-class.html | 2 +- docs/reference/LUT.html | 2 +- docs/reference/Queue-class.html | 2 +- docs/reference/Rvision.html | 2 +- docs/reference/RvisionAck.html | 2 +- docs/reference/Stream-class.html | 2 +- docs/reference/Video-class.html | 2 +- docs/reference/VideoWriter-class.html | 2 +- docs/reference/adaptiveThreshold.html | 2 +- docs/reference/addWeighted.html | 2 +- docs/reference/anisotropicDiffusion.html | 2 +- docs/reference/api.html | 2 +- docs/reference/arcLength.html | 2 +- docs/reference/as.array.Rcpp_Image.html | 2 +- docs/reference/autothreshold.html | 2 +- docs/reference/bilateralFilter.html | 2 +- docs/reference/bitdepth.html | 2 +- docs/reference/blur.html | 2 +- docs/reference/border.html | 2 +- docs/reference/boxFilter.html | 2 +- docs/reference/canny.html | 2 +- docs/reference/capacity.html | 2 +- docs/reference/cartToPolar.html | 2 +- docs/reference/cc_table.html | 2 +- docs/reference/changeBitDepth.html | 2 +- docs/reference/changeColorSpace.html | 2 +- docs/reference/click.html | 2 +- docs/reference/cloneImage.html | 2 +- docs/reference/codec.html | 2 +- docs/reference/col2bgr.html | 2 +- docs/reference/colorspace.html | 2 +- docs/reference/compare.html | 2 +- docs/reference/computeECC.html | 2 +- docs/reference/concatenate.html | 2 +- docs/reference/connectedComponents.html | 2 +- docs/reference/contourArea.html | 2 +- docs/reference/convexHull.html | 4 +- docs/reference/convexityDefects.html | 2 +- docs/reference/countNonZero.html | 2 +- docs/reference/destroyDisplay.html | 2 +- docs/reference/dim.Rcpp_Image.html | 2 +- docs/reference/dim.Rcpp_Queue.html | 2 +- docs/reference/dim.Rcpp_Stream.html | 2 +- docs/reference/dim.Rcpp_Video.html | 2 +- docs/reference/dim.Rcpp_VideoWriter.html | 2 +- docs/reference/display.html | 2 +- docs/reference/distanceTransform.html | 2 +- docs/reference/drawArrow.html | 2 +- docs/reference/drawCircle.html | 2 +- docs/reference/drawEllipse.html | 2 +- docs/reference/drawLine.html | 2 +- docs/reference/drawPolyline.html | 2 +- docs/reference/drawRectangle.html | 2 +- docs/reference/drawRotatedRectangle.html | 2 +- docs/reference/drawText.html | 2 +- docs/reference/edgePreservingFilter.html | 2 +- docs/reference/exp.html | 2 +- docs/reference/extractChannel.html | 2 +- docs/reference/farneback.html | 2 +- docs/reference/fillConvexPoly.html | 2 +- docs/reference/fillPoly.html | 2 +- docs/reference/filter2D.html | 2 +- docs/reference/findContours.html | 2 +- docs/reference/findNonZero.html | 2 +- docs/reference/findTransformECC.html | 2 +- docs/reference/findTransformORB.html | 2 +- docs/reference/fitEllipse.html | 10 +- docs/reference/flip.html | 2 +- docs/reference/floodFill.html | 2 +- docs/reference/fourcc.html | 2 +- docs/reference/fps.html | 2 +- docs/reference/frame.html | 2 +- docs/reference/full.html | 2 +- docs/reference/gaussianBlur.html | 2 +- docs/reference/getGaborKernel.html | 2 +- docs/reference/getPerspectiveTransform.html | 4 +- docs/reference/getStructuringElement.html | 2 +- docs/reference/getTextSize.html | 2 +- docs/reference/grabCut.html | 2 +- docs/reference/histEq.html | 2 +- docs/reference/histmatch.html | 2 +- docs/reference/houghCircles.html | 2 +- docs/reference/huInvariants.html | 2 +- docs/reference/image.html | 2 +- docs/reference/imageArithmetic.html | 2 +- docs/reference/imageLogic.html | 2 +- docs/reference/imageMinMax.html | 2 +- docs/reference/imhist.html | 2 +- docs/reference/improfile.html | 2 +- docs/reference/inPlaceArithmetic.html | 2 +- docs/reference/inPlaceComparison.html | 2 +- docs/reference/inPlaceLogical.html | 2 +- docs/reference/inRange.html | 2 +- docs/reference/index.html | 61 +++- docs/reference/inpaint.html | 2 +- docs/reference/insertChannel.html | 2 +- docs/reference/invert.html | 2 +- docs/reference/isBlob.html | 2 +- docs/reference/isImage.html | 2 +- docs/reference/isQueue.html | 2 +- docs/reference/isStream.html | 2 +- docs/reference/isVideo.html | 2 +- docs/reference/isVideoWriter.html | 2 +- docs/reference/laplacian.html | 2 +- docs/reference/log.html | 2 +- docs/reference/matchShapes.html | 2 +- docs/reference/matchTemplate.html | 2 +- docs/reference/mean.Rcpp_Image.html | 2 +- docs/reference/mean.list.html | 2 +- docs/reference/medianBlur.html | 2 +- docs/reference/merge.html | 2 +- docs/reference/min.Rcpp_Image.html | 2 +- docs/reference/minAreaRect.html | 10 +- docs/reference/minMaxLoc.html | 2 +- docs/reference/moments.html | 2 +- docs/reference/morph.html | 2 +- docs/reference/newDisplay.html | 2 +- docs/reference/niBlackThreshold.html | 2 +- docs/reference/nrow.Rcpp_Image.html | 2 +- docs/reference/ones.html | 2 +- docs/reference/pget.html | 2 +- docs/reference/pixelsInContour.html | 2 +- docs/reference/plot.Image.html | 2 +- docs/reference/plot.blob.html | 2 +- docs/reference/plotOF.html | 2 +- docs/reference/polarToCart.html | 2 +- docs/reference/pow.html | 2 +- docs/reference/pset.html | 2 +- docs/reference/queue.html | 2 +- docs/reference/queue_dimensions.html | 2 +- docs/reference/randn.html | 2 +- docs/reference/randu.html | 2 +- docs/reference/readFrame.html | 2 +- docs/reference/readHIS.html | 2 +- docs/reference/readMulti.html | 2 +- docs/reference/readNext.html | 2 +- docs/reference/reduce.html | 2 +- docs/reference/release.html | 2 +- docs/reference/reset.html | 2 +- docs/reference/resize.html | 2 +- docs/reference/rotateScale.html | 2 +- docs/reference/scharr.html | 2 +- docs/reference/selectROI.html | 2 +- docs/reference/sepFilter2D.html | 2 +- docs/reference/setProp.html | 2 +- docs/reference/setTo.html | 2 +- docs/reference/simpleBlobDetector.html | 2 +- docs/reference/sobel.html | 2 +- docs/reference/spatialGradient.html | 2 +- docs/reference/split.html | 2 +- docs/reference/sqrBoxFilter.html | 2 +- docs/reference/sqrt.html | 2 +- docs/reference/stream.html | 2 +- docs/reference/stream_dimensions.html | 2 +- docs/reference/sub-.Rcpp_Image.html | 2 +- docs/reference/subImage.html | 2 +- docs/reference/sum.html | 2 +- docs/reference/thinning.html | 2 +- docs/reference/threshold.html | 2 +- docs/reference/tile.html | 2 +- docs/reference/timelapse.html | 2 +- docs/reference/video.html | 2 +- docs/reference/videoWriter.html | 2 +- docs/reference/video_dimensions.html | 2 +- docs/reference/videowriter_dimensions.html | 2 +- docs/reference/warpAffine.html | 2 +- docs/reference/warpPerspective.html | 5 +- docs/reference/watershed.html | 2 +- docs/reference/write.Image.html | 2 +- docs/reference/writeFrame.html | 2 +- docs/reference/writeMulti.html | 2 +- docs/reference/writerOuput.html | 2 +- docs/reference/zeros.html | 2 +- docs/sitemap.xml | 21 ++ inst/sample_img/checkerboard6x9.png | Bin 0 -> 12918 bytes man/calibrateCamera.Rd | 97 ++++++ man/cornerSubPix.Rd | 63 ++++ man/findChessboardCorners.Rd | 62 ++++ man/findHomography.Rd | 58 ++++ man/getAffineTransform.Rd | 2 +- man/getOptimalNewCameraMatrix.Rd | 63 ++++ man/getPerspectiveTransform.Rd | 2 +- man/rotate.Rd | 50 +++ man/undistort.Rd | 58 ++++ man/warpPerspective.Rd | 3 +- src/RcppExports.cpp | 2 + src/calib3d.h | 166 ++++++++++ src/transform.h | 40 ++- src/visionModule.cpp | 23 ++ 208 files changed, 1445 insertions(+), 226 deletions(-) create mode 100644 R/calib3d.R create mode 100644 inst/sample_img/checkerboard6x9.png create mode 100644 man/calibrateCamera.Rd create mode 100644 man/cornerSubPix.Rd create mode 100644 man/findChessboardCorners.Rd create mode 100644 man/findHomography.Rd create mode 100644 man/getOptimalNewCameraMatrix.Rd create mode 100644 man/rotate.Rd create mode 100644 man/undistort.Rd create mode 100644 src/calib3d.h diff --git a/DESCRIPTION b/DESCRIPTION index f4dd01c6..4036ed53 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: Rvision Type: Package Title: Computer Vision Library for R -Version: 0.7.0 -Date: 2022-01-25 +Version: 0.7.1 +Date: 2023-10-25 Authors@R: c( person("Simon", "Garnier", email = "garnier@njit.edu", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-3886-3974")), @@ -28,7 +28,7 @@ RcppModules: class_Image, class_Capture, class_VideoWriter, methods_Arithmetic, methods_Statistics, methods_Comparisons, methods_Logical, methods_OpticalFlow, methods_Blob, methods_Morphology, methods_Filters, methods_Display, methods_Draw, methods_Geometry, methods_Shape, methods_Transform, - methods_Feature, methods_Autothresh, methods_Ximgproc + methods_Feature, methods_Autothresh, methods_Ximgproc, methods_Calib3d RoxygenNote: 7.2.3 Biarch: true StagedInstall: false diff --git a/NAMESPACE b/NAMESPACE index 258b3f12..09f1925f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -94,6 +94,7 @@ export(blur) export(border) export(boxFilter) export(boxPoints) +export(calibrateCamera) export(canny) export(capacity) export(cartToPolar) @@ -111,6 +112,7 @@ export(connectedComponents) export(contourArea) export(convexHull) export(convexityDefects) +export(cornerSubPix) export(countNonZero) export(destroyAllDisplays) export(destroyDisplay) @@ -133,7 +135,9 @@ export(farneback) export(fillConvexPoly) export(fillPoly) export(filter2D) +export(findChessboardCorners) export(findContours) +export(findHomography) export(findNonZero) export(findTransformECC) export(findTransformORB) @@ -147,6 +151,7 @@ export(full) export(gaussianBlur) export(getAffineTransform) export(getGaborKernel) +export(getOptimalNewCameraMatrix) export(getPerspectiveTransform) export(getProp) export(getStructuringElement) @@ -221,6 +226,7 @@ export(reduce) export(release) export(reset) export(resize) +export(rotate) export(rotateScale) export(scharr) export(selectROI) @@ -241,6 +247,7 @@ export(thinning) export(threshold) export(tile) export(timelapse) +export(undistort) export(video) export(videoStack) export(videoWriter) diff --git a/R/calib3d.R b/R/calib3d.R new file mode 100644 index 00000000..5099f05d --- /dev/null +++ b/R/calib3d.R @@ -0,0 +1,347 @@ +#' @title Find Calibration Chessboard in Image +#' +#' @description \code{findChessboardCorners} finds the positions of the internal +#' corners of a calibration chessboard. +#' +#' @param image An 8-bit (8U) \code{\link{Image}} object. +#' +#' @param pprow,ppcol The number of internal corners per row and column of the +#' chessboard. +#' +#' @param adaptive_threshold A logical indicating whether to use adaptive +#' thresholding (the default) to convert the image to black and white, rather +#' than a fixed threshold level (computed from the average image brightness). +#' +#' @param normalize A logical indicating whether to normalize (the default) the +#' image gamma with \code{\link{histEq}} before applying fixed or adaptive +#' thresholding. +#' +#' @param filter_quads A logical indicating whether to use additional criteria +#' (like contour area, perimeter, square-like shape) to filter out false quads +#' extracted at the contour retrieval stage (default: FALSE). +#' +#' @param fast_check logical indicating whether to run a fast check on the +#' image that looks for chessboard corners, and shortcut the call if none is +#' found. This can drastically speed up the call in the degenerate condition +#' when no chessboard is observed. +#' +#' @return A \code{(pprow * ppcol)}x\code{2} matrix. If the matrix is empty then +#' no chessboard with the indicated dimensions is detected. +#' +#' @note You can find a suitable chessboard pattern at +#' \url{https://github.com/opencv/opencv/blob/4.x/doc/pattern.png} +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @seealso \code{\link{cornerSubPix}}, \code{\link{calibrateCamera}} +#' +#' @examples +#' checkerboard <- image(system.file("sample_img/checkerboard6x9.png", package = "Rvision")) +#' pts <- findChessboardCorners(checkerboard, 6, 9) +#' +#' @export +findChessboardCorners <- function(image, pprow, ppcol, adaptive_threshold = TRUE, + normalize = TRUE, filter_quads = FALSE, fast_check = TRUE) { + if (!isImage(image)) + stop("'image' is not an Image object.") + + if (image$depth() != "8U") + stop("'image' is not an 8U 'Image' object.") + + flags <- 1 * adaptive_threshold + 2 * normalize + 4 * filter_quads + 8 * fast_check + + `_findChessboardCorners`(image, pprow, ppcol, flags) +} + + +#' @title Refine Corner Locations +#' +#' @description \code{cornerSubPix} finds the sub-pixel locations of corners or +#' radial saddle points in an image from their estimated locations. +#' +#' @param image An 8-bit (8U), single-channel (GRAY) \code{\link{Image}} object. +#' +#' @param corners A matrix of estimated corner locations as returned by +#' \code{\link{findChessboardCorners}}. +#' +#' @param win_size A vector of the half of the side length of the search window. +#' For example, if \code{win_size = c(5, 5)} , then a (5∗2+1)×(5∗2+1)=11×11 +#' search window is used (default: \code{c(11, 11)}). +#' +#' @param zero_zone A vector of the half of the size of the dead region in the +#' middle of the search zone. It is used sometimes to avoid possible +#' singularities in the detection algorithm. The value of \code{c(-1, -1)} +#' indicates that there is no such a size (the default). +#' +#' @param maxit The maximum number of iterations of the detection algorithm +#' (default: 30). +#' +#' @param eps The desired accuracy or change in parameters at which the +#' iterative algorithm stops (default: 0.0001). +#' +#' @return A \code{(pprow * ppcol)}x\code{2} matrix. If the matrix is empty then no +#' chessboard with the indicated dimensions is detected. +#' +#' @references Förstner, W., & Gülch, E. (1987). A fast operator for detection +#' and precise location of distinct points, corners and centres of circular +#' features. Proc. ISPRS Intercommission Conference on Fast Processing of +#' Photogrammetric Data, 6, 281–305. +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @seealso \code{\link{findChessboardCorners}}, \code{\link{calibrateCamera}} +#' +#' @examples +#' checkerboard <- image(system.file("sample_img/checkerboard6x9.png", package = "Rvision")) +#' pts <- findChessboardCorners(checkerboard, 6, 9) +#' checkerboard_gray <- changeColorSpace(checkerboard, "GRAY") +#' pts_refined <- cornerSubPix(checkerboard_gray, pts) +#' +#' @export +cornerSubPix <- function(image, corners, win_size = c(11, 11), zero_zone = c(-1, -1), + maxit = 30, eps = 0.0001) { + if (!isImage(image)) + stop("'image' is not an Image object.") + + if (image$depth() != "8U") + stop("'image' is not an 8U 'Image' object.") + + if (image$nchan() != 1) + stop("'image' is not a single channel 'Image' object.") + + if (ncol(corners) != 2) + stop("'corners' is not a 2-column matrix.") + + if (nrow(corners) < 1) + stop("'corners' does not contain any value.") + + `_cornerSubPix`(image, corners, win_size, zero_zone, maxit, eps) +} + + +#' @title Find a Camera's Intrinsic and Extrinsic Parameters +#' +#' @description \code{calibrateCamera} finds a camera's intrinsic and extrinsic +#' parameters from several views of a calibration pattern. +#' +#' @param ref_points List of matrices of calibration pattern points for each +#' view, in the calibration pattern coordinate space. Each matrix should have +#' the same dimensions as the corresponding matrix in \code{img_points}. +#' +#' @param img_points List of matrices of the projections of the calibration +#' pattern points in each view. If \code{fixed_point > 0}, the same calibration +#' pattern must be used in each view and it must be fully visible. Moreover, +#' all matrices must have the same dimensions and all points in the calibration +#' pattern should be roughly close to a plane. The calibration target has to be +#' rigid, or at least static if the camera (rather than the calibration target) +#' is shifted when grabbing views. See \code{\link{findChessboardCorners}} and +#' \code{\link{cornerSubPix}} for more information about generating projection +#' matrices from images of the calibration pattern. +#' +#' @param nrow,ncol The number of rows and columns of the images used to capture +#' different views of the calibration pattern. +#' +#' @param fixed_point The index of the reference point in \code{ref_points[[1]]} +#' to be fixed (default: 1). Usually the top-right corner point of the +#' calibration pattern is recommended to be fixed. If \code{fixed_point = 0}, +#' then no point is fixed and a less precise calibration algorithm is then +#' used. +#' +#' @param maxit The maximum number of iterations of the detection algorithm +#' (default: 30). +#' +#' @param eps The desired accuracy or change in parameters at which the +#' iterative algorithm stops (default: \code{.Machine$double.eps}). +#' +#' @return A list of matrices: +#' \itemize{ +#' \item{\code{camera_matrix}:}{a 3x3 camera intrinsic matrix.} +#' \item{\code{dist_coeffs:}}{a single row matrix with 4, 5, 8, 12 or 14 +#' elements representing distortion coefficients.} +#' \item{\code{r_vecs:}}{a 3x\code{length(img_points)} matrix of the rotation +#' vectors estimated for each calibration pattern view. Together with the +#' translation vectors below, this is equivalent to the position of the +#' calibration pattern with respect to the camera coordinate space.} +#' \item{\code{t_vecs:}}{a 3x\code{length(img_points)} matrix of the +#' translation vectors estimated for each calibration pattern view. Together +#' with the rotation vectors above, this is equivalent to the position of the +#' calibration pattern with respect to the camera coordinate space.} +#' \item{\code{new_ref_points:}}{If \code{fixed_point > 0}, this is an updated +#' matrix of calibration pattern points. The coordinates might be scaled +#' based on the fixed point defined above. The returned coordinates are +#' accurate only if the above mentioned fixed point is accurate. If +#' \code{fixed_point = 0}, an empty matrix is returned instead.} +#' } +#' +#' @references Bouguet, J.-Y. (2022). Camera Calibration Toolbox for Matlab. +#' CaltechDATA. https://doi.org/10.22002/D1.20164 +#' +#' Strobl, K. H., & Hirzinger, G. (2011, November). More accurate pinhole +#' camera calibration with imperfect planar target. 2011 IEEE International +#' Conference on Computer Vision Workshops (ICCV Workshops). 2011 IEEE +#' International Conference on Computer Vision Workshops (ICCV Workshops), +#' Barcelona, Spain. https://doi.org/10.1109/iccvw.2011.6130369 +#' +#' Zhang, Z. (2000). A flexible new technique for camera calibration. IEEE +#' Transactions on Pattern Analysis and Machine Intelligence, 22(11), 1330–1334. +#' https://doi.org/10.1109/34.888718 +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @seealso \code{\link{findChessboardCorners}}, \code{\link{cornerSubPix}}, +#' \code{\link{getOptimalNewCameraMatrix}} +#' +#' @examples +#' # See the help vignette: +#' \dontrun{ vignette("", package = "Rvision") } +#' +#' @export +calibrateCamera <- function(ref_points, img_points, nrow, ncol, fixed_point = 1, + maxit = 30, eps = .Machine$double.eps) { + if (length(ref_points) != length(img_points)) + stop("'ref_points' and 'img_points' should have the same length.") + + if (!all(sapply(ref_points, nrow) == sapply(img_points, nrow))) + stop("Each matrix in 'ref_points' should have the same number of rows as the corresponding matrix in 'img_points'.") + + `_calibrateCameraRO`(ref_points, img_points, c(nrow, ncol), fixed_point, + 0, maxit, eps) +} + + +#' @title Camera Matrix Correction Using the Free Scaling Parameter +#' +#' @description \code{getOptimalNewCameraMatrix} computes and returns an optimal +#' new camera intrinsic matrix based on the free scaling parameter \code{alpha}. +#' By varying this parameter, you may retrieve only sensible pixels +#' \code{alpha = 0} , keep all the original image pixels if there is valuable +#' information in the corners \code{alpha = 1}, or get something in between. +#' When \code{alpha > 0}, the undistorted result is likely to have some black +#' pixels corresponding to "virtual" pixels outside of the captured distorted +#' image. +#' +#' @param camera_matrix A 3x3 camera intrinsic matrix as returned by +#' \code{\link{calibrateCamera}}. +#' +#' @param dist_coefs A single row matrix with 4, 5, 8, 12 or 14 elements as +#' returned by \code{\link{calibrateCamera}}. +#' +#' @param nrow,ncol The number of rows and columns of the image to undistort. +#' +#' @param alpha A numeric value corresponding to the free scaling parameter +#' between 0 (only valid pixels in the the source image are retained in the +#' undistorted image; the default) and 1 (all the source image pixels are +#' retained in the undistorted image). +#' +#' @param center_principal_point A boolean that indicates whether in the new +#' camera intrinsic matrix the principal point should be at the image center or +#' not (the default). The principal point is chosen to best fit a subset of the +#' source image (determined by alpha) to the corrected image. +#' +#' @return A list: +#' \itemize{ +#' \item{\code{camera_matrix}:}{the new 3x3 camera intrinsic matrix.} +#' \item{\code{roi:}}{a 4-element list defining a rectangle that outlines +#' the all-valid-pixels region in the undistorted image.} +#' } +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @seealso \code{\link{calibrateCamera}} +#' +#' @examples +#' # See the help vignette: +#' \dontrun{ vignette("", package = "Rvision") } +#' +#' @export +getOptimalNewCameraMatrix <- function(camera_matrix, dist_coefs, nrow, ncol, + alpha = 0, center_principal_point = FALSE) { + if (!all(dim(camera_matrix) == 3)) + stop("'camera_matrix' should have exactly 3 rows and 3 columns.") + + if (!all(dim(dist_coefs) == c(1, 5))) + stop("'dist_coefs' should have exactly 1 row and 5 columns.") + + `_getOptimalNewCameraMatrix`(camera_matrix, dist_coefs, c(nrow, ncol), alpha, + center_principal_point) +} + + +#' @title Compensate for Lens Distortion +#' +#' @description \code{undistort} transforms an image to compensate for radial +#' and tangential lens distortion. +#' +#' @param camera_matrix A 3x3 camera intrinsic matrix as returned by +#' \code{\link{calibrateCamera}}. +#' +#' @param dist_coefs A single row matrix with 4, 5, 8, 12 or 14 elements as +#' returned by \code{\link{calibrateCamera}}. +#' +#' @param new_camera_matrix A 3x3 camera intrinsic matrix as returned by +#' \code{\link{getOptimalNewCameraMatrix}} if you chose to execute this +#' optional step (default: NULL). +#' +#' @param target The location where the results should be stored. It can take 3 +#' values: +#' \itemize{ +#' \item{"new":}{a new \code{\link{Image}} object is created and the results +#' are stored inside (the default).} +#' \item{An \code{\link{Image}} object:}{the results are stored in another +#' existing \code{\link{Image}} object. This is fast and will not replace the +#' content of \code{image} but will replace that of \code{target}. Note that +#' \code{target} must have the same dimensions, bit depth, and number of +#' channels as \code{image}.} +#' } +#' +#' @return If \code{target="new"}, the function returns an \code{\link{Image}} +#' object. If \code{target} is an \code{\link{Image}} object, the function +#' returns nothing and modifies that \code{\link{Image}} object in place. +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @seealso \code{\link{findChessboardCorners}}, \code{\link{cornerSubPix}}, +#' \code{\link{calibrateCamera}}, \code{\link{getOptimalNewCameraMatrix}} +#' +#' @examples +#' # See the help vignette: +#' \dontrun{ vignette("", package = "Rvision") } +#' +#' @export +undistort <- function(image, camera_matrix, dist_coefs, new_camera_matrix = NULL, + target = "new") { + if (!isImage(image)) + stop("'image' is not an Image object.") + + if (!all(dim(camera_matrix) == 3)) + stop("'camera_matrix' should have exactly 3 rows and 3 columns.") + + if (!all(dim(new_camera_matrix) == 3)) + stop("'new_camera_matrix' should have exactly 3 rows and 3 columns.") + + if (!all(dim(dist_coefs) == c(1, 5))) + stop("'dist_coefs' should have exactly 1 row and 5 columns.") + + if (isImage(target)) { + if (identical(image, target)) + stop("'image' and 'target' cannot be the same Image object.") + + if (is.null(new_camera_matrix)) { + `_undistortNoNCM`(image, camera_matrix, dist_coefs, target) + } else { + `_undistort`(image, camera_matrix, dist_coefs, new_camera_matrix, target) + } + } else if (target == "new") { + out <- zeros(image$nrow(), image$ncol(), image$nchan(), image$depth(), image$space) + + if (is.null(new_camera_matrix)) { + `_undistortNoNCM`(image, camera_matrix, dist_coefs, out) + } else { + `_undistort`(image, camera_matrix, dist_coefs, new_camera_matrix, out) + } + + out + } else { + stop("Invalid target.") + } +} \ No newline at end of file diff --git a/R/transform.R b/R/transform.R index ca98fcdf..4ce657ea 100644 --- a/R/transform.R +++ b/R/transform.R @@ -1,3 +1,58 @@ +#' @title Perspective Transformation Between Two Planes +#' +#' @description \code{findHomography} computes a perspective transformation +#' between two planes. +#' +#' @param template A grayscale \code{\link{Image}} object. +#' +#' @param src_x,src_y Vector of coordinates of the points in the original plane. +#' +#' @param dst_x,dst_y Vector of coordinates of the points in the target plane. +#' +#' @param method A character string indicating the method used to compute a +#' homography matrix. It can be one of the followings: "LS" (least-square), +#' "RANSAC" (RANSAC-based robust method; the default), "LMEDS" (Least-Median +#' robust method), or "RHO" (PROSAC-based robust method). +#' +#' @param ransac_reproj_th Maximum allowed reprojection error to treat a point +#' pair as an inlier (used in the RANSAC and RHO methods only). That is, if +#' `src_x`, `src_y`, `dst_x`, and `dst_y` are measured in pixels, it usually +#' makes sense to set this parameter somewhere in the range of 1 to 10. +#' +#' @param max_it The maximum number of RANSAC iterations. +#' +#' @param conf Confidence level, between 0 and 1. +#' +#' @return A 3x3 homography matrix. +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @seealso \code{\link{getPerspectiveTransform}}, \code{\link{getAffineTransform}}, +#' \code{\link{warpPerspective}} +#' +#' @examples +#' src <- cbind(x = c(0, 1, 1, 0), y = c(0, 0, 1, 1)) +#' dst <- src + 1 +#' findHomography(src[, 1], src[, 2], dst[, 1], dst[, 2]) +#' +#' @export +findHomography <- function(src_x, src_y, dst_x, dst_y, method = "RANSAC", + ransac_reproj_th = 3, max_it = 2000, conf = 0.95) { + if (!all(length(src_x) == c(length(src_y), length(dst_x), length(dst_y)))) + stop("'src_x', 'src_y', 'dst_x', and 'dst_y' must have the same length.") + + `_findHomography`(src_x, src_y, dst_x, dst_y, + switch(method, + "LS" = 0, + "RANSAC" = 4, + "LMEDS" = 8, + "RHO" = 16, + stop("This is not a valid method. 'homography_method' + must be one of 'LS', 'RANSAC', 'LMEDS', or 'RHO'.")), + ransac_reproj_th, max_it, conf) +} + + #' @title Enhanced Correlation Coefficient Value #' #' @description \code{computeECC} computes the Enhanced Correlation Coefficient @@ -283,6 +338,80 @@ rotateScale <- function(image, center = (dim(image)[2:1] - 1) / 2, angle = 90, s } +#' @title Image Rotation In 90-Degree Increments +#' +#' @description \code{rotate} rotates an image in multiples of 90 degrees. +#' +#' @param image An \code{\link{Image}} object. +#' +#' @param rotation A character string indicating the desired rotation: +#' \itemize{ +#' \item{"CLOCKWISE" (default):}{rotate by 90 degrees clockwise.} +#' \item{"COUNTER":}{rotate by 90 degrees counterclockwise.} +#' \item{"180":}{rotate by 180 degrees.} +#' } +#' +#' @param target The location where the results should be stored. It can take 3 +#' values: +#' \itemize{ +#' \item{"new":}{a new \code{\link{Image}} object is created and the results +#' are stored inside (the default).} +#' \item{An \code{\link{Image}} object:}{the results are stored in another +#' existing \code{\link{Image}} object. This is fast and will not replace the +#' content of \code{image} but will replace that of \code{target}. Note that +#' \code{target} must have the same bit depth and number of channels as +#' \code{image}. The dimensions must be the same if \code{rotation="CLOCKWISE"}, +#' or inverted if \code{rotation="CLOCKWISE"} or \code{rotation="COUNTER"}.} +#' } +#' +#' @return If \code{target="new"}, the function returns an \code{\link{Image}} +#' object. If \code{target} is an \code{\link{Image}} object, the function +#' returns nothing and modifies that \code{\link{Image}} object in place. +#' +#' @author Simon Garnier, \email{garnier@@njit.edu} +#' +#' @seealso \code{\link{rotateScale}} +#' +#' @examples +#' img <- image(system.file("sample_img/balloon1.png", package = "Rvision")) +#' img_rotated <- rotate(img) +#' +#' @export +rotate <- function(image, rotation = "CLOCKWISE", target = "new") { + if (!isImage(image)) + stop("'image' is not an Image object.") + + code <- switch(rotation, + "CLOCKWISE" = 0, + "COUNTER" = 2, + "180" = 1, + stop("This is not a valid rotation. 'rotation' must be one of + 'CLOCKWISE', 'COUNTER', or '180'.")) + + if (isImage(target)) { + if (code %in% c(0, 2) & !all(image$dim() == target$dim()[c(2:1), 3])) + stop("Incorrect 'target' dimensions.") + + if ((code == 1) & !all(image$dim() == target$dim())) + stop("Incorrect 'target' dimensions.") + + `_rotate`(image, code, target) + } else if (target == "new") { + if (code %in% c(0, 2)) { + out <- zeros(image$ncol(), image$nrow(), image$nchan(), image$depth(), image$space) + } else { + out <- zeros(image$nrow(), image$ncol(), image$nchan(), image$depth(), image$space) + } + + `_rotate`(image, code, out) + out + } else { + stop("Invalid target.") + } + +} + + #' @title Affine Transformation #' #' @description \code{warpAffine} applies an affine transformation to an image. @@ -291,8 +420,6 @@ rotateScale <- function(image, center = (dim(image)[2:1] - 1) / 2, angle = 90, s #' #' @param warp_matrix A 2x3 numeric matrix. #' -#' -#' #' @param interp_mode A character string indicating the interpolation method to #' be used. It can be #' any of the following: @@ -432,7 +559,7 @@ warpAffine <- function(image, warp_matrix, interp_mode = "linear", inverse_map = #' #' @author Simon Garnier, \email{garnier@@njit.edu} #' -#' @seealso \code{\link{warpPerspective}} +#' @seealso \code{\link{warpPerspective}}, \code{\link{findHomography}} #' #' @examples #' from <- matrix(c(1, 1, 2, 5, 6, 5, 5, 1), nrow = 4, byrow = TRUE) @@ -477,7 +604,7 @@ getPerspectiveTransform <- function(from, to, from_dim, to_dim = from_dim) { #' #' @author Simon Garnier, \email{garnier@@njit.edu} #' -#' @seealso \code{\link{warpAffine}} +#' @seealso \code{\link{warpAffine}}, \code{\link{findHomography}} #' #' @examples #' from <- matrix(c(1, 1, 2, 5, 6, 5, 5, 1), nrow = 4, byrow = TRUE) @@ -567,7 +694,8 @@ getAffineTransform <- function(from, to, from_dim, to_dim = from_dim) { #' #' @author Simon Garnier, \email{garnier@@njit.edu} #' -#' @seealso \code{\link{warpPerspective}}, \code{\link{findTransformECC}} +#' @seealso \code{\link{warpPerspective}}, \code{\link{findTransformECC}}, +#' \code{\link{findHomography}} #' #' @examples #' file1 <- system.file("sample_img/balloon1.png", package = "Rvision") diff --git a/R/zzz.R b/R/zzz.R index c6c84a12..822a2eb6 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -30,6 +30,7 @@ Rcpp::loadModule("methods_Transform", TRUE) Rcpp::loadModule("methods_Feature", TRUE) Rcpp::loadModule("methods_Autothresh", TRUE) Rcpp::loadModule("methods_Ximgproc", TRUE) +Rcpp::loadModule("methods_Calib3d", TRUE) ### Define generic arithmetic methods ### diff --git a/docs/404.html b/docs/404.html index 41607cf6..beaec25c 100644 --- a/docs/404.html +++ b/docs/404.html @@ -31,7 +31,7 @@ Rvision - 0.7.0 + 0.7.1