1
# -*- coding: utf-8 -*-
3
Created on Thu Mar 5 01:50:10 2020
5
@author: Georg Ganzenmueller, Fraunhofer Ernst-Mach Institut, EMI
7
This code is performs true strain analysis for cylindric specimens based on the
8
evaluation of shadow images.
9
The evolution of the minimal diameter is tracked. Triaxiality of stress is
10
evaluated using Bridgman's correction [1].
11
The algorithm works by determining the silhouette of the specimen gauge region
12
using Canny-edge detection. The minimum distance between the edges constitutes
13
the current cylindrical diameter. In the vicinity of the minimum location,
14
the local edge curvature is calculated, which is then used by the Bridgman
15
correctiion, providing a measure of stress triaxiality.
17
This file is the user interface. The actual silhouette detection is performed
18
in the class SilhouetteDiameter.
20
The user needs to provide a path to a folder containing the images to be analysed,
21
along with their file type suffix. The images need to be labeled with increasing numbers.
22
The specimen diameter should be resolved with at least 100 pixels in order to obtain accurate results
23
with strain errors < 1%.
25
Two parameters significantly affect the accuracy of the strain computation, and especially the accuracy
26
of the stress triaxiality factor: The amount of smoothing (nsmooth) applied to the specimen silhouette
27
detected by the Canny-edge filter, and the order of its spline representation. Good values
28
for nsmooth are 100 -- 1000, and order = 1 to 3.
32
[1] P. W. Bridgman, Studies in Large Plastic Flow and Fracture, McGraw-Hill, New York, (1952).
35
import configparser, triaxiality
37
cfg = configparser.ConfigParser()
38
cfg.read("constrain.ini")
39
suffix = cfg.get("DEFAULT", "suffix")
40
nMax = cfg.getint("DEFAULT", "nMax")
41
transpose = cfg.getboolean("DEFAULT", "transpose") # rotate image? Specimen must be vertical in image
42
notched_specimen = cfg.getboolean("DEFAULT", "notched_specimen")
43
nueps = cfg.getfloat("DEFAULT", "nueps")
45
###############################################################################
46
# *********** Only edit lines above *************
47
###############################################################################
50
import matplotlib.pyplot as plt
52
from Silhouette import Silhouette
56
for file in glob.glob(suffix):
57
filenames.append(file)
59
from natsort import natsorted
60
filenames = natsorted(filenames)
63
return filenames[:nMax]
67
filenames = read_images()
70
diameters = np.zeros(N)
71
notch_radii = np.zeros(N)
72
valid_flag = np.zeros(N, dtype=bool)
74
for i in range(0,len(filenames)):
75
print("\n-------------- file: %s --------------" %(filenames[i]))
76
sil = Silhouette(filenames[i], plot=False, transpose=transpose)
78
if sil.status == True:
80
diameters[i] = sil.diameter
81
if sil.curvature_valid:
83
notch_radii[i] = sil.notch_radius
84
print("current diameter in pixels is: ", sil.diameter, " notch radius is; ", sil.notch_radius, "sigma is", sil.notch_sigma)
85
notch_radii[i] = max(notch_radii[i], 0.25*diameters[i]) # limit severe triaxiality to 1.3
88
print("something went wrong in the analysis, exiting prematurely")
91
eps_eq = (1./nueps) * np.log(diameters[0]/diameters) # equivalent true strain
93
savedata = np.column_stack((np.arange(len(diameters)), eps_eq, diameters, notch_radii))
94
np.savetxt("strain.txt",savedata, header="index, eps_eq, diameter, notch_radius")
97
plt.style.use('dark_background')
98
fig, axs = plt.subplots(2,2)
100
# --- TOP LEFT plot: strain vs. frame number ---
103
ax.set_xlabel('frame No.')
104
ax.set_ylabel('equivalent true strain')
105
ax.plot(eps_eq, color=color, label="strain")
107
# --- BOTTOM LEFT plt: diamater vs frame number ---
109
ax.set_xlabel('frame No.')
110
ax.set_ylabel('diameter [px]')
111
ax.plot(diameters, "rx", label="diameter")
113
# --- TOP RIGHT plot: stress triaxiality vs strain ---
115
ax.set_xlabel('eq. true strain')
116
ax.set_ylabel('stress triaxiality [-]')
117
ax.plot(eps_eq,triaxiality.triax_function(diameters, notch_radii), "bo", label="stress triax.")
120
# --- BOTTOM RIGHT plot: Bridgman factor vs strain ---
122
ax.set_xlabel('eq. true strain')
123
ax.set_ylabel('Bridgman factor [-]')
124
ax.plot(eps_eq, triaxiality.bridgman_function(diameters, notch_radii), "go", label="Bridgman factor")
127
fig.tight_layout() # otherwise the right y-label is slightly clipped
132
# if len(filenames) > 2:
133
# def powerlaw(x, a, n, offset):
134
# return a * (np.abs(x)**n) + offset
135
# def powerlaw_unnotched(x, a, n):
136
# return a * (np.abs(x)**n)
138
# # need a data subset which contains only strain and ratios if valid_flag is set to true
139
# eps_eq_sub = np.compress(valid_flag, eps_eq)
140
# ratios_sub = np.compress(valid_flag, ratios)
141
# #print("length of original array: ", len(eps_eq))
142
# #print("length of subset array: ", len(eps_eq_sub))
145
# if notched_specimen:
148
# popt, pcov = curve_fit(powerlaw, eps_eq_sub, ratios_sub, p0=p0)
149
# ratio_fit = powerlaw(eps_eq, *popt)
156
# popt, pcov = curve_fit(powerlaw_unnotched, eps_eq_sub, ratios_sub, p0=p0)
157
# ratio_fit = powerlaw_unnotched(eps_eq, *popt)
161
# # now replace invalid ratios with fit
163
# #print("original ratios", ratios)
164
# ratios = np.where(valid_flag, ratios, ratio_fit)
165
# #print("repaired ratios", ratios)
168
# bridgman_fit = bridgman_function(ratio_fit)
169
# triax_fit = triax_function(ratio_fit)
171
# # compute Bridgman factor and stress triaxiality
172
# bridgmans = bridgman_function(ratios)
173
# triaxs = triax_function(ratios)
176
# bridgman_fit = bridgmans = bridgman_function(ratios)
177
# triax_fit = triaxs = triax_function(ratios)