eitcom / pyEIT

Python based toolkit for Electrical Impedance Tomography
Other
169 stars 96 forks source link

Reconstructed images exhibit an undesired shift. #99

Closed TooNakko closed 3 months ago

TooNakko commented 3 months ago

Hi!

I am interested in pyEIT, and my team is currently working on reconstructing images. We have successfully built our hardware and achieved good results in image reconstruction. However, we are currently facing an issue. When we place the object near the electrodes, the reconstructed image looks good. However, when we position our object right in the middle of the tank, the reconstructed image appears to be shifted: image

It consistently shifts to the right like this, regardless of the number of attempts we make. We have also compared the results of pyEIT with EIDORS (Matlab), and the image from EIDORS is completely centered. There should not be an issue with our hardware: image

Regarding the code we ran, we modified the eit_dynamic_JAC.py in the examples folder, we assign our voltage matrices to v0 and v1:

v0 = np.loadtxt('example_data/ref_data.txt')
v1 = np.loadtxt('example_data/diff_middle_data.txt')

and also performed some tunning. Our txt files contain a single line of 208 values, representing the voltage measured from those electrodes.

Code:

# coding: utf-8
""" demo on dynamic eit using JAC method """
# Copyright (c) Benyuan Liu. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
from __future__ import absolute_import, division, print_function

import time
import matplotlib.pyplot as plt
import numpy as np
import pyeit.eit.jac as jac
import pyeit.mesh as mesh
from pyeit.eit.fem import EITForward
from pyeit.eit.interp2d import sim2pts
from pyeit.mesh.shape import thorax
import pyeit.eit.protocol as protocol
from pyeit.mesh.wrapper import PyEITAnomaly_Circle

""" 0. build mesh """
n_el = 16  # nb of electrodes
use_customize_shape = False
if use_customize_shape:
    # Mesh shape is specified with fd parameter in the instantiation, e.g : fd=thorax
    mesh_obj = mesh.create(n_el, h0=0.065, fd=thorax)
else:
    mesh_obj = mesh.create(n_el, h0=0.065)

# extract node, element, alpha
pts = mesh_obj.node
tri = mesh_obj.element
x, y = pts[:, 0], pts[:, 1]

""" 1. problem setup """
# mesh_obj["alpha"] = np.random.rand(tri.shape[0]) * 200 + 100 # NOT USED
anomaly = PyEITAnomaly_Circle(center=[0.5, 0.5], r=0.1, perm=1000.0)
mesh_new = mesh.set_perm(mesh_obj, anomaly=anomaly)

""" 2. FEM simulation """
# setup EIT scan conditions
protocol_obj = protocol.create(n_el, dist_exc=1, step_meas=1, parser_meas="std")

# calculate simulated data
fwd = EITForward(mesh_obj, protocol_obj)

v0 = np.loadtxt('example_data/ref_data.txt')
v1 = np.loadtxt('example_data/diff_middle_data.txt')

#v0 = fwd.solve_eit()
#v1 = fwd.solve_eit(perm=mesh_new.perm)

""" 3. JAC solver """
# Note: if the jac and the real-problem are generated using the same mesh,
# then, data normalization in solve are not needed.
# However, when you generate jac from a known mesh, but in real-problem
# (mostly) the shape and the electrode positions are not exactly the same
# as in mesh generating the jac, then data must be normalized.
eit = jac.JAC(mesh_obj, protocol_obj)
eit.setup(p=0.5, lamb=0.8, method="kotre", perm=1000, jac_normalized=True)
ds = eit.solve(v1, v0, normalize=True)
ds_n = sim2pts(pts, tri, np.real(ds))
print('ds=\n', ds_n)
# plot ground truth
fig, ax = plt.subplots(constrained_layout=True)

# plot EIT reconstruction
im = ax.tripcolor(x, y, tri, ds_n, shading="flat", cmap=plt.cm.magma)
for i, e in enumerate(mesh_obj.el_pos):
    ax.annotate(str(i + 1), xy=(x[e], y[e]), color="r")
ax.set_aspect("equal")

fig.colorbar(im, ax=ax)

# plt.savefig('../doc/images/demo_jac.png', dpi=96)
plt.show()

Sample data:

