cartopy: map overlay on NOAA APT image - matplotlib-basemap

I am working on a project trying to decode NOAA APT images, so far I reached the stage where I can get the images from raw IQ recordings from RTLSDRs. Here is one of the decoded images,
Decoded NOAA APT image this image will be used as input for the code (seen as m3.png here on)
Now I am working on overlaying map boundaries on the image (Note: Only on the left half part of the above image)
We know, the time at which the image was captured and the satellite info: position, direction etc. So, I used the position of the satellite to get the center of map projection and and direction of satellite to rotate the image appropriately.
First I tried in Basemap, here is the code
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
from scipy import ndimage
im = plt.imread('m3.png')
im = im[:,85:995] # crop only the first part of whole image
rot = 198.3913296679117 # degrees, direction of sat movement
center = (50.83550180700588, 16.430852851867176) # lat long
rotated_img = ndimage.rotate(im, rot) # rotate image
w = rotated_img.shape[1]*4000*0.81 # in meters, spec says 4km per pixel, but I had to make it 81% less to get better image
h = rotated_img.shape[0]*4000*0.81 # in meters, spec says 4km per pixel, but I had to make it 81% less to get better image
m = Basemap(projection='cass',lon_0 = center[1],lat_0 = center[0],width = w,height = h, resolution = "i")
m.drawcoastlines(color='yellow')
m.drawcountries(color='yellow')
im = plt.imshow(rotated_img, cmap='gray', extent=(*plt.xlim(), *plt.ylim()))
plt.show()
I got this image as a result, which seems pretty good
I wanted to move the code to Cartopy as it is easier to install and is actively being developed. I was unable to find a similar way to set boundaries i.e. width and height in meters. So, I modified most similar example. I found a function which would add meters to longs and lats and used that to set the boundaries.
Here is the code in Cartopy,
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
from scipy import ndimage
import cartopy.feature
im = plt.imread('m3.png')
im = im[:,85:995] # crop only the first part of whole image
rot = 198.3913296679117 # degrees, direction of sat movement
center = (50.83550180700588, 16.430852851867176) # lat long
def add_m(center, dx, dy):
# source: https://stackoverflow.com/questions/7477003/calculating-new-longitude-latitude-from-old-n-meters
new_latitude = center[0] + (dy / 6371000.0) * (180 / np.pi)
new_longitude = center[1] + (dx / 6371000.0) * (180 / np.pi) / np.cos(center[0] * np.pi/180)
return [new_latitude, new_longitude]
fig = plt.figure()
img = ndimage.rotate(im, rot)
dx = img.shape[0]*4000/2*0.81 # in meters
dy = img.shape[1]*4000/2*0.81 # in meters
leftbot = add_m(center, -1*dx, -1*dy)
righttop = add_m(center, dx, dy)
img_extent = (leftbot[1], righttop[1], leftbot[0], righttop[0])
ax = plt.axes(projection=ccrs.PlateCarree())
ax.imshow(img, origin='upper', cmap='gray', extent=img_extent, transform=ccrs.PlateCarree())
ax.coastlines(resolution='50m', color='yellow', linewidth=1)
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', edgecolor='yellow')
plt.show()
Here is the result from Cartopy, it is not as good as the result from Basemap.
I have following questions:
I found it impossible to rotate the map instead of the image, in
both basemap and cartopy. Hence I resorted to rotating the image, is
there a way to rotate the map?
How do I improve the output of cartopy? I think it is the way in
which I am calculating the extent a problem. Is there a way I can
provide meters to set the boundaries of the image?
Is there a better way to do what I am trying to do? any projection that are specific to these kind of applications?
I am adjusting the scale (the part where I decide the number of kms per pixel) manually, is there a way to do this based
on
satellite's altitude?
Any sort of input would be highly appreciated. Thank you so much for your time!
If you are interested you can find the project here.

