R magick: Square crop and circular mask - r

The aim is to
convert any input image to square aspect ratio and
add a circular mask and fill the outside with white or transparency.
I have got 1 to work, but not sure it's the best way to do it. Here is a working example.
library(magick)
path <- "https://cdn.pixabay.com/photo/2016/08/17/21/12/people-1601516_960_720.jpg"
img <- magick::image_read(path)
img
Original image
ii <- magick::image_info(img)
ii_min <- min(ii$width,ii$height)
img1 <- magick::image_crop(img, geometry=paste0(ii_min,"x",ii_min,"+0+0"),repage=TRUE)
img1
Cropped Square Aspect Ratio
I am not sure how to get the last part (2) to work in R. Although I have sort of managed to get it to work using image-magick in unix.
convert -size 500x500 xc:white -fill cropped.jpeg -draw "circle 250,250 250,1" circ.jpg
Circular Frame
I am looking for a solution to 2 in R.

library(magick)
path <- "https://cdn.pixabay.com/photo/2016/08/17/21/12/people-1601516_960_720.jpg"
im <- magick::image_read(path)
# get height, width and crop longer side to match shorter side
ii <- magick::image_info(im)
ii_min <- min(ii$width, ii$height)
im1 <- magick::image_crop(im, geometry=paste0(ii_min, "x", ii_min, "+0+0"), repage=TRUE)
# create a new image with white background and black circle
fig <- magick::image_draw(image_blank(ii_min, ii_min))
symbols(ii_min/2, ii_min/2, circles=(ii_min/2)-3, bg='black', inches=FALSE, add=TRUE)
dev.off()
# create an image composite using both images
im2 <- magick::image_composite(im1, fig, operator='copyopacity')
# set background as white
magick::image_background(im2, 'white')
R version 4.0.0
magick_2.5.2

Related

Can image location be specified with image_mosaic or image_flatten magick functions in R?

When using the image_mosaic or image_flatten functions from the magick R package, the second image is always placed in the upper left of the combined image. Can it be placed in the lower left or lower right of the larger image? Is there a more general way to specify location with pixel or index coordinates?
library(magick)
# grab sample images from magick documentation
bigdata <- image_read("https://jeroen.github.io/images/bigdata.jpg")
rlogo <- image_read("https://jeroen.github.io/images/Rlogo.png")
# scale images for easier viewing in RStudio
bigdata <- image_scale(bigdata, "600x600")
rlogo <- image_scale(rlogo, "150x150")
# combine
img <- c(bigdata, rlogo)
# flatten and mosaic both result in the R logo being in the upper left.
# how can the location of the logo in the combined image be specified,
# for example in the lower left or lower right?
image_flatten(img)
image_mosaic(img)

Modify range of color of raster image in R

I take photo with a black background but due to the light, it can have some reflect. In R I would like to change the background to black one (RGB = 0). I would like to select the color with RGB values lower than 80 and change to 0.
I use this code in R:
library(raster)
folder <- "C:/Users/PC/Pictures/"
img <- list.files(folder)
img.raster<-stack(img)
names(img.raster) <- c('r','g','b')
color <- 80
img.black<-img.raster[[1]]
img.black[img.raster$r<color & img.raster$g<color & img.raster$b<color] <- 0
I rebuilt my image using stack
image = stack(img.black, img.black, img.black)
But by doing this I lose information as I have the same layer for R,G and B. If I tried:
image = stack(img.black, img.raster, img.raster)
by this way the dimension of the image is 7 !!
How to select a range of color and change it without modifying the dimension of the image and the other colors. Do I need to use raster or is there another solution ?
Here is how you could do that. Note that I update the color to 255 rather than 0 to be able to see the effect in this example. Also, you used the first layer of RGB as black. I assume you wanted the third.
Example data
library(raster)
img <- stack(system.file("external/rlogo.grd", package="raster"))
plotRGB(img)
Solution
color_threshold <- 80
update_value <- 255 # 0 in your case
black <- 3
i <- all(img < color_threshold)
img[[black]] <- mask(img[[black]], i, maskvalue=1, updatevalue=update_value)
plotRGB(img)
Or perhaps this is what you are after --- update all cells to zero, not just the black channel:
img <- brick(system.file("external/rlogo.grd", package="raster"))
img2 <- mask(img, all(img < 80), maskvalue=1, updatevalue=0)
plotRGB(img2)

How to extract small dataset images from a large image using box in R

