Search code examples
rimagecrop

Draw a circle in a bitmap image and crop pixels outside circle in R


I'm loading bitmap images into R with dimensions that are roughly 17,000 X 17,000 pixels. I'd like to find a way to draw a circle with a radius (in pixels) of my choosing around the center of the picture and convert all pixels outside of the circle into NA's. For example, if the radius desired was 500 pixels, all pixels within that distance (500) from the centroid would be kept as is. Any pixel farther than that distance (>= 501) from the centroid would be converted to an NA.

The bitmap images are made up entirely of 1's and 0's so here's a smaller example of what these images look like.

img=matrix(sample(c(1,0),1000000,replace=TRUE),ncol=1000,nrow=1000)
image(0:1000,0:1000,img)

Solution

  • I've created a fake image that's smaller than yours so that the code will run more quickly:

    library(plotrix) # To draw a circle
    library(reshape2) # For "melt" function
    

    Create a fake image:

    # Number of rows and columns in image
    nr = 200
    nc = 100
    
    # Create image values
    set.seed(78)
    img = matrix(sample(c(1,0), nr*nc, prob=c(0.8, 1-0.8), replace=TRUE), ncol=nc, nrow=nr)
    

    Now that we have our image, remove points outside the desired circle:

    # melt matrix into "long" format
    img = melt(id.var=1:nrow(img), img)
    names(img) = c("rows","cols","z")
    
    # Find center of image
    center=c(median(1:nr), median(1:nc))
    
    # Set desired radial distance from center
    r=40
    
    # Set values outside radius to -1 (or some value that can't otherwise appear in
    # the matrix). You can set the value to NA, but then you won't be able to
    # control the color of the excluded region (it will just be white).
    img$z[sqrt((img$rows - center[1])^2 + (img$cols - center[2])^2) > r] = -1
    
    # Plot image. Colors ordered from lowest (-1) to highest (1) value
    image(1:nr, 1:nc, matrix(img$z, nrow=nr, byrow=FALSE), col=c("gray80", "green","red"))
    
    # Draw a circle around the selected points
    draw.circle(center[1], center[2], r, lwd=2)
    

    enter image description here