As far as I can see, there is no ability for the underlying Proj.4 to define satellite projections with rotated perspectives (happy to be shown otherwise - I'm no expert!) (note: perhaps via ob_tran?). This is the main reason you can't do this in "native" coordinates/orientation with Basemap or Cartopy.
This question really comes down to a georeferencing problem, to which I couldn't find enough information in places like https://www.cder.dz/download/Art7-1_1.pdf.
My solution is entirely a fudge, but does get you quite close to referencing this image. I double the fudge factors are actually universal, which is a bit of an issue if you want to write general-purpose code.
Some of the fudges I had to make (trial-and-error):
adjust the satellite bearing by 3.2 degrees
adjust where the image centre is by moving it along the satellite trajectory by 10km
adjust where the image centre is by moving it perpendicularly along the satellite trajectory by 10km
scale the x and y pixel sizes by 0.62 and 0.65 respectively
use the "near-sided perspective" projection at an unrealistic satellite_height
The result is what appears to be a relatively well registered image, but as I say, seems unlikely to be generally applicable to all images received:
The code to produce this image (fairly involved, but complete):
import urllib.request
urllib.request.urlretrieve('https://i.stack.imgur.com/UBIuA.jpg', 'm3.jpg')
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
from scipy import ndimage
import cartopy.feature
im = plt.imread('m3.jpg')
im = im[:,85:995] # crop only the first part of whole image
rot = 198.3913296679117 # degrees, direction of sat movement
center = (50.83550180700588, 16.430852851867176) # lat long
import numpy as np
from cartopy.geodesic import Geodesic
import matplotlib.transforms as mtransforms
from matplotlib.axes import Axes
tweaked_rot = rot - 3.2
geod = Geodesic()
# Move the center along the trajectory of the satellite by 10KM
f = np.array(
geod.direct([center[1], center[0]],
180 - tweaked_rot,
10000))
tweaked_center = f[0, 0], f[0, 1]
# Move the satellite perpendicular from its proposed trajectory by 15KM
f = np.array(
geod.direct([tweaked_center[0], tweaked_center[1]],
180 - tweaked_rot + 90,
10000))
tweaked_center = f[0, 0], f[0, 1]
data_crs = ccrs.NearsidePerspective(
central_latitude=tweaked_center[1],
central_longitude=tweaked_center[0],
)
# Compute the center in data_crs coordinates.
center_lon_lat_ortho = data_crs.transform_point(
tweaked_center[0], tweaked_center[1], ccrs.Geodetic())
# Define the affine rotation in terms of matplotlib transforms.
rotation = mtransforms.Affine2D().rotate_deg_around(
center_lon_lat_ortho[0], center_lon_lat_ortho[1], tweaked_rot)
# Some fudge factors. Sorry - there are entirely application specific,
# perhaps some reading of https://www.cder.dz/download/Art7-1_1.pdf
# would enlighten these... :(
ff_x, ff_y = 0.62, 0.65
ff_x = ff_y = 0.81
x_extent = im.shape[1]*4000/2 * ff_x
y_extent = im.shape[0]*4000/2 * ff_y
img_extent = [-x_extent, x_extent, -y_extent, y_extent]
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection=data_crs)
ax.margins(0.02)
with ax.hold_limits():
ax.stock_img()
# Uing matplotlib's image transforms if the projection is the
# same as the map, otherwise we need to fall back to cartopy's
# (slower) image resampling algorithm
if ax.projection == data_crs:
transform = rotation + ax.transData
else:
transform = rotation + data_crs._as_mpl_transform(ax)
# Use the original Axes method rather than cartopy's GeoAxes.imshow.
mimg = Axes.imshow(ax, im, origin='upper', cmap='gray',
extent=img_extent, transform=transform)
lower_left = rotation.frozen().transform_point([-x_extent, -y_extent])
lower_right = rotation.frozen().transform_point([x_extent, -y_extent])
upper_left = rotation.frozen().transform_point([-x_extent, y_extent])
upper_right = rotation.frozen().transform_point([x_extent, y_extent])
plt.plot(lower_left[0], lower_left[1],
upper_left[0], upper_left[1],
upper_right[0], upper_right[1],
lower_right[0], lower_right[1],
marker='x', color='black',
transform=data_crs)
ax.coastlines(resolution='10m', color='yellow', linewidth=1)
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', edgecolor='yellow')
sat_pos = np.array(geod.direct(tweaked_center, 180 - tweaked_rot,
np.linspace(-x_extent*2, x_extent*2, 50)))
with ax.hold_limits():
plt.plot(sat_pos[:, 0], sat_pos[:, 1], transform=ccrs.Geodetic(),
label='Satellite path')
plt.plot(tweaked_center, 'ob')
plt.legend()
As you can probably tell, I got a bit carried away with this question. It is a super interesting problem, but not really a cartopy/Basemap one per-say.
Hope that helps!

