Joining discontinuous skeleton shapes and discontinuous lines - matlab

I have a binary image, I want to detect discontinuous lines and linking them.
I don't know anything (coordinates, angle etc).
Can any one guide me how should I start? Suppose I have this image:
I want to join discontinuous lines. And I want to store information of lines joining (in an array) to use afterward.

I found your problem interesting and I will try to give you just some ideas but unfortunately not a complete algorithm (you know, it takes time...). I will also leave you with some unanswered questions.
I consider the image you posted as a binary image, that is the black pixels have value of zero and the white pixels have value of one. I ignore the red pixels because I think you drew them in order to highlight where you would like to connect the broken lines; ignoring the red pixels means I will set their value to zero.
First of all we need some definitions.
A non-border pixel has 8 neighbor (north-west, north, north-east, east, south-east, south, south-west, west) pixels:
abc
h*d
gfe
in the above diagram the pixel is indicated by * and its 8 neighbor by a,b,c,d,e,f,g and h.
I define an endpoint pixel as a pixel with value of one and just one neighbor with value of one, the remaining neighbor have a value of zero, so for example this diagram shows an endpoint pixel
000
011
000
because d=1 and all the remaining neighbors are zero.
The following diagram shows instead a pixel which is not and endpoint pixel because it has two neighbors equal to one (a=1 and e=1)
100
010
001
Now we can start to describe a part of a simple algorithm.
In the first step find all the endpoint pixels and put them in a vector: in the following image I marked the endpoints from 1 to 15 (note that the endpoint 15 was not highlighted in the image you posted).
In the second step, for each endpoint, find its closest endpoint: for example consider the endpoint 4, its closest endpoint is 5. Now, if you follow the simple rule of connecting one endpoint with its closest endpoint you will have segments connecting 4-5, 10-11, 13-14, which are all fine. But consider 1: its closest endpoint is 2 or maybe it is 3, but I would like that the algorithm just connected 2 and 3 while connecting 1 to the leftmost vertical line. I would also like the same behavior for 6, 9 and 12.
Now a different situation: what about 6, 7 and 8? Ignore for a moment 8, the closest endpoint of 6 is then 7 but they are already connected, how we can manage this case?
And, last, consider 15: why did not highlight it in the image you posted? Maybe it should be ignored?

May be this would help.
Increase the thickness of the lines to at-least 2.
Find those runs of consecutive foreground pixel in vertical direction in the image whose previous or next column has all background pixel within the run-length. This would give the location of the points, which needs to be processed.
For each point find the nearest steep point. This would be either a branch point or a point where an abrupt change in angle has occured. (Example point 15 in the image of previous answer). If there is no such point there is obviously another end-point. Call these as reference point. The vector between an endpoint and reference point would give the direction of extension.
Now there can be various ways to decide which point to join with. You can take the nearest foreground point in that direction. You can also pick some features depending on the angle and distance between an endpoint and a point of extension to use in a KNN classifier.
Hope it helps.

Related

How to perform matching of markers from two images which are taken from different perspective?

I have a markered robot with circular markers and two images from different perspective as shown: (Circular white rings are the markers)
I want to match the markers in the two images, by matching I mean the bottommost marker of 1st image should be treated as correspondence point of bottom most marker of 2nd image and so on.
The finger-like robot given in the image can bend in any direction given in space (can also bend in a U-like manner).
If it helps, the camera geometry is fixed and known beforehand.
I am lost, as simple correspondence algorithm would not work, since the perspectives are very different. How should I go about matching the two images?
You can start like this:
You know the position of the mounting point on the base panel for each perspective.
You know the positions of the white rings for each perspective as discussed here.
You can derive the direction of the arm at each ring by its tilt.
So you can easily determine the sequence of the positions starting with the mounting point stepping from ring to ring even if the arm is bent. With this you can match the rings from both images. If you have any situation where this fails, please add an according example to your question!
Unfortunately, you don't have matching points but matching curves. You might try to fit ellipses on the rings and take the ellipse centers for points to be matched.
This is an approximation, as the center of a circle does not exactly project as the center of the ellipse, but I don't think that this will be the major source of error: as you only see half circles, the fitting will not be that accurate.
If all nine circles remain visible and are ordered vertically, the matching of the centers is trivial. If they are not ordered but don't form a loop, you can probably start from the lowest and follow the chain of nearest neighbors.

breadth-first search in coordinate based system

