from NSFopen.read import read
import numpy as np
import collections
import cv2 as cv # aka opencv-python
from PIL import Image
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
font = {'size': 12}
matplotlib.rc('font', **font)
def fittingFunc(matrix, xaxis, order):
newmatrix = np.zeros(np.shape(matrix))
for i in range(len(matrix)):
p = np.polyfit(xaxis, matrix[i,:], order)
f = np.poly1d(p)
fit_array = f(xaxis)
newmatrix[i, :] = matrix[i, :] - fit_array
return newmatrix
def unsharp_mask(image, kernel_size=5, sigma=1.0, amount=1.0, threshold=0):
if kernel_size%2 != 1:
kernel_size += 1
blurred = cv.GaussianBlur(image, (kernel_size, kernel_size), sigma)
sharpened = float(amount + 1) * image - float(amount) * blurred
sharpened = np.maximum(sharpened, np.zeros(sharpened.shape))
sharpened = np.minimum(sharpened, 255 * np.ones(sharpened.shape))
sharpened = sharpened.round().astype(np.uint8)
if threshold > 0:
low_contrast_mask = np.absolute(image - blurred) < threshold
np.copyto(sharpened, image, where=low_contrast_mask)
return sharpened
def laplacian_sharp(image, ddepth = cv.CV_16S, kernel_size=3, amount = 0.5):
edges = cv.Laplacian(image, ddepth, ksize=kernel_size)
sharpened = (1-amount)*image - amount*edges
armax = np.max(sharpened)
armin = np.min(sharpened)
sharpened = (sharpened - armin)/(armax-armin)*255
return sharpened
filename = 'grid.nid'
signals = ['Topography','Z-Axis','Z-Axis Sensor'] # 'Amplitude', there could be more, i.e. 2nd lock-in signal, etc.
scan_direction = 'Forward' # 'Forward', 'Backward', '2nd Forward', '2nd Backward'
scan_to_plot = 'Image' # 'Image', 'Spec' or 'Sweep'
fitting_order = 1 # order of the fitting polynom
fitting = True # Use line fit or not
afm = read(filename, verbose = False)
data = afm.data
available_channels = list(data[scan_to_plot][scan_direction].index)
signal_to_plot = [i for i in available_channels if i in signals][0]
rawdata = data[scan_to_plot][scan_direction][signal_to_plot]*1e9 # nm
param = afm.param
xrange = param['X']['range'][0]
yrange = param['Y']['range'][0]
dict_key = filename.split(".nid")[0]
xaxis = np.linspace(0, xrange*1e6, len(rawdata[0]))
yaxis = np.linspace(0, yrange*1e6, len(rawdata))
if fitting:
data = fittingFunc(rawdata, xaxis, fitting_order)
else:
data = rawdata
force_limits = True # in case of glitches and spikes in the plots, make it False in the beginning
xlbl = 'X [$\mu$m]'
ylbl = 'Y [$\mu$um]'
fig, axarr = plt.subplots(1, 1, figsize=(7.5,7), dpi=300)
vmin = -40
vmax = 40
cmap = 'afmhot'
im = axarr.pcolormesh(xaxis, yaxis, data, cmap = cmap, shading='auto')
if force_limits:
im.set_clim(vmin = vmin, vmax = vmax)
axarr.set_title(filename.split(".nid")[0])
axarr.set(xlabel=xlbl, ylabel=ylbl)
ax_divider = make_axes_locatable(axarr)
cax = ax_divider.append_axes("right", size="5%", pad="2%")
p = plt.colorbar(im, cax=cax)
p.ax.set_ylabel("Z (nm)")
plt.show()
for i in range(len(data)):
for j in range(len(data[0])):
if data[i,j] < vmin:
data[i,j] = vmin
if data[i,j] > vmax:
data[i,j] = vmax
spread = 1/(vmax - vmin)
imdata = (data-vmin)*spread*255
imdata_new = np.uint8(imdata)
img = Image.fromarray(imdata_new, 'L')
img.save('img.jpg')
img = cv.imread('img.jpg', cv.IMREAD_GRAYSCALE) # Save and read img file, because cv2.imdecode is producing an error
img_sharp_g = unsharp_mask(img, kernel_size=7, sigma=1.0, amount=25.0, threshold=0.5)
img_sharp_l = laplacian_sharp(img, ddepth = cv.CV_16S, kernel_size=3, amount = 0.6)
img_sharp_g = img_sharp_g/spread/255 + vmin # Bring back to the physical range
img_sharp_l = img_sharp_l/spread/255 + vmin # Bring back to the physical range
im_im = collections.OrderedDict()
axnum = 0
fig, axarr = plt.subplots(1, 3, figsize=(14,5), dpi=300)
fig.tight_layout(pad=5.0)
for ax in axarr:
index = str(axnum)
if axnum == 0:
im_im[str(axnum)] = ax.pcolormesh(xaxis, yaxis, data, cmap = cmap, shading = 'auto')
ax.set_title(filename.split(".nid")[0])
ax.set(xlabel=xlbl, ylabel=ylbl)
im_im[str(axnum)].set_clim(vmin = vmin, vmax = vmax)
elif axnum == 1:
im_im[str(axnum)] = ax.pcolormesh(xaxis, yaxis, img_sharp_g, cmap = cmap, shading = 'auto')
ax.set_title(filename.split(".nid")[0] + " unsharp")
ax.set(xlabel=xlbl, ylabel='')
im_im[str(axnum)].set_clim(vmin = vmin, vmax = vmax)
else:
im_im[str(axnum)] = ax.pcolormesh(xaxis, yaxis, img_sharp_l, cmap = cmap, shading = 'auto')
ax.set_title(filename.split(".nid")[0] + " laplacian")
ax.set(xlabel=xlbl, ylabel='')
im_im[str(axnum)].set_clim(vmin = vmin/3, vmax = vmax/3)
ax_divider = make_axes_locatable(ax)
cax = ax_divider.append_axes("right", size="5%", pad="2%")
p = plt.colorbar(im_im[str(axnum)], cax=cax)
if axnum == 2:
p.ax.set_ylabel("Z (nm)")
axnum += 1
plt.show()