Related

Is there an algorithm to find known size and shape object in an image?

Since image processing and computer vision aren't of my field of study I'm having difficulty finding an algorithm that can identify the positions of rectangles of known size and proportion in certain images to automate a process.
These are grayscale images containing some circles and only one or none white rectangle with rounded edges, as can be seen in the example figure below.
3 different imagens with the "same" retangle to be found
Thank you
Try OpenCV, it stands for Open Computer Vision. It’s free. This is written in Python.
import cv2
import numpy as np
img = cv2.imread("C:\\Users\\mogar\\Desktop\\temp.jpg")
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(grayImage, 160, 255, cv2.THRESH_BINARY)
kernel = np.ones((5,5),np.uint8)
thresh = cv2.erode(thresh,kernel,iterations = 1)
#thresh = np.invert(thresh)
cv2.imshow("Threholded Image", thresh)
cv2.waitKey(0) & 0xFF == ord('q')
cv2.destroyAllWindows()
_, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
for cnts in contours:
rect = cv2.minAreaRect(cnts)
box = cv2.boxPoints(rect)
box = np.int0(box)
(x,y),(w,h),angle = rect
w = int(w)
h = int(h)
area = w*h
if area > 10000 and area < 100000:
print("Area Check", area)
cv2.drawContours(img, [box], 0, (0,0,255), 5)
small = cv2.resize(img, (0,0), fx=0.3, fy=0.3)
cv2.imshow("Contours", small)
cv2.waitKey(0) & 0xFF == ord('q')
cv2.destroyAllWindows()
You may need to adjust some of the threshold values and area values so that you'll be enclosing only the rectangles. You'll notice the rectangles are not fully enclosed right now, that is literally because the text is getting in the way and cutting the rectangles in half. If you had a clean image; I'm sure this would work great. If you have any questions please don't hesitate the ask, but it may take some time before I can answer.

annulus with scipy Delaunay

i try to draw a 3d solid that represents an annulus. I have used the scipy module and Delaunay to do the calculation.
Unfortunately the plot shows a 3d cylinder and not an annulus. Has somebody an idea how to modify the code? Is scipy the right module? Can i use Delaunay with retangular shapes?
thanks in advance!
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.spatial import Delaunay
points = 50
theta = np.linspace(0,2*np.pi,points)
radius_middle = 7.5
radius_inner = 7
radius_outer = 8
x_m_cartesian = radius_middle * np.cos(theta)
y_m_cartesian = radius_middle * np.sin(theta)
z_m_cartesian = np.zeros(points)
M_m = np.c_[x_m_cartesian,y_m_cartesian,z_m_cartesian]
x_i_cartesian = radius_inner * np.cos(theta)
y_i_cartesian = radius_inner * np.sin(theta)
z_i_cartesian = np.zeros(points)
M_i = np.c_[x_i_cartesian,y_i_cartesian,z_i_cartesian]
x1_m_cartesian = radius_middle * np.cos(theta)
y1_m_cartesian = radius_middle * np.sin(theta)
z1_m_cartesian = np.ones(points)
M1_m = np.c_[x1_m_cartesian,y1_m_cartesian,z1_m_cartesian]
x2_i_cartesian = radius_inner * np.cos(theta)
y2_i_cartesian = radius_inner * np.sin(theta)
z2_i_cartesian = np.ones(points)
M2_i = np.c_[x2_i_cartesian,y2_i_cartesian,z2_i_cartesian]
M = np.vstack((M_m,M_i,M1_m,M2_i))
# Delaunay
CH = Delaunay(M).convex_hull
x,y,z = M[:,0],M[:,1],M[:,2]
fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111,projection='3d')
#ax.scatter(x[:,0],y[:,1],z[:,2])
ax.plot_trisurf(x,y,z,triangles=CH, shade=False, color='lightblue',lw=1, edgecolor='k')
plt.show()
As noted in the comments the convex hull is a convex shape and therefore cannot represent an annulus. However, the concept of the concave hull (also known as the alpha-shape) is probably appropriate for your needs. Basically, the alpha-shape removes from the Delaunay triangulation the triangles (tetrahedra in your 3D case) that have a circumradius greater than some value (defined by the alpha parameter).
This answer provides an implementation of the alpha-shape surface (i.e., the outer boundary) for 3D points. Using the alpha_shape_3D function from that answer, with an alpha value of 3, resulted in the figure below.
The following two lines in the code (replacing the assignment to CH and the plot function) do the job.
vertices, edges, facets = alpha_shape_3D(pos=M, alpha=3.)
ax.plot_trisurf(x,y,z,triangles=facets, shade=False, color='lightblue',lw=1, edgecolor='k')