I am not an experienced programmer (programming language MATLAB) and hence have barely any knowledge of advanced algorithms. One of these is the breadth-first search. The concept I understand but implementing it into my problem is difficult for me.
My problem:
I place disks, of equal sizes, randomly in a square and will place the coordinates of the disks into separate matrices when they are one connected network. I colorized them for clarity (see image). Now, I have to find the shortest path from left to right of the network which spans from left to right and want to do this based on the coordinates. The disks have to touch in order to be connected to each other. They cannot form a path if they are not touching.
So this is what I currently have:
I have a matrix with coordinates x and coordinates y in columns 1 and 2, every row representing one of the disks (for ease, let's just take the coordinates of all the connecting disks, excluding those which are not spanning from left to right when connected).
The diameter of the disks is known (0.2).
We can easily identify which disks are on the left boundary of the square and which disks are on the right boundary of the square. These represent the possible starting coordinates and the possible goal coordinates.
% Coordinates of group of disks, where the group connects from left to right.
0.0159 0.1385
0.0172 0.2194
0.0179 0.4246
0.0231 0.0486
0.0488 0.1392
0.0709 0.2109
0.0813 0.0595
0.0856 0.3530
0.1119 0.3756
0.1275 0.2530
0.1585 0.4751
0.1702 0.2926
0.1908 0.3828
0.1961 0.3277
0.2427 0.4001
0.2492 0.4799
0.2734 0.4788
0.3232 0.3547
0.3399 0.3275
0.3789 0.3716
0.4117 0.3474
0.4579 0.3961
0.4670 0.3394
0.4797 0.3279
0.4853 0.4786
0.3495 0.4455
0.4796 0.2736
0.0693 0.0746
0.1288 0.4204
0.1271 0.4071
0.1218 0.4646
0.1255 0.3080
0.4154 0.2926
Positions of disks and colored the connecting disks. Image is very schematic and many more disks should be expected in a much larger area (keeping same size disks).
My strategy was to set up a breadth-first search, taking the starting coordinates as one of the disks (can be any) on the left side of the square. The goal will be to find the shortest path to the right side of the square.
To my understanding, I want to pick a starting coordinate and check all disks if they are within a diameter distance (middle point to middle point of the disks) of my starting coordinate. If they are within range of my starting coordinate I want to place them in a 'queue' (natively not supported by MATLAB? but let's set one up ourselves). Then, the next step is to take the first disk which was close enough and do the same for this one. I can do this but once I have to do the second disk which was within my first disk, I am lost in how and/or what data structure I should take and how to save the 'path' which it is finding. This means I can find a path but not all paths and hence also not the shortest path.
I appreciate any help! Maybe some documentation which I have not seen yet or maybe an example which is very comparable.
Best regards,
If they are within range of my starting coordinate I want to place
them in a 'queue'
Before you add it to the queue you want to make sure this disk was not processed (put in the queue) before. Each disk should be processed only once, so you make sure the "neighbor" disk has not been processed before, then mark it as processed and add it to the queue.
the next step is to take the first disk which was close enough and do
the same for this one.
Actually the next disc to process is simply the one at the head of the queue.
Continue to do so until you hit the target / stop criteria.
how to save the 'path' which it is finding
There are several techniques to do so. An easy one would be to maintain a "come from" value to each disk. This value points to the "parent" of the disk.
Since each disk is processed once (at most) it will have one "come from" value or none.
When the target is reached the path can be reconstructed starting from the "come from" value of the target.
This question has now been solved!
The way I have solved this was close to what was already suggested in my question but also with help from some of the comments.
The distance between coordinates can be put into a matrix. Let us look at coordinate (disk) 1 and coordinate (disk 3). This means that we will be at elements (1,3) and (3,1). If the disks are within touching distance, these two elements will indicate a 1 and otherwise a 0. This is done for all disks and this creates the adjacency matrix.
I created a 'graph' with the built-in function G = Graph(adjacency matrix) we can create an undirected graph. Then with the built in function [path, distance of path] = shortestpath(G,s,t) where G is the graph and s and t are the starting disks (in this case, indicated by integers), the shortest path can be found from disk s to t.
There is however one thing that we must pay attention to and that is representing the actual distance between disks. If we look at G, we can actually see that it contains two objects. One representing the nodes and the other representing the edges. The edges is crucial for the coordinate based distances as we can set the 'weight' of the edge as the distance between two disks. This can simply be done by looping over the nodes and calculating the distance between the neighbouring nodes and inserting them into the weight (G.Edges.Weight(i) = distance between the respective nodes).
How do I find the optimal path from left to right? I loop over all starting disks (defined as touching the left side of the square) and find the shortest path to all disks that touch the right side of the square. Saving the distances of the paths the actual shortest path can be found.
To give you an example of what can be achieved, the following video shows what paths from every starting disk can be found and the final frame shows the shortest path. Video of path finding. The shortest path I have also attached here:
Shortest path left to right.
If there are any questions you would like to ask me about specifics, let me know.

DITMatlab: How to calculate hysteresis for experimental data set?

I got an experimental data set that looks more or less like this.
I need to determine how big the hysteresis loop is, aka if I look at two points with the same capacity (Y axis), whats the maximum distance between said points (X axis).
The issue is, data points arent located on the same Y value, aka I cant just find max X and min X for every Y and subtract them - that'd be too easy :^)
I figured I can use convex hull (convhull) to calculate the outer envelope of the set, but then I realised, it will only work for the convex part, not the concaved part, but I guess I can divide my data set into smaller subsets and find a sum of them... or something.
And then, assuming I have the data set thats only the outer outline of the data set, I need to calculate distances between left and right border (as shown here), but then again, thats just data set of X and Y, and Id need to find the point where green line crosses outer rim
So here are the questions:
Is there a matlab procedure that calculates the outer outline of data set, that works with the concaved part - kinda like convhull, but better?
Assuming I have the outline data set, is there an easy way to calculate secant line of data set, like shown on second picture??
Thanks for any advice, hope I made what I have in mind clear enough - english isnt my first language
Benji
EDIT 1: Or perhaps there is an easier (?) way to determine, which points form biggest outline? Like... group points into (duh) groups, lets say, those near 20%, 30%, 40%... and then pick two randomly (or brute force pick all possible pairs), one for top boundary, other for bot boundary, and then calculate area of polygon formed this way? Then, select set of points resulting in polygon with biggest area?
EDIT 2: Ooor I could group them like I thought I would before, and then work on only two groups at a time. Find convex hull for two groups, then for two next groups, and when Im done with all the groups, Id only need to find points common to all the group, and find a global hull :D Yeah, that might work :D

how can i split an image based on longest horizontal edge?

For example , how can i split the two row of books of this shelf based on horizontal edge? I have used sobel edge detector to detect the edges but i don't know how to or what condition to use to split the image.
I can recommend you two different approach to solve this problem.
1) Machine learning approach. This requires some labeled data, indicating the y coordinate of the edge position, then HOG feature plus a random forest classifier will do the job.
2) Image processing approach. First, let's see the output of what i have done:
the blue color indicating the score of being the desired y position of the separation edge.
Such approach always relies on some assumptions on your data, here we suppose that the target horizontal edge separating books, which contains a lot of vertical lines. Namely, we are looking for y coordinate where locate long horizontal lines which are not cut by vertical lines.
Once define our objective, the rest begin very easy.
First we need a straight line detector, hough transform will do.
Secondly, we vote for each y coordinates for being the best separator using two scores:
1) 1st score describes how many long horizontal lines (found previously) are located in the neighborhood. Let's call it s_h.
2) 2nd score describes how many long vertical lines are located in the neighborhood. Let's call it s_v.
Finally, we only need to combine s_v and s_h to make a final score. For example,
s = s_h / (s_v + 1)
Using this, we get the first scoring map posted at the beginning. Some further post processing need to be done, but should not be difficult.
Here is just one possibility to solve it, here you find my code presented in a notebook.

