Detect a specific line from a image using R - r

I am new to image processing. I want to detect a specific line in this image, which is the horizontal line in the middle of it. I am wondering how to approach it. This is the map, and it has already been simplified to the edge map.

Here's one method.
Let's start by reading in your image. We'll use the png library for this, so if you don't have it installed, you'll want to install.packages("png") first.
library(png)
img_link <- "https://i.stack.imgur.com/PygvJ.png"
img <- readPNG(readBin(img_link, "raw", 1e6))
The readPNG function extracts the image as an array. In this case, the array is 360 by 371 by 4:
dim(img)
#> [1] 360 371 4
This means the image is 360 by 371 pixels and contains four channels: red, blue, green and alpha (transparency).
We can plot this array at any time by calling:
plot(as.raster(img))
To find a horizontal red line, all we need to do is look at the row sums of the pixel values in the green channel, which will drop sharply at the target row.
sum_green <- apply(img[,,2], 1, sum)
We can plot this vector to ensure there is a row with a large drop-off in one of the rows, as we would expect.
plot(sum_green, type = "l")
To get this row, we just find the minimum row sum:
target_row <- which.min(sum_green)
target_row
#> [1] 183
So our red line is on the 183rd row. To prove this, let's make the 183rd row of our image black and draw it again:
img[target_row, , 1:3] <- 0
plot(as.raster(img))
This looks correct.

Related

How to use text function in R?

I am learning graphical analysis using R. Here is the code, which I can not understand.
barplotVS <- barplot(table(mtcarsData$vs), xlab="Type of engine")
text(barplotVS,table(mtcarsData$vs)/2,table(mtcarsData$vs),cex=1.25)
The output is like below. I can not understand the function of text(), I googled the text() function, which shows that the parameter of text(x,y) is numeric vectors of coordinates where the text labels should be written. Can anyone tell me what is barplotVS,table(mtcarsData$vs)/2,table(mtcarsData$vs),cex=1.25 in my code.
barplotVS <- barplot(table(mtcarsData$vs), xlab="Type of engine")
print(barplotVS)
outputs:
[,1]
[1,] 0.7
[2,] 1.9
These are the positions where the center of the bars in the barplot are on the x axis.
print(table(mtcarsData$vs))
outputs:
0 1
18 14
the numbers below are the occurrences of each value that is present in mtcarsData$vs and the numbers above are the actual value that is counted.
When you run the function:
text(barplotVS,table(mtcarsData$vs)/2,table(mtcarsData$vs),cex=1.25)
the first value will be the x positions where to put the labels (i.e. 0.7 and 1.9), the second parameter will be the y positions set in this case to total counts divided by two (i.e. 9 and 7) meaning to put the labels halfway in the bars, the third will be the labels (i.e. 18 and 14) and finally cex is a value that allows to change the size of the font.
Anyway R has in general a good documentation that you can call by using the ? operator (as suggested in the comments). In order to understand try to run the code and check what each variable contains with print or str functions. If you use a IDE (e.g. RStudio) have the content of the variables in a graphical panel so you don't event need to print.

Documenting code with plot

I have tried to find a way to plot a graph where the x-axis wraps at a specified position and then continues at 0 to the right of the max value.
I am attaching an example where the x-axis wraps at 720, e.g. 720 == 0.
It does not matter which tool to use as long it is easy to install on Linux (Ubuntu)
I am trying to assign a x-label column to my data serie where the x axis is in column B and data in column D and x-labels in column C.
but that does not work for me, e.g. the x-axis in above example spans from 685 to 735 instead of 685 to 720 then to 15
So using line diagram instead of scatter as #pnuts did solved my problem.
Instead of x values for the x-axis apply the remainder after x has been divided by 720:

Sliding window in a data frame r