How to convert from the image coordinates to Cartesian coordinates

I have this 3D image generated from the simple code below.
% Input Image size
imageSizeY = 200;
imageSizeX = 120;
imageSizeZ = 100;
%# create coordinates
[rowsInImage, columnsInImage, pagesInImage] = meshgrid(1:imageSizeY, 1:imageSizeX, 1:imageSizeZ);
%# get coordinate array of vertices
vertexCoords = [rowsInImage(:), columnsInImage(:), pagesInImage(:)];
centerY = imageSizeY/2;
centerX = imageSizeX/2;
centerZ = imageSizeZ/2;
radius = 28;
%# calculate distance from center of the cube
sphereVoxels = (rowsInImage - centerY).^2 + (columnsInImage - centerX).^2 + (pagesInImage - centerZ).^2 <= radius.^2;
%# Now, display it using an isosurface and a patch
fv = isosurface(sphereVoxels,0);
patch(fv,'FaceColor',[0 0 .7],'EdgeColor',[0 0 1]); title('Binary volume of a sphere');
view(45,45);
axis equal;
grid on;
xlabel('x-axis [pixels]'); ylabel('y-axis [pixels]'); zlabel('z-axis [pixels]')
I have tried plotting the image with isosurface and some other volume visualization tools, but there remains quite a few surprises for me from the plots.
The code has been written to conform to the image coordinate system (eg. see: vertexCoords) which is a left-handed coordinate system I presume. Nonetheless, the image is displayed in the Cartesian (right-handed) coordinate system. I have tried to see this displayed as the figure below, but that’s simply not happening.
I am wondering if the visualization functions have been written to display the image the way they do.
Image coordinate system:
Going forward, there are other aspects of the code I am to write for example if I have an input image sphereVoxels as in above, in addition to visualizing it, I would want to find north, south east, west, top and bottom locations in the image, as well as number and count the coordinates of the vertices, plus more.
I foresee this would likely become confusing for me if I don’t stick to one coordinate system, and considering that the visualization tools predominantly use the right-hand coordinate system, I would want to stick with that from the onset. However, I really do not know how to go about this.
Right-hand coordinate system:
Any suggestions to get through this?
When you call meshgrid, the dimensions x and y axes are switched (contrary to ndgrid). For example, in your case, it means that rowsInImage is a [120x100x200] = [x,y,z] array and not a [100x120x200] = [y,x,z] array even if meshgrid was called with arguments in the y,x,z order. I would change those two lines to be in the classical x,y,z order :
[columnsInImage, rowsInImage, pagesInImage] = meshgrid(1:imageSizeX, 1:imageSizeY, 1:imageSizeZ);
vertexCoords = [columnsInImage(:), rowsInImage(:), pagesInImage(:)];

How to have 100% zoom factor withChaco