Region of Interest in nighttime vehicle detection

I am developing a project of detecting vehicles' headlights in night scene. I am working on a demo on MATLAB. My problem is that I need to find region of interest (ROI) to get low computing requirement. I have researched in many papers and they just use a fixed ROI like this one, the upper part is ignored and the bottom is used to analysed later.
However, if the camera is not stable, I think this approach is inappropriate. I want to find a more flexible one, which alternates in each frame. My experiments images are shown here:
If anyone has any idea, plz give me some suggestions.
I would turn the problem around and say that we are looking for headlights
ABOVE a certain line rather than saying that the headlights are below a certain line i.e. the horizon,
Your images have a very high reflection onto the tarmac and we can use that to our advantage. We know that the maximum amount of light in the image is somewhere around the reflection and headlights. We therefore look for the row with the maximum light and use that as our floor. Then look for headlights above this floor.
The idea here is that we look at the profile of the intensities on a row-by-row basis and finding the row with the maximum value.
This will only work with dark images (i.e. night) and where the reflection of the headlights onto the tarmac is large.
It will NOT work with images taking in daylight.
I have written this in Python and OpenCV but I'm sure you can translate it to a language of your choice.
import matplotlib.pylab as pl
import cv2
# Load the image
im = cv2.imread('headlights_at_night2.jpg')
# Convert to grey.
grey_image = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
Smooth the image heavily to mask out any local peaks or valleys
We are trying to smooth the headlights and the reflection so that there will be a nice peak. Ideally, the headlights and the reflection would merge into one area
grey_image = cv2.blur(grey_image, (15,15))
Sum the intensities row-by-row
intensity_profile = []
for r in range(0, grey_image.shape[0]):
intensity_profile.append(pl.sum(grey_image[r,:]))
Smooth the profile and convert it to a numpy array for easy handling of the data
window = 10
weights = pl.repeat(1.0, window)/window
profile = pl.convolve(pl.asarray(intensity_profile), weights, 'same')
Find the maximum value of the profile. That represents the y coordinate of the headlights and the reflection area. The heat map on the left show you the distribution. The right graph shows you the total intensity value per row.
We can clearly see that the sum of the intensities has a peak.The y-coordinate is 371 and indicated by a red dot in the heat map and a red dashed line in the graph.
max_value = profile.max()
max_value_location = pl.where(profile==max_value)[0]
horizon = max_value_location
The blue curve in the right-most figure represents the variable profile
The row where we find the maximum value is our floor. We then know that the headlights are above that line. We also know that most of the upper part of the image will be that of the sky and therefore dark.
I display the result below.
I know that the line in both images are on almost the same coordinates but I think that is just a coincidence.
You may try downsampling the image.