diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..f2299f4 --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,3 @@ +^LICENSE\.md$ +^LEGOMosaics\.Rproj$ +^\.Rproj\.user$ diff --git a/.gitignore b/.gitignore index a33b48a..aff3e7d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ GoldenGirls3.gif 99_Rayshader.R beaarthur.mp4 WarholBea.png +0_PkgSetup.R diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..d57fe69 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,23 @@ +Package: LEGOMosaics +Title: What the Package Does (One Line, Title Case) +Version: 0.0.0.9000 +Authors@R: + person(given = "Ryan", + family = "Timpe", + role = c("aut", "cre"), + email = "ryan.timpe@gmail.com", + comment = c(ORCID = "YOUR-ORCID-ID")) +Description: What the package does (one paragraph). +License: MIT + file LICENSE +Encoding: UTF-8 +LazyData: true +Imports: + dplyr, + tidyr, + purrr, + ggplot2, + magrittr +Suggests: + rayshader +Roxygen: list(markdown = TRUE) +RoxygenNote: 6.1.1 diff --git a/Images/.gitignore b/Images/.gitignore index 33aa9be..f23ecc9 100644 --- a/Images/.gitignore +++ b/Images/.gitignore @@ -7,3 +7,4 @@ LEGOEmmetRapt.JPG LEGOEmmetRapt2.JPG beaarthur.jpg torosaurus.JPG +UP.PNG diff --git a/Images/UP.PNG b/Images/UP.PNG new file mode 100644 index 0000000..7cc4829 Binary files /dev/null and b/Images/UP.PNG differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..95aba47 --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2019 +COPYRIGHT HOLDER: Ryan Timpe diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..ac30a4b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2019 Ryan Timpe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..47202d5 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,5 @@ +# Generated by roxygen2: do not edit by hand + +export("%>%") +export(scale_image) +importFrom(magrittr,"%>%") diff --git a/R/scale_image.R b/R/scale_image.R new file mode 100644 index 0000000..03a833a --- /dev/null +++ b/R/scale_image.R @@ -0,0 +1,79 @@ +#' Scale an image raster array to a small number of pixels. Process into a data frame. +#' +#' @param image A raster array from an image. +#' @param img_size Size of output image in pixel, where one pixel = one 'brick'. Use a single value (e.g. \code{48}) for a square image with 48 pixels on each side. +#' Use an array of two values for a rectangular image \code{c(width, height)}. +#' @param brightness A value >1 will increase the brightness of the image while a positive value <1 will decrease the brightness. +#' @param warhol Array of values \code{c(1, 2, 3)} associated with R, G, B color channels. Swap values in array to swap color channels for a fun visual effect. +#' @return A list with element \code{Img_scaled} containing a data frame of the x- & y-coordinates, R, G, B channels, and hex color of each brick (pixel). +#' @export +#' +scale_image <- function(image, img_size, brightness = 1, warhol = 1:3){ + + #Adjust brightness. Max channel value is 1 + if(brightness < 0 ){stop("brightness should be a positive value. Use 1 for no change, >1 for lighter, <1 for darker.")} + image_b <- image*brightness + image_b[image_b>1] <- 1 + + #Only whole values for image size + img_size <- round(img_size, 0) + + #RGB channel order as specified with the `warhol` input + col_chan <- order(warhol[1:3]) + + #Convert image to a data frame with RGB values + img <- dplyr::bind_rows( + list( + (as.data.frame(image_b[, , col_chan[1]]) %>% + dplyr::mutate(y=dplyr::row_number(), channel = "R")), + (as.data.frame(image_b[, , col_chan[2]]) %>% + dplyr::mutate(y=dplyr::row_number(), channel = "G")), + (as.data.frame(image_b[, , col_chan[3]]) %>% + dplyr::mutate(y=dplyr::row_number(), channel = "B")) + ) + ) %>% + tidyr::gather(x, value, -y, -channel) %>% + dplyr::mutate(x = as.numeric(gsub("V", "", x))) %>% + tidyr::spread(channel, value) + + #Wide or tall image? Shortest side should be `img_size` pixels + if(max(img$x) > max(img$y)){ + img_scale_x <- max(img$x) / max(img$y) + img_scale_y <- 1 + } else { + img_scale_x <- 1 + img_scale_y <- max(img$y) / max(img$x) + } + + #If only 1 img_size value, create a square image + if(length(img_size) == 1){ + img_size2 <- c(img_size, img_size) + } else { + img_size2 <- img_size[1:2] + img_scale_x <- 1 + img_scale_y <- 1 + } + + #Rescale the image + img2 <- img %>% + dplyr::mutate(y_scaled = (y - min(y))/(max(y)-min(y))*img_size2[2]*img_scale_y + 1, + x_scaled = (x - min(x))/(max(x)-min(x))*img_size2[1]*img_scale_x + 1) %>% + dplyr::select(-x, -y) %>% + dplyr::group_by(y = ceiling(y_scaled), x = ceiling(x_scaled)) %>% + #Get average R, G, B and convert it to hexcolor + dplyr::summarize_at(dplyr::vars(R, G, B), dplyr::funs(mean(.))) %>% + dplyr::rowwise() %>% + dplyr::mutate(color = rgb(R, G, B)) %>% + dplyr::ungroup() %>% + #Center the image + dplyr::filter(x <= median(x) + img_size2[1]/2, x > median(x) - img_size2[1]/2, + y <= median(y) + img_size2[2]/2, y > median(y) - img_size2[2]/2) %>% + #Flip y + dplyr::mutate(y = (max(y) - y) + 1) + + out_list <- list() + out_list[["Img_scaled"]] <- img2 + + return(out_list) + +} \ No newline at end of file diff --git a/R/utils-pipe.R b/R/utils-pipe.R new file mode 100644 index 0000000..fb8c818 --- /dev/null +++ b/R/utils-pipe.R @@ -0,0 +1,11 @@ +#' Pipe operator +#' +#' See \code{magrittr::\link[magrittr]{\%>\%}} for details. +#' +#' @name %>% +#' @rdname pipe +#' @keywords internal +#' @export +#' @importFrom magrittr %>% +#' @usage lhs \%>\% rhs +NULL diff --git a/data/lego_colors.rda b/data/lego_colors.rda new file mode 100644 index 0000000..5861770 Binary files /dev/null and b/data/lego_colors.rda differ diff --git a/man/pipe.Rd b/man/pipe.Rd new file mode 100644 index 0000000..b7daf6a --- /dev/null +++ b/man/pipe.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-pipe.R +\name{\%>\%} +\alias{\%>\%} +\title{Pipe operator} +\usage{ +lhs \%>\% rhs +} +\description{ +See \code{magrittr::\link[magrittr]{\%>\%}} for details. +} +\keyword{internal} diff --git a/man/scale_image.Rd b/man/scale_image.Rd new file mode 100644 index 0000000..bea43d8 --- /dev/null +++ b/man/scale_image.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/scale_image.R +\name{scale_image} +\alias{scale_image} +\title{Scale an image raster array to a small number of pixels. Process into a data frame.} +\usage{ +scale_image(image, img_size, brightness = 1, warhol = 1:3) +} +\arguments{ +\item{image}{A raster array from an image.} + +\item{img_size}{Size of output image in pixel, where one pixel = one 'brick'. Use a single value (e.g. \code{48}) for a square image with 48 pixels on each side. +Use an array of two values for a rectangular image \code{c(width, height)}.} + +\item{brightness}{A value >1 will increase the brightness of the image while a positive value <1 will decrease the brightness.} + +\item{warhol}{Array of values \code{c(1, 2, 3)} associated with R, G, B color channels. Swap values in array to swap color channels for a fun visual effect.} +} +\value{ +A list with element \code{Img_scaled} containing a data frame of the x- & y-coordinates, R, G, B channels, and hex color of each brick (pixel). +} +\description{ +Scale an image raster array to a small number of pixels. Process into a data frame. +}