As an example, in chaco/examples/demo/basic/image_inspector.py, how to set the zoom factor such that 1 array point corresponds to 1 screen pixel (100% zoom). It seems that the ZoomTool methods (zoom_in, zoom_out, ...) only deal with zoom factor changes, not with absolute factor setting.
I would try something with plot.range2d.low, plot.range2d.high and plot.outer_bounds. The first two relate to data space, while the latter relates to the size of the picture area. By setting the limits of the data space using the picture area, you can map 1 pixel to 1 data unit. Here's an example, the interesting bit is in the _zoom_100_percent method:
import numpy as np
from chaco.api import Plot, ArrayPlotData
from chaco.tools.api import PanTool, ZoomTool
from enable.api import ComponentEditor
from traits.api import Button, HasTraits, Instance, on_trait_change
from traitsui.api import Item, View
class HundredPercentZoom(HasTraits):
plot = Instance(Plot)
zoom_button = Button('100% Zoom')
traits_view = View(
Item('plot', editor=ComponentEditor(), show_label=False),
'zoom_button',
width=800,
height=600,
)
def _plot_default(self):
t = np.linspace(0, 1000, 200)
y = 400 * (np.sin(t) + 0.1 * np.sin(t * 100))
plot = Plot(ArrayPlotData(t=t, y=y))
plot.plot(('t', 'y'))
plot.tools.append(PanTool(plot))
plot.tools.append(ZoomTool(plot))
return plot
#on_trait_change('zoom_button')
def _zoom_100_percent(self):
low = self.plot.range2d.low
bounds = self.plot.outer_bounds
print(bounds)
self.plot.range2d.high = (low[0] + bounds[0], low[1] + bounds[1])
if __name__ == "__main__":
hpz = HundredPercentZoom()
hpz.configure_traits()
I added a print statement in there so you can see that the plot area is different than the window area, which is 800x600. I also added a PanTool and ZoomTool, so you can pan around once zoomed in. You can go back to the orignal zoom state using the Escape key, as long as your plot has a ZoomTool.
The solution I have arrived to, starting from the original example image_inspector.py . A button allows to have a 100 % zoom factor around a point chosen as the zoom center.
All is in the _btn_fired method in class Demo.
There may still be a problem of 1 not being subtracted or added to some bounds or limits, as the button operation is not strictly involutive (a second press should not do anything) as it should.
Anything simpler?
#!/usr/bin/env python
"""
Demonstrates the ImageInspectorTool and overlay on a colormapped image
plot. The underlying plot is similar to the one in cmap_image_plot.py.
- Left-drag pans the plot.
- Mousewheel up and down zooms the plot in and out.
- Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular
region to zoom. If you use a sequence of zoom boxes, pressing alt-left-arrow
and alt-right-arrow moves you forwards and backwards through the "zoom
history".
- Pressing "p" will toggle the display of the image inspector overlay.
"""
# Major library imports
from numpy import linspace, meshgrid, pi, sin, divide, multiply
# Enthought library imports
from enable.api import Component, ComponentEditor
from traits.api import HasTraits, Instance, Button, Float
from traitsui.api import Item, Group, View, HGroup
# Chaco imports
from chaco.api import ArrayPlotData, jet, Plot
from chaco.tools.api import PanTool, ZoomTool
from chaco.tools.image_inspector_tool import ImageInspectorTool, \
ImageInspectorOverlay
#===============================================================================
# # Create the Chaco plot.
#===============================================================================
def _create_plot_component():# Create a scalar field to colormap
xbounds = (-2*pi, 2*pi, 600)
ybounds = (-1.5*pi, 1.5*pi, 300)
xs = linspace(*xbounds)
ys = linspace(*ybounds)
x, y = meshgrid(xs,ys)
z = sin(x)*y
# Create a plot data obect and give it this data
pd = ArrayPlotData()
pd.set_data("imagedata", z)
# Create the plot
plot = Plot(pd)
img_plot = plot.img_plot("imagedata",
xbounds = xbounds[:2],
ybounds = ybounds[:2],
colormap=jet)[0]
# Tweak some of the plot properties
plot.title = "My First Image Plot"
plot.padding = 50
# Attach some tools to the plot
plot.tools.append(PanTool(plot))
zoom = ZoomTool(component=plot, tool_mode="box", always_on=False)
plot.overlays.append(zoom)
imgtool = ImageInspectorTool(img_plot)
img_plot.tools.append(imgtool)
overlay = ImageInspectorOverlay(component=img_plot, image_inspector=imgtool,
bgcolor="white", border_visible=True)
img_plot.overlays.append(overlay)
return plot
#===============================================================================
# Attributes to use for the plot view.
size = (800, 600)
title="Inspecting a Colormapped Image Plot"
#===============================================================================
# # Demo class that is used by the demo.py application.
#===============================================================================
class Demo(HasTraits):
plot = Instance(Component)
center_x = Float
center_y = Float
btn = Button('100 %')
def _btn_fired(self):
img_plot, = self.plot.plots['plot0']
zoom_center = (self.center_x, self.center_y)
# Size of plot in screen pixels
plot_size = img_plot.bounds
# Zoom center in screen space
zoom_center_screen, = img_plot.map_screen(zoom_center)
# Get actual bounds in data space
low, high = (img_plot.index_mapper.range.low,
img_plot.index_mapper.range.high)
# Get data space x and y units in terms of x and y array indices
sizes = [item.get_size() for item in img_plot.index.get_data()]
(min_x, min_y), (max_x, max_y) = img_plot.index.get_bounds()
unit = divide((max_x - min_x, max_y - min_y), sizes)
# Calculate new bounds
new_low = zoom_center - multiply(zoom_center_screen, unit)
new_high = new_low + multiply(plot_size, unit)
# Set new bounds
img_plot.index_mapper.range.set_bounds(new_low,new_high)
traits_view = View(
Group(
Item('plot', editor=ComponentEditor(size=size),
show_label=False),
HGroup('center_x', 'center_y', 'btn'),
orientation = "vertical"
),
resizable=True, title=title
)
def _plot_default(self):
return _create_plot_component()
demo = Demo()
if __name__ == "__main__":
demo.configure_traits()