In one-line form:
Reference:   2.25 1.18 0.79 0.69 0.53 0.43 0.49 0.52 0.50 0.67 0.85 1.15 2.12 4.80 1.36 0.95 0.66 0.51 0.51 0.55 0.47 0.59 0.65 0.67 1.17 1.12 2.59 1.38 0.89 0.66 0.66 0.59 0.50 0.51 0.58 0.59 0.86 1.38 2.10 5.02 1.60 0.99 0.79 0.69 0.46 0.50 0.47 0.47 0.59 0.84 1.12 0.96 1.55 0.99 0.70 0.63 0.46 0.39 0.38 0.31 0.39 0.50 0.62 1.11 1.96 4.51 1.50 0.95 0.61 0.62 0.48 0.45 0.47 0.57 0.65 0.75 1.57 2.08 4.77 1.57 0.95 0.61 0.55 0.36 0.39 0.43 0.45 0.62 0.87 1.33 1.11 2.12 1.13 0.86 0.54 0.44 0.41 0.43 0.45 0.48 0.70 0.84 1.07 2.12 4.70 1.53 0.96 0.59 0.56 0.50 0.50 0.50 0.59 0.72 0.56 1.35 1.34 0.31 1.66 1.03 0.69 0.68 0.57 0.53 0.63 0.60 0.60 1.00 1.41 2.03 4.65 1.32 0.86 0.65 0.55 0.49 0.47 0.43 0.40 0.62 0.62 0.94 1.37 0.61 1.45 1.07 0.74 0.59 0.57 0.47 0.41 0.52 0.63 0.75 1.31 1.13 1.94 1.26 0.89 0.71 0.60 0.46 0.40 0.47 0.49 0.57 0.86 1.43 2.04 4.76 1.45 0.95 0.68 0.48 0.35 0.39 0.41 0.39 0.55 0.88 1.17 1.68 4.08 1.25 0.96 0.63 0.44 0.49 0.41 0.47 0.53 0.68 0.84 1.37 2.10 5.00 1.62 0.95 0.50 0.56 0.43 0.42 0.48 0.62 0.65 0.85 1.27 0.94
Difference:  1.52 0.95 0.70 0.85 0.76 0.68 0.77 0.78 0.66 0.69 0.72 0.91 1.78 4.19 1.14 0.99 0.82 0.76 0.83 0.88 0.69 0.73 0.69 0.59 1.03 0.82 1.90 1.20 0.82 0.84 0.97 0.96 0.80 0.75 0.70 0.66 0.77 1.08 1.76 4.63 1.40 0.99 0.98 1.00 0.78 0.78 0.71 0.64 0.69 0.71 0.98 0.59 0.71 0.92 0.72 0.78 0.66 0.64 0.58 0.51 0.58 0.59 0.65 0.98 1.71 4.13 1.46 1.35 1.15 0.81 0.78 0.72 0.73 0.82 0.80 0.50 1.48 1.22 2.12 1.34 0.94 0.80 0.71 0.58 0.66 0.66 0.70 0.88 0.97 1.05 0.73 1.61 0.98 0.93 1.10 0.60 0.63 0.68 0.68 0.78 0.87 0.91 0.91 1.94 4.06 1.24 0.88 0.67 0.70 0.75 0.77 0.83 0.77 0.87 0.67 1.52 1.56 0.96 1.96 0.96 0.75 0.79 0.81 0.86 0.97 0.94 0.81 1.11 1.23 1.76 4.13 1.21 0.76 0.63 0.66 0.69 0.74 0.70 0.60 0.78 0.47 1.15 1.73 3.29 1.25 0.89 0.77 0.70 0.82 0.79 0.66 0.82 0.81 0.77 1.16 0.86 1.40 1.16 0.84 0.68 0.75 0.74 0.60 0.75 0.66 0.66 0.62 1.08 1.81 4.12 1.27 0.78 0.73 0.63 0.52 0.66 0.63 0.57 0.66 0.84 0.90 0.73 1.50 1.03 0.76 0.73 0.59 0.76 0.66 0.67 0.72 0.79 0.76 1.15 1.86 4.53 1.37 0.87 0.59 0.78 0.70 0.71 0.75 0.81 0.70 0.63 0.99 0.74

