crop image, convert to black and white and sharpen it - r

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()

Related

R magick: Square crop and circular mask

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

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)

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)

Finding RGB values from an jpeg image in R

I am trying to find RGB values in R.
The jpeg images that I am using have an object with white background.
Like this one: http://www.wild-wonders.com/blog/wp-content/uploads/2009/11/nba_france_16.jpg
Right now, in order to just select the object, I have to trace each object manually (by plotting dots which makes the selection into a shape that will later be used to get the RGB values). Is there any tools or packages like magic wand tool in photoshop that will automatically select the white background?
Have a look at the functionality provided by the Bioconductor package EBImage, an image processing and analysis toolbox for R. To install the package use:
source("http://bioconductor.org/biocLite.R")
biocLite("EBImage")
The example below illustrates how to automatically extract an object from white background, and get its #rrggbb pixel values. I used a value of 0.95 for thresholding rather than 1.0 (corresponding to white pixels) because of the artifacts introduced by jpeg compression.
library(EBImage)
## load the array representing pixel intensities into R
img <- readImage("http://www.wild-wonders.com/blog/wp-content/uploads/2009/11/nba_france_16.jpg")
## convert to grayscale before thresholding
gray <- channel(img, "gray")
## create a mask separating objects from background
mask <- gray < 0.95
## label objects (connected sets of pixels)
obj <- bwlabel(mask)
## indices of pixels within the object
idx <- which(mask==1, arr.ind=TRUE)
## extract the red, green, and blue pixel intensities
rgb <- cbind(channel(img, "r")[idx],
channel(img, "g")[idx],
channel(img, "b")[idx])
## convert to #RRGGBB representation
rgb(rgb)

R raster recognizing black color raster image

The code below produces two boxes on my image. I am planning to analyze pixels within those boxes further.
I want to put a condition that if along an edge of a box, there is a black color (or a similar color such as grey) pixel then don't proceed. How can i specify such condition?
In below example, in the case of the red square I don't want to proceed further as it has black pixels at the top right hand corner. While I would like to proceed in the case of green square as it doesn't have a black color pixel along it's edge.
library(raster)
r1 <- brick(system.file("external/rlogo.grd", package="raster"))
x <- crop(r1, extent(0,50,0,50))
plotRGB(x)
plot(extent(c(0,20,0,20)), lwd=2, col="red", add=TRUE)
plot(extent(c(21,35,0,10)), lwd=2, col="Green", add=TRUE)
That is not very well defined as in this case color is made of RGB values. But here is a general solution that you could adapt. I 'flatten' these to a single channel by taking the average, and then test for the smallest value being below a threshold (white is 255, 255, 255 in RGB, black is 0,0,0) at the boundary
proceed <- function(f, e, threshold) {
lns <- as(as(e, 'SpatialPolygons'), 'SpatialLines')
v <- unlist(extract(f, lns))
ifelse( min(v, na.rm=TRUE) < threshold, FALSE, TRUE)
}
# flat <- mean(x) # not sophisticated see
# http://stackoverflow.com/questions/687261/converting-rgb-to-grayscale-intensity
flat <- sum(x * c(0.2989, 0.5870, 0.1140))
proceed(flat, extent(c(0,20,0,20)), 100)
proceed(flat, extent(c(21,35,0,10)), 100)
(much improved after seeing jbaums' solution; which is now gone)

Resources