Detecting a line in an image and save its coordinates - r

I have an image representing an intensity graph:
intensity graph
In order to multiplicate two intensitiy graphs I need to save the coordinates of this graph. Thus, I first want to find the (middle or one border of the) line and then get its coordinates. So far I tried a few things. Which came nearest to the solution was using the LineSegmentDetector package:
library(pixmap)
image <- read.pnm(file = "graph.pgm", cellres = 1)
x <- image#grey * 255
linesegments <- image_line_segment_detector(x)
linesegments
plot(image)
plot(linesegments, add = TRUE, col = "red")
This gives me a couple of line segments:
enter image description here
However, the aim is to get one line of 1 pixel width like this:
enter image description here
Subsequently, I would need the coordinates of this graph. I would need one y value for every pixel in x direction.
I hope my problem is clear and am thankful for any help!

Related

How to plot 3d vectors on 2-dimensional surface using Gnuplot?

I am trying to reproduce a plot as in the attached image below.
In this picture, the position of the vectors is fixed at a specific position (let's say in a 10×10 grid), and the orientation of the vectors represents the magnitude of the x and y coordinate. In contrast, the color represents the magnitude of the z coordinate.
I need help with Gnuplot codes to plot a similar one.
enter data here
enter data here
Data points for referenceenter image description here.
The key of the solution is:
plot 'DATA.dat' with vectors head size 0.08,20,60 filled lc palette
you can play with the vector's head size parameters, borders, colors etc.

Finding xy coordinates of shelves in a store floorplan in r

I'm working on the following: I have a store layout, example see below (cannot add the real thing for GDPR reasons but the example should do the trick) on which I have xy coordinates from visitors (anonymous of course)
I already placed a grid on the picture so I can see which route they take in the store. That works fine. origin is bottom left and x & y are scaled from 0-100.
So far so good. Now next step is identifying the coordinates of the shelves, rectangles in the picture. Is there a way to do this without having to do this manually? The real store layout contains more than 900 shelves or am I pushing out the boat too far?
The output I'm looking for is a dataframe that contains a shelve ID and the coordinates for the corners. Idea is to create some heatmaps in the store to see that there are blind spots, hotspots, ...
The second analysis needs also the integer points. The idea is to create vectors of visitor points so we get a direction to which they are looking. By using the scope of what a human being can see I would give percentages of "seen" the products based on intersection with integer points.
thx!
JL
One approach is to perform clustering on the black pixels of the image. The clusters are then the shelves. If the shelves are axis parallel you can find the rectangles by just taking min/max in each direction. This works quite well:
Sample code (I converted the image to PNG as it is easier to read than gif):
library(png)
library(dbscan)
library(tidyverse)
library(RColorBrewer)
img <- readPNG("G18JU.png")
is_black <-
img %>%
apply(c(1, 2), sum) %>% #sum all color channels
{. < 2.5} %>% # we assume black if the sum is lower than 2.5 (max value is 3)
which(arr.ind=TRUE) # the indices of the black pixels
clust <- dbscan(is_black, 2) # identify clusters
rects <-
as.tibble(is_black) %>%
mutate(cluster = clust$cluster) %>% # add cluster information
group_by(cluster) %>%
## find corner points of rectangles normalized to [0, 1]
summarise(xleft = max(col) / dim(img)[2],
ybottom = 1 - min(row) / dim(img)[1],
xright = min(col) / dim(img)[2],
ytop = 1 - max(row) / dim(img)[1])
## plot the image and the rectangles
plot(c(0, 1), c(0, 1), type="n")
rasterImage(img, 0, 0, 1, 1)
for (i in seq_len(nrow(rects))) {
rect(rects$xleft[i], rects$ybottom[i], rects$xright[i], rects$ytop[i],
border = brewer.pal(nrow(rects), "Paired")[i], lwd = 2)
}
Of course this approach also detects other black lines as "rectangles" (e.g. the black border). But I guess you can easily create a "clean" image.
Edit: extend method to find shelves that share a black line
To extend the method such that it can separate shelves that share a black line:
First, identify the rectangles in the way outlined above.
Then, extract each rectangle from the image and compute the row means. This gives you a 1d image (= line) for each rectangle. In this line apply thresholding and clustering as before. The clusters are now the black line segments, and the mean of each cluster corresponds to a vertical line shared by two shelves.
To find horizontal shared lines, the same procedure can be applied, but with column means instead of row means.

How to convert x y coordinates to hexbin center coordinates

I'm aware of the hexbin package, but I don't want to summarize the data at this point. I don't draw my plots in R, so I have no need for hexbin objects or many other things in this package.
I simply want to convert/round each point's coordinates to the xy coordinates of the center of the hexagon that contains the point. In other words, instead of the hexbin function returning a hexbin object, I want to return x and y coordinates of hexagon centers that correspond to the input coordinates.
I assumed I would find something useful in the source code of the hexbin function, but I'm kinda lost there. I don't want to write my own function if it's already been done, so any advice is welcome.
Assign your hexbin with desired bin sizes to an object and then check the structure. The center of mass is given by #xcm and #ycm. See ?hexbin.
An example is shown below.
library(hexbin)
mtcars_hexbin <- hexbin(mtcars$mpg ~ mtcars$hp, xbins = 5, IDs= TRUE)
str(mtcars_hexbin)
# The x, y of center of mass are given by:
mtcars_hexbin#xcm
mtcars_hexbin#ycm
Edited to answer comment: If IDs=TRUE, then the output #cID gives the cell number to which each original non-aggregated points belong to. #cell gives you the cell number associated with #xcm, #ycm center of mass coordinates. #count tells you how many points belong to a cell.
mtcars_hexbin#cID
mtcars_hexbin#cell
mtcars_hexbin#count

How to get the color coded plotted areas in images using R?

Hi R expert of the world,
Assume I have a point pattern that generate an intensity map and that this map is color coded in 3 region in an pixeled image.... how could I get the color-coded area?
here it is an example using spatstat:
library(spatstat)
japanesepines
Z<-density(japanesepines); plot(dens) # ---> I create a density map
b <- quantile(Z, probs = (0:3)/3) # ---> I "reduce it" to 3 color-ceded zones
Zcut <- cut(Z, breaks = b, labels = 1:3); plot(Zcut)
class(Zcut) # ---> and Zcut is my resultant image ("im")
Thank you in advance
Sacc
In your specific example it is very easy to calculate the area because you used quantile to cut the image: This effectively divides the image into areas of equal size, so there should be three areas of size 1/3 since the window is a unit square. In general to calculate areas from a factor valued image you could use as.tess and tile.areas (continuing your example):
Ztess <- as.tess(Zcut)
tile.areas(Ztess)
In this case the areas are 0.333313, which must be due to discretization.
I'm not exactly sure what you're after, but you can count up the number of pixels in each color using the table() function.
table(Zcut[[1]])

Gnuplot "vector line"

I am trying to generate a plot which uses arrows as markers in Gnuplot. These arrows I want to turn in a specific angle which I know. So I have value triples of x1 ... xn, y1...yn, alpha1...alphan. Sorry, I wasn't able to include a pic from my hard drive to illustrate what I want to achieve.
Basically, for every (15th or so) x-y pair, the marker should be an arrow which uses a certain angle.
The measured data is tightly packed so I suppose I will have to define an increment between the markers. The length of the arrow can be the same all over.
I would appreciate your ideas.
Gnuplot has a plot mode with vectors that is what you want
Given that your file has the following format, x y angle and assuming that
your angle is in radians, you have to take into account that
with vectors requires 4 parameters, namely x y dx dy where dx
and dy are the projections of the lenght of the arrow.
this draws only the arrows, if you want a line you have to make
two passes on the data.
you want to draw an arrow for a data point over, say, 10 points.
That said, I'd proceed like this
dx(a) = 0.2*cos(a) # 0.2 is an arbitrary scaling factor
dy(a) = 0.2*sin(a)
# this draws the arrows
plot 'mydata.dat' every 10 using 1:2:(dx(a)):(dy(a)) with vectors
# this draws the line
plot 'mydata.dat'
You may want to use help plot to find the detailed explanation of all the parameters that you can apply to a with vectors plot.
Credits: An article on the gnuplotting site

Resources