least squares fitting to a 3 dimensional data set

I am working on video stabilisation ( making shaky videos non-shaky) using matlab.
One of the steps is to find a smooth camera path given the unstable camera path.
The unstable camera path is one which gives the jittering or shake to the video.
I have camera path specified using camera position which is a 3d-data.
camera path - (cx,cy,cz);
As i plot in matlab, i can visually see the shakiness of the camera motion.
So now i require a least squares fitting to be done on the camera path specified by(cx,cy,cz);
I came across polyfit() which does fitting for 2-dimensional data.
But what i need is a 3-d smooth curve fit to the shaky curve.
Thanks in advance.
Couldn't you just fit three separate 1d curves for cx(t), cy(t), cz(t)?
BTW: I think what you need is a Kalman filter, not a polynomial fit to the camera path. But I'm not sure if matlab has builtin support for that.
Approach using least square fit:
t = (1:0.1:5)';
% model
px = [ 5 2 1 ];
x = polyval(px,t);
py = [ -2 1 1 ];
y = polyval(py,t);
pz = [ 1 20 1 ];
z = polyval(pz,t);
% plot model
figure
plot3(x,y,z)
hold all
% simulate measurement
xMeasured = x+2*(rand(length(x),1)-0.5);
yMeasured = y+2*(rand(length(y),1)-0.5);
zMeasured = z+2*(rand(length(z),1)-0.5);
% plot simulated measurements
plot3(xMeasured, yMeasured, zMeasured,'or')
hold off
grid on
% least squares fit
A = [t.^2, t, t./t];
pxEstimated = A\xMeasured;
pyEstimated = A\yMeasured;
pzEstimated = A\zMeasured;
Let me be grateful to stackoverflow.com first of all and then my thanks to zellus and nikie who had started me thinking about the problem more. So now I have reached the solution which follows zellus approach and as nikie pointed out I used parameter 't' .
cx, cy,cz are the coordinates in 3d space and in my case they are all 343x1 doubles
My final code is shown below which fits the 3d data set:
t = linspace(1,343,343)';
load cx.mat;
load cy.mat;
load cz.mat;
plot3(cx, cy, cz,'r'),title('source Camera Path');
hold all
A = [t.^2, t, t./t];
fx = A\cx;
fy = A\cy;
fz = A\cz;
Xev = polyval(fx,t);
Yev = polyval(fy,t);
Zev = polyval(fz,t);
plot3(Xev,Yev,Zev,'+b'),title('Fitting Line');
I look forward to more interesting discussions on StackOverflow with great helpful people.