How to clean nodes (corner points) from thinning result? - image-processing

I'm working with Julia. I've the following result from a road's binary image
after Thinning (skeleton)
After thinning, I used Harris corner detection, which gets me red dots. To get line segments, I remove the red dots and each line is a line-segment with unique number.
The problem is that some red points are too close. How can I make red dots white (i.e. not corner points) if the points are too close?
using Images
using LinearAlgebra
t = thinning(road_image)
detection_method = harris
corners = imcorner(t, Percentile(99.5); method=detection_method)
labels = label_components(corners)
new_labels = label_components(labels) #because some labels are cluster of points, so this makes them 1
all_nodes = component_centroids(new_labels)
centre_line_node = CartesianIndex.(map(i -> trunc.(Int, all_nodes[i]), 1:length(all_nodes)))
img_labels = RGB{N0f8}.(t)
img_labels[centre_line_node] .= RGB(1.0, 0.0, 0.0)

Although you didn't provide enough details about your code (even the full code) again, I managed to get the job done using my previous answer using a little bit of justification:
using Images, ImageBinarization
road_image = load("oxLCJ.png") # The raw image
gimg = Gray.(road_image)
bin = binarize(gimg, UnimodalRosin()) .> 0.5
thinned = thinning(bin)
function check_adjacent(
loc::CartesianIndex{2},
all_locs::Vector{CartesianIndex{2}}
)
conditions = [
loc - CartesianIndex(0,1) ∈ all_locs,
loc + CartesianIndex(0,1) ∈ all_locs,
loc - CartesianIndex(1,0) ∈ all_locs,
loc + CartesianIndex(1,0) ∈ all_locs,
loc - CartesianIndex(1,1) ∈ all_locs,
loc + CartesianIndex(1,1) ∈ all_locs,
loc - CartesianIndex(1,-1) ∈ all_locs,
loc + CartesianIndex(1,-1) ∈ all_locs
]
return sum(conditions)
end;
function find_the_contour_branches(img::BitMatrix)
img_matrix = convert(Array{Float64}, img)
not_black = findall(!=(0.0), img_matrix)
contours_branches = Vector{CartesianIndex{2}}()
for nb∈not_black
t = check_adjacent(nb, not_black)
(t==1 || t==3) && push!(contours_branches, nb)
end
return contours_branches
end;
function highlight_contours(img, contours; resize::Bool=false, scale::Union{Int64, Float64}=1)
img_matrix = convert(Array{RGB, 2}, img)
img_matrix[contours] .= RGB(1,0,0)
if resize
img_matrix = typeof(scale)==Int64 ? imresize(img_matrix, size(img).*scale) : imresize(img_matrix, ratio=scale)
end
return img_matrix
end;
contours = find_the_contour_branches(thinned)
highlight_contours(thinned, contours)
Gives me a result that if I zoom in, I see the following:
If you want details about the functions, see the previous answer I mentioned above (It's documented). Here, I just replaced contours with contours_branches and t==1 && push!(contours, nb) with (t==1 || t==3) && push!(contours_branches, nb) as far as I remember. But the idea is the same.
Update:
The code can get enhanced further. For example, I replaced the for loop in the highlight_contours function with img_matrix[contours] .= RGB(1,0,0). But other improvements are out of the interest of this answer.

Related

power law and truncated power law curve fitting problem in python

Recently, I am making a code that allows curve fitting (power law and truncated power law) in a log-log scale graph using a series of data.
I found the 'from scipy.optimize import curve_fit' module, so the code I made it is as follows:
Power law (the x and y value of data is self.fx_ti and self.fy_pti, respectively)
def Powerlaw (self, event):
fig, ax = plt.subplots(2,1)
ax[0].plot(self.fx_ti, self.fy_pti, 'ko', alpha = 0.7, markersize = 4)
ax[0].set_title("Probability Distribution")
ax[0].set(ylabel = "P" + r"($\tau_i$) " + r'$s^{-1}$', xlabel = r"$\tau _i$"+" (s)")
def power_law(ti, a0, mi):
return a0*ti**(-mi)
popt, pcov = curve_fit(power_law, self.fx_ti, self.fy_pti, p0 = [0,0])
ax[0].plot(self.fx_ti, power_law(self.fx_ti, *popt), 'b', lw = 1)
res = self.fy_pti - power_law(self.fx_ti, *popt)
ax[1].plot(self.fx_ti, res, "ko", markersize = 4)
ax[0].set_xscale('log')
ax[0].set_yscale('log')
plt.ion
plt.show()
I think a pretty good fitting occurs when running the code.
But the problem is in 'truncated power law' fitting.
There is nothing different from general power law fitting.
The code I made it is as follows :
def Truncated (self, event):
fig, ax = plt.subplots(2,1)
ax[0].plot(self.fx_ti, self.fy_pti, 'ko', alpha = 0.7, markersize = 4)
ax[0].set_title("Probability Distribution")
ax[0].set(ylabel = "P" + r"($\tau_i$) " + r'$s^{-1}$', xlabel = r"$\tau _i$"+" (s)")
def truncated_power_law(x, a, b, c):
return a*x**(-b)*np.exp(np.multiply(-1,x)/c)
popt, pcov = curve_fit(truncated_power_law, self.fx_ti, self.fy_pti)
ax[0].plot(self.fx_ti, popt[0]*self.fx_ti**(-popt[1])*np.exp(np.multiply(-1,self.fx_ti)/popt[2]), 'b', lw = 1)
res = self.fy_pti - truncated_power_law(self.fx_ti, *popt)
ax[1].plot(self.fx_ti, res, "ko", markersize = 4)
ax[0].set_xscale('log')
ax[0].set_yscale('log')
plt.ion
plt.show()
You can see the result in the picture I attached.
Please python code geniuses...help...please
enter image description here

Exit condition 41 on SNOPT

I'm trying to run an optimization with SNOPT.
Right now as I run it I consistently get exit condition 41.
I've added the following parameters to the solver:
prog.SetSolverOption(solver.solver_id(),"Function Precision","1e-6")
prog.SetSolverOption(solver.solver_id(),"Major Optimality Tolerance","1e-3")
prog.SetSolverOption(solver.solver_id(),"Superbasics limit","600")
#print("Trying to Solve")
result = solver.Solve(prog)
print(result.is_success())
But I still contently get the same exit condition.
The error seems to be from the interpolation function I'm using. (When I remove it I no longer get the error).
t, c, k = interpolate.splrep(sref, kapparef, s=0, k=3)
kappafnc = interpolate.BSpline(t, c, k, extrapolate=False)
Here is the function I think I determined was causing the issue:
def car_continous_dynamics(self, state, force, steering):
beta = steering
s = state[0]
#print(s)
n = state[1]
alpha = state[2]
v = state[3]
#State = s, n, alpha , v
#s= distance along the track, n = perpendicular distance along the track
#alpha = velocity angle relative to the track
#v= magnitude of the velocity of the car
s_val = 0
if s.value() >0:
s_val = s.value()
Cm1 = 0.28
Cm2 = 0.05
Cr0 = 0.011
Cr2 = 0.006
m = 0.043
phi_dot = v*beta*15.5
Fxd = (Cm1 - Cm2 * v) * force - Cr2 * v * v - Cr0 *tanh(5 * v)
s_dot = v*cos(alpha+.5*beta)/(1)##-n*self.kappafunc(s_val))
n_dot= v*sin(alpha+.5*beta)
alpha_dot = phi_dot #-s_dot*self.kappafunc(s_val)
v_dot=Fxd/m*cos(beta*.5)
# concatenate velocity and acceleration
#print(s_dot)
#print(n_dot)
#print(alpha_dot)
#print(v_dot)
state_dot = np.array((s_dot,n_dot,alpha_dot,v_dot))
#print("State dot")
#print(state_dot.dtype.name)
#print(state_dot)
#print(state_dot)
return state_dot
``
Debugging INFO 41 in SNOPT is generally challenging, it is often caused by some bad gradient (but could also due to the problem being really hard to optimize).
You should check if your gradient is well-behaved. I see you have
s_val = 0
if s.value() >0:
s_val = s.value()
There are two potential problems
Your s carries the gradient (you could check s.derivatives(), it has non-zero gradient), but when you compute s_val, this is a float object with no gradient. Hence you lose the gradient information.
s_val is non-differentiable at 0.
I would use s instead of s_val in your function (without the branch if s.value() > 0). And also add a constraint s>=0 by
prog.AddBoundingBoxConstraint(0, np.inf, s)
With this bounding box constraint, SNOPT guarantees that in each iteration, the value of is is always non-negative.

Minimizing memory usage in Julia function

This function is a workhorse which I want to optimize. Any idea on how its memory usage can be limited would be great.
function F(len, rNo, n, ratio = 0.5)
s = zeros(len); m = copy(s); d = copy(s);
s[rNo]=1
rNo ≤ len-1 && (m[rNo + 1] = s[rNo+1] = -n[rNo])
rNo > 1 && (m[rNo - 1] = s[rowNo-1] = n[rowNo-1])
r=1
while true
for i ∈ 2:len-1
d[i] = (n[i]*m[i+1] - n[i-1]*m[i-1])/(r+1)
end
d[1] = n[1]*m[2]/(r+1);
d[len] = -n[len-1]*m[len-1]/(r+1);
for i ∈ 1:len
s[i]+=d[i]
end
sum(abs.(d))/sum(abs.(m)) < ratio && break #converged
m = copy(d); r+=1
end
return reshape(s, 1, :)
end
It calculates rows of a special matrix exponential which I stack later.
Although the full method is quite faster than built in exp thanks to the special properties, it takes up far more memory as measured by #time.
Since I am a noob in memory management and also in Julia, I am sure it can be optimized quite a bit..
Am I doing something obviously wrong?
I think most of your allocations come from sum(abs.(d))/sum(abs.(m)) < ratio && break #converged. If you replace it with sum(abs, d)/sum(abs,m) < ratio && break #converged those allocations should go away. (it also will be a speed boost).
Your other allocations can be removed by replacing m = copy(d) with m .= d which does an element-wise copy.
There are also a couple of style things where I think you could make this a nicer function to read and use. My changes would be as follows
function F(rNo, v, ratio = 0.5)
len = length(v)
s = zeros(len+1); m = copy(s); d = copy(s);
s[rNo]=1
rNo ≤ len && (m[rNo + 1] = s[rNo+1] = -v[rNo])
rNo > 1 && (m[rNo - 1] = s[rowNo-1] = v[rowNo-1])
r=1
while true
for i ∈ 2:len
d[i] = (v[i]*m[i+1] - v[i-1]*m[i-1]) / (r+1)
end
d[1] = v[1]*m[2]/(r+1);
d[end] = -v[end]*m[end]/(r+1);
s .+= d
sum(abs, d)/sum(abs, m) < ratio && break #converged
m .= d; r+=1
end
return reshape(s, 1, :)
end
The most notable change is removing len from the arguments. Including an array length argument is common in C (and probably others) where finding the length of an array is hard, but in Julia length is cheap (O(1)), and adding extra arguments is just more clutter and confusion for the people using it. I also made use of the fact that julia is able to turn s[end] into s[length(x)] to make this a little cleaner. Also, in general when using Julia you should look for ways to use dotted operations rather than writing for loops. The for loops will be fast, but why take 3 lines to do what you could in 1 shorter line? (I also renamed n to v since to me n is a number and v is a vector, but that is pure preference).
I hope this helps.

Highcharts/HighcharteR - draw a polygon with rounded corners

library(highcharter)
highchart() %>%
hc_add_series(name='Polygon',type='polygon',data=list(c(1,4),c(2,4), c(3,3), c(2,3)),
borderRadius = 10, lineColor = "red", lineWidth = 3)][1]][1]
Hello everybody. I use a polygon to display some data. I would prefer to have the borders to be round, but the borderRadius attribute does not work for the polygon.
Does anyone have an idea how to archieve a rounded look of my polygon? Documentation did not help in this case :-(. This is made the the R Highcharter package, but I would also be totally fine with an example in die native JS Library.
Thank you!
This works somewhat:
spline.poly <- function(xy, vertices, k=3, ...) {
# Assert: xy is an n by 2 matrix with n >= k.
# Wrap k vertices around each end.
n <- dim(xy)[1]
if (k >= 1) {
data <- rbind(xy[(n-k+1):n,], xy, xy[1:k, ])
} else {
data <- xy
}
# Spline the x and y coordinates.
data.spline <- spline(1:(n+2*k), data[,1], n=vertices, ...)
x <- data.spline$x
x1 <- data.spline$y
x2 <- spline(1:(n+2*k), data[,2], n=vertices, ...)$y
# Retain only the middle part.
cbind(x1, x2)[k < x & x <= n+k, ]
}
X <- matrix(c(resultdf$yAxis, resultdf$xAxis), ncol=2)
hpts <- chull(X) # Creates indices of a convex hull from a matrix
hpts <- c(hpts, hpts[1]) # connect last and first dot
hpts <- data.frame(X[hpts, ])
hpts <- data.frame(spline.poly(as.matrix(data.frame(hpts$X1, hpts$X2)), 500)) %>%
setNames(c("yAxis", "xAxis"))
the spline.poly function creates a lot of new points which connect to a more rounded shape :-)