I’m trying to obtain the proportions of individuals that that shares certain DNA sequences between two given points. And I want to use a specific sliding window. In order to show the problem I create this example. First I create a data frame with four columns.
x<-c(rep("sc256",times=2000),rep("sc784",times=2000))
pos1<-round(runif(2000,100,5000),digits=0)
pos2<-round(runif(2000,100,5000),digits=0)
y3<-rep(c(2,1),times=2000)
M1<-data.frame(x,pos1,pos2,y3)
colnames(M1)=c("iid","pos1","pos2","chr")
I also create a function to obtain the proportion of individuals that have sequences in a particular interval.
roh_island<-function(pop,chr,p1,p2){
a<-pop[pop$chr==chr,]
island<-subset(a,pos1>=p1 & pos2<=p2)
n<-nrow(island)/length(M1$iid)
return(n)
}
roh_island(M1,1,345,700)
Now I want to transform this interval into a sliding window of size 10 that moves between values 0 and 7000. So this window will take positions [0,10);(10,20),…,(6990,7000]. I also need that the new function with the slide window stores all the windows and proportion of individuals in each in a data frame to afterwards plot it. I try some solutions that I have found regarding sliding windows I saw but I could not make them work. Thanks
This code will slide p1 from 0 to 6990 in steps of 10 while p2 slides from 10 to 7000 in steps of 10:
output = apply(data.frame(seq(0,6990,10), seq(10,7000,10)), MARGIN=1,
function(x,y,z,a) roh_island(M1, 1, x[1], x[2]))
plot(output, col="blue")
grid(5, 5)

Vectorizing raster brick objects with r-raster so that I can count them

I have an image of columns of red and blue bordered circles like so:
Where the columns alternate red and blue (in this example the first column is red)
I have been able to create a raster brick and plot the image in RGB layers but I want to count these columns into a vector like this (from above example). Values 1(red) and 2(blue)
1,1,1,1,2,2,2,1,1,2,1,1,1 ...
Is it possible to clear out areas of the brick I don't need for counting and collapse the brick down into values I could then convert into the numbers or labels I want? Or is there a much simpler way that I'm unable to locate? Also long term I want to be able to point the program at several images without opening them myself.
Edit: To clear somethings up, I want to count the circles top to bottom, left to right. For example once the first col is counted, I want to start over at the top of the next column on the right. Also I'm not sure if I'm headed in the right direction but I was able to remove all background cells from the image. leaving me with a plot of only values where the circles are.
Edit 2:
The current code I have for the image above.
color.image <- brick("image")
color.image = dropLayer(color.image,4) #gets rid of a channel
plot(color.image)
e <- extent(-10, 240, 45, 84.8) #xmin,xmax, ymin,ymax
ccolor.image <- crop(color.image, e)
plot(ccolor.image)
#thresholding to simplify what I was dealing with
mini=ccolor.image[ccolor.image > 97] = NA
mini=ccolor.image[ccolor.image < 15] = NA
mini=ccolor.image[ccolor.image > 20] = 80
plot(ccolor.image)
mcolor = as.matrix(ccolor.image)
colSums(ccolor.image)
rowSums(ccolor.image)
Edit 3:
I figured it out! Or at least found a round about way to do it, will post code later once I clean it up some. I still however would like input on creating a vector based on the matrix of values I have for my simplified raster brick matrix. Code coming soon!
The fastest way to count values in a raster is freq(x, merge=T). This will give you the value in one column and the frequency in as many columns as you have rows. In this way we the need to poll a value of interest and sum all the other columns (the counts). Hope that helps!
freq_vals <- freq ( rasterbrick , merge = T )
sum( freq_vals [ which ( freq_vals$value == 1 ) , 2 : ncol ( freq_vals ) ] )

How to get a value of a multi-dimensional array by an INCOMPLETE vector of indices

This question is very similar to
R - how to get a value of a multi-dimensional array by a vector of indices
I have:
dim_count <- 5
dims <- rep(3, dim_count)
pi <- array(1:3^5, dims)
I want to get an entire line, but with an automatic building of the address of this line.
For example, I would like to get:
pi[1,,2,2,3]
## [1] 199 202 205
You could insert a sequence covering the whole dimension in the appropriate slot:
do.call("[",list(pi,1,1:dim(pi)[2],2,2,3))
By the way, defining a variable called pi is a little dangerous (I know this was inherited from the previous question) -- suppose you tried a few lines later to compute the circumference of a circle as pi*diameter ...

Resources