In matrix form:
Reference:
2.25 1.18 0.79 0.69 0.53 0.43 0.49 0.52 0.50 0.67 0.85 1.15 2.12  
4.80 1.36 0.95 0.66 0.51 0.51 0.55 0.47 0.59 0.65 0.67 1.17 1.12  
2.59 1.38 0.89 0.66 0.66 0.59 0.50 0.51 0.58 0.59 0.86 1.38 2.10  
5.02 1.60 0.99 0.79 0.69 0.46 0.50 0.47 0.47 0.59 0.84 1.12 0.96  
1.55 0.99 0.70 0.63 0.46 0.39 0.38 0.31 0.39 0.50 0.62 1.11 1.96  
4.51 1.50 0.95 0.61 0.62 0.48 0.45 0.47 0.57 0.65 0.75 1.57 2.08  
4.77 1.57 0.95 0.61 0.55 0.36 0.39 0.43 0.45 0.62 0.87 1.33 1.11  
2.12 1.13 0.86 0.54 0.44 0.41 0.43 0.45 0.48 0.70 0.84 1.07 2.12  
4.70 1.53 0.96 0.59 0.56 0.50 0.50 0.50 0.59 0.72 0.56 1.35 1.34  
0.31 1.66 1.03 0.69 0.68 0.57 0.53 0.63 0.60 0.60 1.00 1.41 2.03  
4.65 1.32 0.86 0.65 0.55 0.49 0.47 0.43 0.40 0.62 0.62 0.94 1.37  
0.61 1.45 1.07 0.74 0.59 0.57 0.47 0.41 0.52 0.63 0.75 1.31 1.13  
1.94 1.26 0.89 0.71 0.60 0.46 0.40 0.47 0.49 0.57 0.86 1.43 2.04  
4.76 1.45 0.95 0.68 0.48 0.35 0.39 0.41 0.39 0.55 0.88 1.17 1.68  
4.08 1.25 0.96 0.63 0.44 0.49 0.41 0.47 0.53 0.68 0.84 1.37 2.10  
5.00 1.62 0.95 0.50 0.56 0.43 0.42 0.48 0.62 0.65 0.85 1.27 0.94

Difference:
1.52 0.95 0.70 0.85 0.76 0.68 0.77 0.78 0.66 0.69 0.72 0.91 1.78  
4.19 1.14 0.99 0.82 0.76 0.83 0.88 0.69 0.73 0.69 0.59 1.03 0.82  
1.90 1.20 0.82 0.84 0.97 0.96 0.80 0.75 0.70 0.66 0.77 1.08 1.76  
4.63 1.40 0.99 0.98 1.00 0.78 0.78 0.71 0.64 0.69 0.71 0.98 0.59  
0.71 0.92 0.72 0.78 0.66 0.64 0.58 0.51 0.58 0.59 0.65 0.98 1.71  
4.13 1.46 1.35 1.15 0.81 0.78 0.72 0.73 0.82 0.80 0.50 1.48 1.22  
2.12 1.34 0.94 0.80 0.71 0.58 0.66 0.66 0.70 0.88 0.97 1.05 0.73  
1.61 0.98 0.93 1.10 0.60 0.63 0.68 0.68 0.78 0.87 0.91 0.91 1.94  
4.06 1.24 0.88 0.67 0.70 0.75 0.77 0.83 0.77 0.87 0.67 1.52 1.56  
0.96 1.96 0.96 0.75 0.79 0.81 0.86 0.97 0.94 0.81 1.11 1.23 1.76  
4.13 1.21 0.76 0.63 0.66 0.69 0.74 0.70 0.60 0.78 0.47 1.15 1.73  
3.29 1.25 0.89 0.77 0.70 0.82 0.79 0.66 0.82 0.81 0.77 1.16 0.86  
1.40 1.16 0.84 0.68 0.75 0.74 0.60 0.75 0.66 0.66 0.62 1.08 1.81  
4.12 1.27 0.78 0.73 0.63 0.52 0.66 0.63 0.57 0.66 0.84 0.90 0.73  
1.50 1.03 0.76 0.73 0.59 0.76 0.66 0.67 0.72 0.79 0.76 1.15 1.86  
4.53 1.37 0.87 0.59 0.78 0.70 0.71 0.75 0.81 0.70 0.63 0.99 0.74

Would you mind to take a look and enlighten me on what might be wrong here? Thank you so much!

liubenyuan commented 3 months ago

Hi, I reproduce figure 1 with your data.

If you plot your v0 or v1, you will find that the measurement protocol is "rotate measurement", in pyEIT or EIDORS, this means that during each excitation, the first measurement is the differential pair right after the excitation pair. So, in line 39, you should use

# setup EIT scan conditions
protocol_obj = protocol.create(n_el, dist_exc=1, step_meas=1, parser_meas="fmmu")  # change "std" to "rotate_meas" or "fmmu"

and the imaging parameters should be tuned accordingly for minimizing image artifacts (it seems that the bottom two electrodes might have contact problem).

TooNakko commented 3 months ago

Thank you so much, it fixed the problem!