How to make ImageTransformation produce an anamorphic version of image

I'm experimenting with the ImageTransformation function to try to make anamorphic versions of images, but with limited progress so far. I'm aiming for the results you get using the image reflected in a cylindrical mirror, where the image curves around the central mirror for about 270 degrees. The wikipedia article has a couple of neat examples (and I borrowed Holbein's skull from them too).
i = Import["../Desktop/Holbein_Skull.jpg"];
i = ImageResize[i, 120]
f[x_, y_] := {(2 (y - 0.3) Cos [1.5 x]), (2 (y - 0.3) Sin [1.5 x])};
ImageTransformation[i, f[#[[1]], #[[2]]] &, Padding -> White]
But I can't persuade Mathematica to show me the entire image, or to bend it correctly. The anamorphic image should wrap right round the mirror placed "inside" the centre of the image, but it won't. I found suitable values for constants by putting it inside a manipulate (and turning the resolution down :). I'm using the formula:
x1 = a(y + b) cos(kx)
y1 = a(y + b) sin(kx)
Any help producing a better result would be greatly appreciated!
In ImageTransformation[f,img], the function f is such that a point {x,y} in the resulting image corresponds to f[{x,y}] in img. Since the resulting image is basically the polar transformation of img, f should be the inverse polar transformation, so you could do something like
anamorphic[img_, angle_: 270 Degree] :=
Module[{dim = ImageDimensions[img], rInner = 1, rOuter},
rOuter = rInner (1 + angle dim[[2]]/dim[[1]]);
ImageTransformation[img,
Function[{pt}, {ArcTan[-#2, #1] & ## pt, Norm[pt]}],
DataRange -> {{-angle/2, angle/2}, {rInner, rOuter}},
PlotRange -> {{-rOuter, rOuter}, {-rOuter, rOuter}},
Padding -> White
]
]
The resulting image looks something like
anamorphic[ExampleData[{"TestImage", "Lena"}]]
Note that you can a similar result with ParametricPlot and TextureCoordinateFunction, e.g.
anamorphic2[img_Image, angle_: 270 Degree] :=
Module[{rInner = 1,rOuter},
rOuter = rInner (1 + angle #2/#1 & ## ImageDimensions[img]);
ParametricPlot[{r Sin[t], -r Cos[t]}, {t, -angle/2, angle/2},
{r, rInner, rOuter},
TextureCoordinateFunction -> ({#3, #4} &),
PlotStyle -> {Opacity[1], Texture[img]},
Mesh -> None, Axes -> False,
BoundaryStyle -> None,
Frame -> False
]
]
anamorphic2[ExampleData[{"TestImage", "Lena"}]]
Edit
In answer to Mr.Wizard's question, if you don't have access to ImageTransformation or Texture you could transform the image data by hand by doing something like
anamorph3[img_, angle_: 270 Degree, imgWidth_: 512] :=
Module[{data, f, matrix, dim, rOuter, rInner = 1.},
dim = ImageDimensions[img];
rOuter = rInner (1 + angle #2/#1 & ## dim);
data = Table[
ListInterpolation[#[[All, All, i]],
{{rOuter, rInner}, {-angle/2, angle/2}}], {i, 3}] &#ImageData[img];
f[i_, j_] := If[Abs[j] <= angle/2 && rInner <= i <= rOuter,
Through[data[i, j]], {1., 1., 1.}];
Image#Table[f[Sqrt[i^2 + j^2], ArcTan[i, -j]],
{i, -rOuter, rOuter, 2 rOuter/(imgWidth - 1)},
{j, -rOuter, rOuter, 2 rOuter/(imgWidth - 1)}]]
Note that this assumes that img has three channels. If the image has fewer or more channels, you need to adapt the code.

Resources