diff --git a/NAMESPACE b/NAMESPACE
index 2079d710..b25ce1c5 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -145,6 +145,7 @@ export(fps)
export(frame)
export(full)
export(gaussianBlur)
+export(getAffineTransform)
export(getGaborKernel)
export(getPerspectiveTransform)
export(getProp)
diff --git a/R/StreamClass.R b/R/StreamClass.R
index aad0ff61..81478f07 100644
--- a/R/StreamClass.R
+++ b/R/StreamClass.R
@@ -29,9 +29,18 @@
#' @description Function for creating \code{\link{Stream}} objects from video
#' streams.
#'
-#' @param index An integer value corresponding to the index of the camera to
-#' read a stream from (default: 0; 0 is usually the default webcam on most
-#' computers).
+#' @param ... Either:
+#' \itemize{
+#' \item{index: }{An integer value corresponding to the index of the camera
+#' to read a stream from (default: 0; 0 is usually the default webcam on
+#' most computers). Or...}
+#' \item{stream_string: }{...a character string corresponfing to the URL of
+#' video stream (eg. protocol://host:port/script_name?script_params|auth)
+#' or a GStreamer pipeline string in gst-launch tool format if GStreamer is
+#' used as backend API. Note that each video stream or IP camera feed has
+#' its own URL scheme. Please refer to the documentation of source stream
+#' to know the right URL format.}
+#' }
#'
#' @param api A character string corresponding to the API to use for reading the
#' stream from the camera (see Note; default: "ANY").
@@ -77,8 +86,17 @@
#' }
#'
#' @export
-stream <- function(index = 0, api = "ANY") {
- new(Stream, index = index, api = api)
+stream <- function(..., api = "ANY") {
+ args <- list(...)
+
+ if (!inherits(args[[1]], "character"))
+ args[[1]] <- as.integer(args[[1]])
+
+ if (length(args) > 1)
+ if (inherits(args[[2]], "character"))
+ api <- args[[2]]
+
+ new(Stream, args[[1]], api = api)
}
diff --git a/R/feature.R b/R/feature.R
index 959429cb..5ff0431d 100644
--- a/R/feature.R
+++ b/R/feature.R
@@ -366,7 +366,7 @@ ORBkeypoints <- function(image, mask = NULL, n_features = 500, scale_factor = 1.
st <- switch(score_type,
"HARRIS" = 0,
- "FAST" = 0,
+ "FAST" = 1,
stop("Invalid score type.")
)
diff --git a/R/transform.R b/R/transform.R
index 28eccef2..ca98fcdf 100644
--- a/R/transform.R
+++ b/R/transform.R
@@ -453,6 +453,51 @@ getPerspectiveTransform <- function(from, to, from_dim, to_dim = from_dim) {
}
+#' @title Affine Transform
+#'
+#' @description \code{getAffineTransform} computes the matrix of an affine
+#' transform from 4 pairs of corresponding points in a source and destination
+#' image.
+#'
+#' @param from A 4x2 matrix indicating the location (x, y) of 4 points in the
+#' source image.
+#'
+#' @param to A 4x2 matrix indicating the location (x, y) of 4 points in the
+#' destination image. The order of the points must correspond to the order in
+#' \code{from}.
+#'
+#' @param from_dim A vector which first two elements indicate the number of rows
+#' and columns of the source image.
+#'
+#' @param to_dim A vector which first two elements indicate the number of rows
+#' and columns of the destination image. If not specified, \code{from_dim} will
+#' be used as a default.
+#'
+#' @return A 3x3 matrix.
+#'
+#' @author Simon Garnier, \email{garnier@@njit.edu}
+#'
+#' @seealso \code{\link{warpAffine}}
+#'
+#' @examples
+#' from <- matrix(c(1, 1, 2, 5, 6, 5, 5, 1), nrow = 4, byrow = TRUE)
+#' to <- matrix(c(1, 1, 1, 5, 5, 5, 5, 1), nrow = 4, byrow = TRUE)
+#' getAffineTransform(from, to, c(1080, 1920), c(1080, 1920))
+#'
+#' @export
+getAffineTransform <- function(from, to, from_dim, to_dim = from_dim) {
+ if (any(dim(from) != c(4, 2)) | any(dim(to) != c(4, 2)))
+ stop("'from' and 'to' must be 4x2 matrices.")
+
+ from[, 1] <- from[, 1] - 1
+ from[, 2] <- -from[, 2] + from_dim[1]
+ to[, 1] <- to[, 1] - 1
+ to[, 2] <- -to[, 2] + from_dim[1] - (from_dim[1] - to_dim[1])
+
+ `_getAffineTransform`(from, to)
+}
+
+
#' @title Perspective Transformation
#'
#' @description \code{warpPerspective} applies a perspective transformation to
diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml
index d4024888..3e94647e 100644
--- a/docs/pkgdown.yml
+++ b/docs/pkgdown.yml
@@ -9,7 +9,7 @@ articles:
z5_gpu: z5_gpu.html
z6_queue: z6_queue.html
z7_stack: z7_stack.html
-last_built: 2023-08-08T12:51Z
+last_built: 2023-08-09T18:21Z
urls:
reference: https://swarm-lab.github.io/Rvision/reference
article: https://swarm-lab.github.io/Rvision/articles
diff --git a/docs/reference/convexHull.html b/docs/reference/convexHull.html
index 3ca17448..869052f0 100644
--- a/docs/reference/convexHull.html
+++ b/docs/reference/convexHull.html
@@ -98,7 +98,7 @@
Author<
Examples
convexHull(rnorm(100), rnorm(100))
-#> [1] 3 80 86 43 5 87 76 93 30 70
+#> [1] 18 27 42 50 95 51 52
diff --git a/docs/reference/fitEllipse.html b/docs/reference/fitEllipse.html
index f2b2fc0f..11aa0a99 100644
--- a/docs/reference/fitEllipse.html
+++ b/docs/reference/fitEllipse.html
@@ -119,16 +119,16 @@ Author<
Examples
fitEllipse(rnorm(100), rnorm(100))
#> $angle
-#> [1] 59.89347
+#> [1] 68.14399
#>
#> $height
-#> [1] 4.499532
+#> [1] 4.426012
#>
#> $width
-#> [1] 3.404044
+#> [1] 3.899822
#>
#> $center
-#> [1] -0.20713183 -0.01245182
+#> [1] -0.00229378 -0.37228656
#>
diff --git a/docs/reference/index.html b/docs/reference/index.html
index 9a95aa9b..cf1fcce1 100644
--- a/docs/reference/index.html
+++ b/docs/reference/index.html
@@ -290,7 +290,7 @@ All functionsdestroyDisplay() destroyAllDisplays()
- Destroy Image
Display
+ Destroy Image
Display
-
dim(<Rcpp_Image>)
@@ -325,7 +325,7 @@
- - Display
Image
Object
+ - Display
Image
Object
-
distanceTransform()
@@ -335,22 +335,22 @@
- - Draw Arrows on an
Image
+ - Draw Arrows on an
Image
-
drawCircle()
- - Draw Circles on an
Image
+ - Draw Circles on an
Image
-
drawEllipse()
- - Draw Ellipses on an
Image
+ - Draw Ellipses on an
Image
-
drawLine()
- - Draw Lines on an
Image
+ - Draw Lines on an
Image
-
drawPolyline()
@@ -360,17 +360,17 @@
- - Draw Rectangles on an
Image
+ - Draw Rectangles on an
Image
-
drawRotatedRectangle()
- - Draw Rotated Rectangles on an
Image
+ - Draw Rotated Rectangles on an
Image
-
drawText()
- - Draw Text on an
Image
+ - Draw Text on an
Image
-
edgePreservingFilter()
@@ -435,7 +435,7 @@ All functionsflip()
- - Flip an
Image
+ - Flip an
Image
-
floodFill()
@@ -468,6 +468,11 @@
+ - Affine Transform
+
-
+
getGaborKernel()
- Gabor Filter Kernels
@@ -695,7 +700,7 @@ All functionsnewDisplay()
- - Open New
Image
Display
+ - Open New
Image
Display
-
niBlackThreshold()
@@ -820,7 +825,7 @@
- - Resize an
Image
+ - Resize an
Image
-
rotateScale()
diff --git a/docs/reference/minAreaRect.html b/docs/reference/minAreaRect.html
index 5f157e10..b336ffe4 100644
--- a/docs/reference/minAreaRect.html
+++ b/docs/reference/minAreaRect.html
@@ -100,16 +100,16 @@ Author<
Examples
minAreaRect(rnorm(100), rnorm(100))
#> $angle
-#> [1] 81.68349
+#> [1] 81.83121
#>
#> $height
-#> [1] 5.16795
+#> [1] 5.80548
#>
#> $width
-#> [1] 4.448408
+#> [1] 4.489648
#>
#> $center
-#> [1] -0.5567193 0.2278657
+#> [1] -0.6323334 0.1881826
#>
diff --git a/docs/sitemap.xml b/docs/sitemap.xml
index c3df2791..9c31b6af 100644
--- a/docs/sitemap.xml
+++ b/docs/sitemap.xml
@@ -279,6 +279,9 @@
https://swarm-lab.github.io/Rvision/reference/gaussianBlur.html
+
+ https://swarm-lab.github.io/Rvision/reference/getAffineTransform.html
+
https://swarm-lab.github.io/Rvision/reference/getGaborKernel.html
diff --git a/man/getAffineTransform.Rd b/man/getAffineTransform.Rd
new file mode 100644
index 00000000..3c66af45
--- /dev/null
+++ b/man/getAffineTransform.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/transform.R
+\name{getAffineTransform}
+\alias{getAffineTransform}
+\title{Affine Transform}
+\usage{
+getAffineTransform(from, to, from_dim, to_dim = from_dim)
+}
+\arguments{
+\item{from}{A 4x2 matrix indicating the location (x, y) of 4 points in the
+source image.}
+
+\item{to}{A 4x2 matrix indicating the location (x, y) of 4 points in the
+destination image. The order of the points must correspond to the order in
+\code{from}.}
+
+\item{from_dim}{A vector which first two elements indicate the number of rows
+and columns of the source image.}
+
+\item{to_dim}{A vector which first two elements indicate the number of rows
+and columns of the destination image. If not specified, \code{from_dim} will
+be used as a default.}
+}
+\value{
+A 3x3 matrix.
+}
+\description{
+\code{getAffineTransform} computes the matrix of an affine
+ transform from 4 pairs of corresponding points in a source and destination
+ image.
+}
+\examples{
+from <- matrix(c(1, 1, 2, 5, 6, 5, 5, 1), nrow = 4, byrow = TRUE)
+to <- matrix(c(1, 1, 1, 5, 5, 5, 5, 1), nrow = 4, byrow = TRUE)
+getAffineTransform(from, to, c(1080, 1920), c(1080, 1920))
+
+}
+\seealso{
+\code{\link{warpAffine}}
+}
+\author{
+Simon Garnier, \email{garnier@njit.edu}
+}
diff --git a/man/stream.Rd b/man/stream.Rd
index cf7598f3..e70ef8c9 100644
--- a/man/stream.Rd
+++ b/man/stream.Rd
@@ -4,12 +4,21 @@
\alias{stream}
\title{Create an Object of Class \code{Stream}}
\usage{
-stream(index = 0, api = "ANY")
+stream(..., api = "ANY")
}
\arguments{
-\item{index}{An integer value corresponding to the index of the camera to
-read a stream from (default: 0; 0 is usually the default webcam on most
-computers).}
+\item{...}{Either:
+\itemize{
+ \item{index: }{An integer value corresponding to the index of the camera
+ to read a stream from (default: 0; 0 is usually the default webcam on
+ most computers). Or...}
+ \item{stream_string: }{...a character string corresponfing to the URL of
+ video stream (eg. protocol://host:port/script_name?script_params|auth)
+ or a GStreamer pipeline string in gst-launch tool format if GStreamer is
+ used as backend API. Note that each video stream or IP camera feed has
+ its own URL scheme. Please refer to the documentation of source stream
+ to know the right URL format.}
+}}
\item{api}{A character string corresponding to the API to use for reading the
stream from the camera (see Note; default: "ANY").}
diff --git a/src/Stream.h b/src/Stream.h
index d5fdf444..dbf45471 100644
--- a/src/Stream.h
+++ b/src/Stream.h
@@ -1,7 +1,9 @@
class Stream : public Capture {
public:
Stream(int index, std::string api);
+ Stream(std::string stream_string, std::string api);
bool open(int index, std::string api);
+ bool openStr(std::string stream_string, std::string api);
private:
};
@@ -12,9 +14,22 @@ Stream::Stream(int index, std::string api) {
}
}
+Stream::Stream(std::string stream_string, std::string api) {
+ if (!this->cap.open(stream_string, getAPIId(api))) {
+ Rcpp::stop("Could not open the stream.");
+ }
+}
+
bool Stream::open(int index, std::string api) {
if (!this->cap.open(index, getAPIId(api)))
Rcpp::stop("Could not open the stream.");
return true;
}
+
+bool Stream::openStr(std::string stream_string, std::string api) {
+ if (!this->cap.open(stream_string, getAPIId(api)))
+ Rcpp::stop("Could not open the stream.");
+
+ return true;
+}
diff --git a/src/transform.h b/src/transform.h
index 731649b6..5d0997ae 100644
--- a/src/transform.h
+++ b/src/transform.h
@@ -171,6 +171,26 @@ arma::Mat< float > _getPerspectiveTransform(arma::Mat< float > from, arma::Mat<
return out;
}
+arma::Mat< float > _getAffineTransform(arma::Mat< float > from, arma::Mat< float > to) {
+ arma::Mat< float > out;
+
+ cv::Point2f from_p[] = {
+ cv::Point2f(from(0, 0), from(0, 1)),
+ cv::Point2f(from(1, 0), from(1, 1)),
+ cv::Point2f(from(2, 0), from(2, 1)),
+ cv::Point2f(from(3, 0), from(3, 1)) };
+
+ cv::Point2f to_p[] = {
+ cv::Point2f(to(0, 0), to(0, 1)),
+ cv::Point2f(to(1, 0), to(1, 1)),
+ cv::Point2f(to(2, 0), to(2, 1)),
+ cv::Point2f(to(3, 0), to(3, 1)) };
+
+ cv::Mat_< float > affineMatrix = getAffineTransform(from_p, to_p);
+ cv2arma(affineMatrix, out);
+ return out;
+}
+
void _warpPerspective(Image& image, arma::Mat< float > m, int interpMode, int borderType,
Rcpp::NumericVector borderColor, Image& target) {
cv::Mat_< float > warpMatrix;
diff --git a/src/utils.h b/src/utils.h
index 2f040bed..be878d3a 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -30,6 +30,18 @@ bool ImageConst5(SEXP* args, int nargs) {
return true ;
}
+bool StreamConst1(SEXP* args, int nargs) {
+ if(nargs != 2) return false;
+ if(TYPEOF(args[0]) != INTSXP) return false ;
+ return true ;
+}
+
+bool StreamConst2(SEXP* args, int nargs) {
+ if(nargs != 2) return false;
+ if(TYPEOF(args[0]) != STRSXP) return false ;
+ return true ;
+}
+
bool QueueConst1(SEXP* args, int nargs) {
if(nargs != 4) return false;
if(!Rf_inherits(args[0], "Rcpp_Video")) return false ;
diff --git a/src/visionModule.cpp b/src/visionModule.cpp
index da4d5625..6f315f99 100644
--- a/src/visionModule.cpp
+++ b/src/visionModule.cpp
@@ -94,8 +94,10 @@ RCPP_MODULE(class_Capture) {
Rcpp::class_("Stream")
.derives("Capture")
- .constructor()
+ .constructor< int, std::string > ("", &StreamConst1)
+ .constructor< std::string, std::string > ("", &StreamConst2)
.method("open", &Stream::open)
+ .method("openStr", &Stream::openStr)
;
Rcpp::class_("Queue")
@@ -374,7 +376,9 @@ RCPP_MODULE(methods_Transform) {
function("_getRotationMatrix2D", &_getRotationMatrix2D, List::create(_["center"],
_["angle"], _["scale"]), "");
function("_getPerspectiveTransform", &_getPerspectiveTransform,
- List::create(_["from"], _["to"]), "");
+ List::create(_["from"], _["to"]), "");
+ function("_getAffineTransform", &_getAffineTransform,
+ List::create(_["from"], _["to"]), "");
function("_warpAffine", &_warpAffine, List::create(_["image"], _["m"],
_["interpMode"], _["borderType"], _["borderColor"], _["target"]), "");
function("_warpPerspective", &_warpPerspective, List::create(_["image"], _["m"],