I would like to extract from an image a dataset of smaller images as illustrated as follow. I would like to create a box of 64x64 pixels, translate it in x and y and save each image in JPEG.
Could you suggest a function in R to do it ? I do not find the way the create a box.
You can use the magick-package for this. It has many functions for image-manipulation.
Basically what I did in the following code is reading in the image and then based on image-size create a list of coordinates which spans most of the image (a part of the edges might be missing), but this is only an example and you could modify it to the coordinates you need. Each point refers to the top-left point of one box you want to crop.
Afterwards in the loop I specify the size of the box 64x64 and use to coordinates from earlier to offset this box in each iteration and to give each cropped image a unique name.
install.packages("magick")
library(magick)
# read in image
im <- image_read("example.jpg")
# get image size
im_dim <- dim(image_data(im))
# create offsets for cropping image
coords <- expand.grid(x = seq(0, im_dim[2]-64, by = 64),
y = seq(0, im_dim[3]-64, by = 64))
coords$offset <- paste0("+", coords$x, "+", coords$y)
# crop and save
for(i in coords$offset) {
cropped <- image_crop(im, paste0("64x64", i))
image_write(cropped, paste0("example", i,".jpg"))
}

Converting raster (tiff) image to a pixel image in R - problems when converting spatial polygon into owin object class

I am not an R expert, but i use it for all kinds of image processing. Now I am trying to apply Gaussian blur smoothing (spatstat package) on my satellite S-2 image. Original type of my image is Raster (Raster layer) tiff, actually a subtract image from two Sentinel-2 bands (green and blue). To apply blur on this kind of image I have to first convert it to a pixel image. I've tried doing this following few other questions (like this one Converting a raster object to an im object in R), but i did not succed. I have tried few possibilities, like converting raster image into matrix and than to pixel image, but this does not work, because the image is than too large (although I use small, croped area of the whole Sentinel-2 image).
So, my function in brief looks something like that:
blue <- raster("S2A_OPER_MSI_T33TWH_B02.tif")
green <- raster("S2A_OPER_MSI_T33TWH_B03.tif")
subt <- function(r1, r2) {
return(r2-r1)
}
out_sub1 <- (blue, green, fun = subt)
I tried to apply blur directly on a Raster image, but i soon realized its not working on raster data:
gauss_sub1 <- blur(out_sub1, sigma = 5)
#Error: is.im(x) is not TRUE
So, I try to convert my image into a pixel one
out_sub11 <- as.im(X = "out_sub1")
Error in as.im.function(X, W, ..., dimyx = dimyx, na.replace = na.replace): A window W is required
Therefore I try to define a window following my raster extent
e <- out_sub1#extent
sp_w <- as(e, "SpatialPolygons")
W <- as(sp_w, "owin")
Error in as(SP.win, "owin") : no method or default for coercing “SpatialPolygons” to “owin”
Can anyone tell me what am I doing wrong or how can I convert spatial polygon into owin object class, so I can further process blur command?
And can please someone explain me what difference there is between raster image and a pixel image in R?
You can apply a filter using raster library:
library(raster)
r <- blue - green
# 3 by 3 mean filter
r_mf <- focal(r, w=matrix(1/9,nrow=3,ncol=3))
# gaussian filter
gf <- focalWeight(r, 2, "Gauss")
r_gf <- focal(r, w=gf)

crop image, convert to black and white and sharpen it

I want to take x, convert it into a black and white image. Then i want to convert all pixels that are below 100 to 0 and convert all pixels that are above 100 to 255. I want to get a sharper image where background will be white and objects within image will be black. And then store new x (black and white sharp image) on my hard drive. How could i do it?
library(raster)
r1 <- brick(system.file("external/rlogo.grd", package="raster"))
x <- crop(r1, extent(0,50,0,50))
plotRGB(x)
Based upon earlier question, i wrote below lines to convert r1 to black and white. But plotRGB function fails :(. Plot function works but it doesnt return me a black and white image
flat <- sum(x * c(0.2989, 0.5870, 0.1140))
plotRGB(flat)
flat
plot(flat)
========update1==========
in case anyone interested,
image colors can be swapped easily by using "1-twoclasses" in place of "twoclasses" in image and plot functions below
To actually see grays you need to provide these colors.
library(raster)
r1 <- brick(system.file("external/rlogo.grd", package="raster"))
x <- crop(r1, extent(0,50,0,50))
flat <- sum(x * c(0.2989, 0.5870, 0.1140))
plot(flat, col=gray(seq(0,1,0.1)))
You can use the reclassify function to get values that are either 0 or 255 but in this case it would seem more sensible to use 1 and 2
twoclasses <- cut(flat, c(0,100,255))
plot(twoclasses, col=gray(c(0,1)))
To write to disk, you can do something like:
png(width=ncol(twoclasses)*10, height=nrow(twoclasses)*10)
par(mai=c(0,0,0,0))
image(twoclasses, col=gray(c(0,1)))
dev.off()

Resources