├── LICENSE
├── README.md
├── figs
├── flowchart.png
├── head_example.png
└── hip_example.png
├── outputs
├── input.png
├── output.png
└── simulation_config.json
├── sample_data
├── sample_1.mat
└── sample_2.mat
├── simulation_demo.m
├── src
├── create_phantom.m
├── hu2mu.m
├── metal_artifact_simulation.m
├── mu2hu.m
├── phantom_proj_mono.m
├── phantom_proj_poly.m
├── set_config_for_artifact_simulation.m
├── threshold_based_weighting.m
├── water_correction.m
├── xray_characteristic_data.csv
└── xray_characteristic_data.mat
└── utils
├── save_config_as_json.m
└── set_window.m
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 s-mitsuki
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Metal Artifact Simulation
2 | A MATLAB implementation of metal artifact simulation based on [1].
3 | We also introduced a water-based beam hardening correction [2] to generate an image similar to that generated by common CT systems, where a built-in calibration linearizes the polychromatic x-ray projection.
4 |
5 | If you use this code, please consider citing:
6 |
7 | Sakamoto, M., Hiasa, Y., Otake, Y., Takao, M., Suzuki, Y., Sugano, N., & Sato, Y. (2019, March). Automated segmentation of hip and thigh muscles in metal artifact contaminated CT using CNN. In International Forum on Medical Imaging in Asia 2019 (Vol. 11050, p. 110500S). International Society for Optics and Photonics.
8 |
9 |
10 |
11 | ## Authors
12 |
13 | Mitsuki Sakamoto
14 | Yoshito Otake
15 |
16 | ## Requirements
17 | [MATLAB (Image Processing Toolbox required).](https://jp.mathworks.com/products/matlab.html)
18 |
19 | We tested our code using MATLAB 2015a, 2018a and 2019a.
20 |
21 | ## Test using sample data
22 | You can test metal artifact simulation by running "simulation_demo.m".
23 | We prepared 2 images and corresponding metal labels of different parts in the "sample data" directory.
24 | The input and output images will be saved in "outputs" directory.
25 |
26 | ### Sample 1 (hip joint region)
27 | In "sample_1.mat", a CT image of the hip joint region and a corresponding metal label are stored.
28 | Below is the simulation result obtained by using the default settings.
29 | In addition to the preoperative (input) and the simulated (output) images, the postoperative CT image of the same patient is shown below.
30 |
31 |
32 |
33 | ### Sample 2 (head)
34 | In "sample_2.mat", a CT image of the head with a corresponding metal label are stored.
35 | Below is the simulation result obtained using the default settings.
36 |
37 |
38 |
39 | ## License
40 | This project is licensed under the [MIT license](/LICENSE).
41 |
42 | ## Reference
43 | 1. Zhang, Y., & Yu, H. (2018). Convolutional neural network based metal artifact reduction in X-ray computed tomography. IEEE transactions on medical imaging, 37(6), 1370-1381.
44 |
45 | 2. Herman, G. T. (1979). Correction for beam hardening in computed tomography. Physics in Medicine & Biology, 24(1), 81.
46 |
--------------------------------------------------------------------------------
/figs/flowchart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NAIST-ICB/metal_artifact_simulation/ac816eee1a918ab7514b627fade762bf0b5a5165/figs/flowchart.png
--------------------------------------------------------------------------------
/figs/head_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NAIST-ICB/metal_artifact_simulation/ac816eee1a918ab7514b627fade762bf0b5a5165/figs/head_example.png
--------------------------------------------------------------------------------
/figs/hip_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NAIST-ICB/metal_artifact_simulation/ac816eee1a918ab7514b627fade762bf0b5a5165/figs/hip_example.png
--------------------------------------------------------------------------------
/outputs/input.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NAIST-ICB/metal_artifact_simulation/ac816eee1a918ab7514b627fade762bf0b5a5165/outputs/input.png
--------------------------------------------------------------------------------
/outputs/output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NAIST-ICB/metal_artifact_simulation/ac816eee1a918ab7514b627fade762bf0b5a5165/outputs/output.png
--------------------------------------------------------------------------------
/outputs/simulation_config.json:
--------------------------------------------------------------------------------
1 | {"data":[{"Energy":1,"Water":4077,"Bone":3781,"Titanium":5870,"Iron":9085,"Intensity":0},{"Energy":2,"Water":617.3,"Bone":586.9,"Titanium":986,"Iron":1627,"Intensity":0},{"Energy":3,"Water":192.8,"Bone":295.8,"Titanium":332,"Iron":557.6,"Intensity":0},{"Energy":4,"Water":82.77,"Bone":133.1,"Titanium":152,"Iron":256.7,"Intensity":0},{"Energy":5,"Water":42.59,"Bone":191.7,"Titanium":684,"Iron":139.9,"Intensity":0},{"Energy":6,"Water":24.64,"Bone":117.1,"Titanium":432,"Iron":84.84,"Intensity":0},{"Energy":7,"Water":15.5,"Bone":67.60988261,"Titanium":283,"Iron":55.56,"Intensity":0},{"Energy":8,"Water":10.4,"Bone":37.3,"Titanium":306,"Iron":305.6,"Intensity":0},{"Energy":9,"Water":7.29,"Bone":26.8,"Titanium":148,"Iron":225.7,"Intensity":49.73536278},{"Energy":10,"Water":5.33,"Bone":19.9,"Titanium":111,"Iron":170.7,"Intensity":238.5495208},{"Energy":11,"Water":4.03,"Bone":15.2,"Titanium":85,"Iron":132.3,"Intensity":862.8132977},{"Energy":12,"Water":3.13,"Bone":11.9,"Titanium":66.8,"Iron":104.7,"Intensity":2196.270332},{"Energy":13,"Water":2.49,"Bone":9.48,"Titanium":53.5,"Iron":84.33,"Intensity":4420.964307},{"Energy":14,"Water":2.02,"Bone":7.69,"Titanium":43.5,"Iron":68.94,"Intensity":10421.40312},{"Energy":15,"Water":1.67,"Bone":6.33,"Titanium":35.9,"Iron":57.09,"Intensity":18636.95161},{"Energy":16,"Water":1.41,"Bone":5.27,"Titanium":29.9,"Iron":47.79,"Intensity":37950.48968},{"Energy":17,"Water":1.2,"Bone":4.45,"Titanium":25.2,"Iron":40.41,"Intensity":61393.99747},{"Energy":18,"Water":1.04,"Bone":3.79,"Titanium":21.4,"Iron":34.47,"Intensity":79736.97466},{"Energy":19,"Water":0.913,"Bone":3.26,"Titanium":18.4,"Iron":29.65,"Intensity":100999.1641},{"Energy":20,"Water":0.81,"Bone":2.83,"Titanium":15.9,"Iron":25.68,"Intensity":123616.4965},{"Energy":21,"Water":0.725,"Bone":2.48,"Titanium":13.8,"Iron":22.4,"Intensity":148659.8902},{"Energy":22,"Water":0.656,"Bone":2.18,"Titanium":12.1,"Iron":19.65,"Intensity":176107.6524},{"Energy":23,"Water":0.598,"Bone":1.94,"Titanium":10.6,"Iron":17.34,"Intensity":205516.0089},{"Energy":24,"Water":0.549,"Bone":1.73,"Titanium":9.41,"Iron":15.38,"Intensity":230934.4377},{"Energy":25,"Water":0.508,"Bone":1.56,"Titanium":8.37,"Iron":13.7,"Intensity":255458.3578},{"Energy":26,"Water":0.473,"Bone":1.4,"Titanium":7.48,"Iron":12.26,"Intensity":275529.0111},{"Energy":27,"Water":0.443,"Bone":1.28,"Titanium":6.72,"Iron":11.02,"Intensity":295620.9604},{"Energy":28,"Water":0.418,"Bone":1.16,"Titanium":6.05,"Iron":9.942,"Intensity":312324.5385},{"Energy":29,"Water":0.395,"Bone":1.07,"Titanium":5.48,"Iron":9.001,"Intensity":329444.4456},{"Energy":30,"Water":0.376,"Bone":0.982,"Titanium":4.97,"Iron":8.176,"Intensity":340060.6186},{"Energy":31,"Water":0.358,"Bone":0.908,"Titanium":4.53,"Iron":7.451,"Intensity":350399.9242},{"Energy":32,"Water":0.343,"Bone":0.842,"Titanium":4.14,"Iron":6.81,"Intensity":357774.9053},{"Energy":33,"Water":0.33,"Bone":0.785,"Titanium":3.79,"Iron":6.242,"Intensity":365182.8133},{"Energy":34,"Water":0.318,"Bone":0.733,"Titanium":3.49,"Iron":5.737,"Intensity":368197.4839},{"Energy":35,"Water":0.308,"Bone":0.688,"Titanium":3.21,"Iron":5.285,"Intensity":370174.3253},{"Energy":36,"Water":0.298,"Bone":0.647,"Titanium":2.97,"Iron":4.881,"Intensity":370158.8536},{"Energy":37,"Water":0.289,"Bone":0.61,"Titanium":2.75,"Iron":4.518,"Intensity":369626.3968},{"Energy":38,"Water":0.282,"Bone":0.577,"Titanium":2.55,"Iron":4.192,"Intensity":368456.9322},{"Energy":39,"Water":0.275,"Bone":0.548,"Titanium":2.37,"Iron":3.896,"Intensity":367299.0802},{"Energy":40,"Water":0.268,"Bone":0.521,"Titanium":2.21,"Iron":3.629,"Intensity":363529.2904},{"Energy":41,"Water":0.263,"Bone":0.496,"Titanium":2.07,"Iron":3.387,"Intensity":359420.6743},{"Energy":42,"Water":0.257,"Bone":0.474,"Titanium":1.94,"Iron":3.166,"Intensity":354948.0588},{"Energy":43,"Water":0.252,"Bone":0.454,"Titanium":1.82,"Iron":2.965,"Intensity":350744.5569},{"Energy":44,"Water":0.248,"Bone":0.436,"Titanium":1.71,"Iron":2.782,"Intensity":344701.6915},{"Energy":45,"Water":0.244,"Bone":0.419,"Titanium":1.61,"Iron":2.614,"Intensity":337969.5247},{"Energy":46,"Water":0.24,"Bone":0.403,"Titanium":1.51,"Iron":2.46,"Intensity":333678.8909},{"Energy":47,"Water":0.236,"Bone":0.389,"Titanium":1.43,"Iron":2.318,"Intensity":329295.3548},{"Energy":48,"Water":0.233,"Bone":0.376,"Titanium":1.35,"Iron":2.188,"Intensity":320781.8885},{"Energy":49,"Water":0.23,"Bone":0.364,"Titanium":1.28,"Iron":2.068,"Intensity":312148.3633},{"Energy":50,"Water":0.227,"Bone":0.352,"Titanium":1.21,"Iron":1.957,"Intensity":305174.1673},{"Energy":51,"Water":0.224,"Bone":0.342,"Titanium":1.15,"Iron":1.855,"Intensity":298010.2179},{"Energy":52,"Water":0.222,"Bone":0.332,"Titanium":1.1,"Iron":1.76,"Intensity":290946.9606},{"Energy":53,"Water":0.219,"Bone":0.323,"Titanium":1.04,"Iron":1.672,"Intensity":283748.1728},{"Energy":54,"Water":0.217,"Bone":0.315,"Titanium":0.995,"Iron":1.591,"Intensity":278714.0505},{"Energy":55,"Water":0.215,"Bone":0.307,"Titanium":0.95,"Iron":1.515,"Intensity":273631.5296},{"Energy":56,"Water":0.213,"Bone":0.3,"Titanium":0.908,"Iron":1.444,"Intensity":369343.687},{"Energy":57,"Water":0.211,"Bone":0.293,"Titanium":0.869,"Iron":1.378,"Intensity":465565.0935},{"Energy":58,"Water":0.209,"Bone":0.287,"Titanium":0.832,"Iron":1.316,"Intensity":546765.4408},{"Energy":59,"Water":0.208,"Bone":0.281,"Titanium":0.798,"Iron":1.259,"Intensity":627747.0206},{"Energy":60,"Water":0.206,"Bone":0.275,"Titanium":0.766,"Iron":1.205,"Intensity":447779.1827},{"Energy":61,"Water":0.204,"Bone":0.27,"Titanium":0.736,"Iron":1.154,"Intensity":266566.3429},{"Energy":62,"Water":0.203,"Bone":0.265,"Titanium":0.708,"Iron":1.107,"Intensity":240859.4159},{"Energy":63,"Water":0.201,"Bone":0.26,"Titanium":0.682,"Iron":1.063,"Intensity":214937.5622},{"Energy":64,"Water":0.2,"Bone":0.256,"Titanium":0.657,"Iron":1.021,"Intensity":208670.0869},{"Energy":65,"Water":0.199,"Bone":0.252,"Titanium":0.634,"Iron":0.9816,"Intensity":201761.7268},{"Energy":66,"Water":0.197,"Bone":0.248,"Titanium":0.612,"Iron":0.9446,"Intensity":262349.2987},{"Energy":67,"Water":0.196,"Bone":0.244,"Titanium":0.591,"Iron":0.9097,"Intensity":323053.0165},{"Energy":68,"Water":0.195,"Bone":0.24,"Titanium":0.572,"Iron":0.8768,"Intensity":263911.8128},{"Energy":69,"Water":0.194,"Bone":0.237,"Titanium":0.554,"Iron":0.8457,"Intensity":203208.059},{"Energy":70,"Water":0.193,"Bone":0.234,"Titanium":0.536,"Iron":0.8164,"Intensity":172538.2732},{"Energy":71,"Water":0.192,"Bone":0.231,"Titanium":0.52,"Iron":0.7886,"Intensity":141902.938},{"Energy":72,"Water":0.191,"Bone":0.228,"Titanium":0.504,"Iron":0.7623,"Intensity":135249.5722},{"Energy":73,"Water":0.19,"Bone":0.225,"Titanium":0.489,"Iron":0.7374,"Intensity":128072.4682},{"Energy":74,"Water":0.189,"Bone":0.222,"Titanium":0.476,"Iron":0.7138,"Intensity":125819.8954},{"Energy":75,"Water":0.188,"Bone":0.22,"Titanium":0.462,"Iron":0.6915,"Intensity":123910.8011},{"Energy":76,"Water":0.187,"Bone":0.217,"Titanium":0.45,"Iron":0.6702,"Intensity":120084.8679},{"Energy":77,"Water":0.186,"Bone":0.215,"Titanium":0.438,"Iron":0.65,"Intensity":115706.5341},{"Energy":78,"Water":0.185,"Bone":0.213,"Titanium":0.426,"Iron":0.6308,"Intensity":112856.0653},{"Energy":79,"Water":0.185,"Bone":0.211,"Titanium":0.416,"Iron":0.6126,"Intensity":108417.7112},{"Energy":80,"Water":0.184,"Bone":0.209,"Titanium":0.405,"Iron":0.5952,"Intensity":105390.2737},{"Energy":81,"Water":0.183,"Bone":0.207,"Titanium":0.395,"Iron":0.5787,"Intensity":100520.3443},{"Energy":82,"Water":0.182,"Bone":0.205,"Titanium":0.386,"Iron":0.5629,"Intensity":99818.46531},{"Energy":83,"Water":0.181,"Bone":0.203,"Titanium":0.377,"Iron":0.5478,"Intensity":96275.41323},{"Energy":84,"Water":0.181,"Bone":0.201,"Titanium":0.369,"Iron":0.5335,"Intensity":92478.71927},{"Energy":85,"Water":0.18,"Bone":0.2,"Titanium":0.361,"Iron":0.5198,"Intensity":88651.63192},{"Energy":86,"Water":0.179,"Bone":0.198,"Titanium":0.353,"Iron":0.5067,"Intensity":86577.76786},{"Energy":87,"Water":0.179,"Bone":0.196,"Titanium":0.345,"Iron":0.4942,"Intensity":84557.14407},{"Energy":88,"Water":0.178,"Bone":0.195,"Titanium":0.338,"Iron":0.4822,"Intensity":80892.68974},{"Energy":89,"Water":0.177,"Bone":0.194,"Titanium":0.331,"Iron":0.4707,"Intensity":77195.90356},{"Energy":90,"Water":0.177,"Bone":0.192,"Titanium":0.325,"Iron":0.4597,"Intensity":74258.49674},{"Energy":91,"Water":0.176,"Bone":0.191,"Titanium":0.318,"Iron":0.4492,"Intensity":71242.6721},{"Energy":92,"Water":0.175,"Bone":0.189,"Titanium":0.312,"Iron":0.4391,"Intensity":68055.87902},{"Energy":93,"Water":0.175,"Bone":0.188,"Titanium":0.307,"Iron":0.4295,"Intensity":64602.08666},{"Energy":94,"Water":0.174,"Bone":0.187,"Titanium":0.301,"Iron":0.4202,"Intensity":61854.81207},{"Energy":95,"Water":0.174,"Bone":0.186,"Titanium":0.296,"Iron":0.4113,"Intensity":59123.60874},{"Energy":96,"Water":0.173,"Bone":0.185,"Titanium":0.291,"Iron":0.4028,"Intensity":56922.92375},{"Energy":97,"Water":0.172,"Bone":0.183,"Titanium":0.286,"Iron":0.3945,"Intensity":54747.21795},{"Energy":98,"Water":0.172,"Bone":0.182,"Titanium":0.281,"Iron":0.3866,"Intensity":52073.13183},{"Energy":99,"Water":0.171,"Bone":0.181,"Titanium":0.277,"Iron":0.3791,"Intensity":49397.68878},{"Energy":100,"Water":0.171,"Bone":0.18,"Titanium":0.272,"Iron":0.3717,"Intensity":47153.24848},{"Energy":101,"Water":0.17,"Bone":0.179,"Titanium":0.268,"Iron":0.3647,"Intensity":44825.74255},{"Energy":102,"Water":0.17,"Bone":0.178,"Titanium":0.264,"Iron":0.3579,"Intensity":42178.37574},{"Energy":103,"Water":0.169,"Bone":0.177,"Titanium":0.26,"Iron":0.3514,"Intensity":39190.23514},{"Energy":104,"Water":0.169,"Bone":0.176,"Titanium":0.256,"Iron":0.3451,"Intensity":36813.16526},{"Energy":105,"Water":0.168,"Bone":0.176,"Titanium":0.252,"Iron":0.3391,"Intensity":34479.26914},{"Energy":106,"Water":0.168,"Bone":0.175,"Titanium":0.249,"Iron":0.3332,"Intensity":31734.31846},{"Energy":107,"Water":0.167,"Bone":0.174,"Titanium":0.246,"Iron":0.3276,"Intensity":29046.87268},{"Energy":108,"Water":0.167,"Bone":0.173,"Titanium":0.242,"Iron":0.3221,"Intensity":26712.97656},{"Energy":109,"Water":0.166,"Bone":0.172,"Titanium":0.239,"Iron":0.3169,"Intensity":24240.83606},{"Energy":110,"Water":0.166,"Bone":0.171,"Titanium":0.236,"Iron":0.3118,"Intensity":21681.3743},{"Energy":111,"Water":0.165,"Bone":0.171,"Titanium":0.233,"Iron":0.3069,"Intensity":19199.43777},{"Energy":112,"Water":0.165,"Bone":0.17,"Titanium":0.23,"Iron":0.3021,"Intensity":17341.09087},{"Energy":113,"Water":0.164,"Bone":0.169,"Titanium":0.227,"Iron":0.2975,"Intensity":15640.08114},{"Energy":114,"Water":0.164,"Bone":0.168,"Titanium":0.225,"Iron":0.2931,"Intensity":13130.99815},{"Energy":115,"Water":0.164,"Bone":0.168,"Titanium":0.222,"Iron":0.2888,"Intensity":10419.69907},{"Energy":116,"Water":0.163,"Bone":0.167,"Titanium":0.22,"Iron":0.2846,"Intensity":8403.650404},{"Energy":117,"Water":0.163,"Bone":0.166,"Titanium":0.217,"Iron":0.2806,"Intensity":6312.050483},{"Energy":118,"Water":0.162,"Bone":0.166,"Titanium":0.215,"Iron":0.2767,"Intensity":4253.095729},{"Energy":119,"Water":0.162,"Bone":0.165,"Titanium":0.212,"Iron":0.2729,"Intensity":1971.380764},{"Energy":120,"Water":0.161,"Bone":0.164,"Titanium":0.21,"Iron":0.2693,"Intensity":669.987145}],"E0":40,"metal_name":"Titanium","metal_density":6,"noise_scale":12,"filter_name":"Hann","freqscale":1,"mu_water":0.268,"mu_air":0,"T1":100,"T2":1500,"energy_composition":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120],"polynomial_order_for_correction":3,"output_size":512,"pixel_size":0.041,"angle_size":0.1,"angle_num":1000,"SOD":1219.5121951219512,"correction_coeff":[-0.0065791818903273014,0.076892893874113619,0.98292556349944837,-0.0001105218423619691]}
--------------------------------------------------------------------------------
/sample_data/sample_1.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NAIST-ICB/metal_artifact_simulation/ac816eee1a918ab7514b627fade762bf0b5a5165/sample_data/sample_1.mat
--------------------------------------------------------------------------------
/sample_data/sample_2.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NAIST-ICB/metal_artifact_simulation/ac816eee1a918ab7514b627fade762bf0b5a5165/sample_data/sample_2.mat
--------------------------------------------------------------------------------
/simulation_demo.m:
--------------------------------------------------------------------------------
1 | % This code is to test Metal artifact simulation.
2 | %
3 | % Mitsuki Sakamoto
4 | % Nara Institute of Science and Technology
5 | % 2019-06-25
6 | %%
7 | addpath('.\src');
8 | addpath('.\utils');
9 |
10 | %% Load images
11 | load('./sample_data/sample_2.mat'); % load "sample" valuable
12 | image = sample.image;
13 | metal = sample.metal;
14 | pixel_size = sample.pixel_size; % [cm]
15 | disp('Load images');
16 |
17 | %% Set config
18 | config = set_config_for_artifact_simulation(pixel_size);
19 | disp('Set config');
20 |
21 | %% Preprocess
22 | image(image<-500) = -1000; % erase the boundary
23 | image = hu2mu(double(image), config.mu_water, config.mu_air);
24 | disp('Preprocess');
25 |
26 | %% Phantom calibration
27 | phantom = create_phantom(512, 512, 200, config.mu_water);
28 | config.correction_coeff = water_correction(phantom, config);
29 | disp('Phantom calibration');
30 |
31 | %% Metal Artifact Simulation
32 | sim = metal_artifact_simulation(image, metal, config);
33 | disp('Metal Artifact Simulation');
34 |
35 | %% Convert results from mu to HU
36 | sim_hu = mu2hu(sim, config.mu_water, config.mu_air);
37 | disp('Convert results from mu to HU');
38 |
39 | %% Save results
40 | save_dir = './outputs';
41 | if ~exist(save_dir, 'dir'); mkdir(save_dir); end
42 | imwrite(set_window(mu2hu(image, config.mu_water, config.mu_air), -150, 350),...
43 | fullfile(save_dir, 'input.png'));
44 | imwrite(set_window(sim_hu, -150, 350),...
45 | fullfile(save_dir, 'output.png'));
46 |
47 | if ~verLessThan('matlab', '9.1') % older than 2016b
48 | save_config_as_json(fullfile(save_dir, 'simulation_config.json'), config);
49 | else
50 | save(fullfile(save_dir, 'simulation_config.mat'), 'config')
51 | end
52 | disp('Save results');
--------------------------------------------------------------------------------
/src/create_phantom.m:
--------------------------------------------------------------------------------
1 | function phantom = create_phantom(xsize, ysize, r, mu_water)
2 | %CREATE_PHANTOM
3 | % create phantom virtually filled with water
4 | [X,Y] = meshgrid(-(xsize-1)/2:(xsize-1)/2, -(ysize-1)/2:(ysize-1)/2);
5 | phantom = (X.^2 + Y.^2)0) = 0;
36 | x_bone(x_metal>0) = 0;
37 | x_metal = double(x_metal) * mu_metal0;
38 |
39 | % Forward Projection
40 | d_water = fanbeam(x_water, ...
41 | SOD,...
42 | 'FanSensorGeometry','arc',...
43 | 'FanSensorSpacing', angle_size, ...
44 | 'FanRotationIncrement',360/angle_num);
45 | d_bone = fanbeam(x_bone,...
46 | SOD,...
47 | 'FanSensorGeometry','arc',...
48 | 'FanSensorSpacing', angle_size, ...
49 | 'FanRotationIncrement',360/angle_num);
50 | d_metal = fanbeam(x_metal,...
51 | SOD,...
52 | 'FanSensorGeometry','arc',...
53 | 'FanSensorSpacing', angle_size, ...
54 | 'FanRotationIncrement',360/angle_num);
55 | d_water = d_water * pixel_size;
56 | d_bone = d_bone * pixel_size;
57 | d_metal = d_metal * pixel_size;
58 |
59 | % Energy Composition
60 | total_intensity = 0;
61 | v = zeros(size(d_water, 1), size(d_water, 2), numel(energy_composition));
62 |
63 | for ii = 1:numel(energy_composition)
64 | energy = energy_composition(ii);
65 |
66 | m_water = data{energy, 'Water'};
67 | m_bone = data{energy, 'Bone'};
68 | m_metal = data{energy, metal_name};
69 | intensity = data{energy, 'Intensity'};
70 | d_water_tmp = d_water*(m_water/m0_water);
71 | d_bone_tmp = d_bone*(m_bone/m0_bone);
72 | d_metal_tmp = d_metal*(m_metal/m0_metal);
73 | DRR = d_water_tmp + d_bone_tmp + d_metal_tmp;
74 |
75 | y = intensity * (exp(-DRR));
76 | v(:, :, ii) = y;
77 | total_intensity = total_intensity + intensity;
78 | end
79 | poly_y = sum(v, 3);
80 |
81 | % Reconstruction
82 | noisy_y = power(10, noise_scale)*imnoise(poly_y/power(10, noise_scale),'poisson');
83 | p = -log(noisy_y/total_intensity);
84 | p = polyval(correction_coeff, p); % water correction
85 | sim = ifanbeam(p,...
86 | SOD,...
87 | 'FanSensorGeometry','arc',...
88 | 'FanSensorSpacing',angle_size,...
89 | 'OutputSize',output_size,...
90 | 'FanRotationIncrement',360/angle_num,...
91 | 'Filter', filter_name,...
92 | 'FrequencyScaling', freqscale);
93 | sim(sim<0) = 0;
94 | sim = sim/pixel_size;
95 |
96 | end
97 |
98 |
--------------------------------------------------------------------------------
/src/mu2hu.m:
--------------------------------------------------------------------------------
1 | function hu = mu2hu(mu, mu_water, mu_air)
2 | % MU2HU
3 | % convert from HU (Hounsfield Unit) to mu (linear attenuation coefficient)
4 | hu = 1000*(mu-mu_water)/(mu_water-mu_air);
5 | end
--------------------------------------------------------------------------------
/src/phantom_proj_mono.m:
--------------------------------------------------------------------------------
1 | function p = phantom_proj_mono(phantom, config)
2 | % PHANTOM_PROJ_MONO
3 | % calculate forward projection of the given phantom based on
4 | % monochromatic X-ray
5 |
6 | % Parse argments
7 | SOD = config.SOD;
8 | angle_size = config.angle_size;
9 | angle_num = config.angle_num;
10 | pixel_size = config.pixel_size;
11 |
12 | % Forward Projection
13 | d_water = fanbeam(phantom, ...
14 | SOD,...
15 | 'FanSensorGeometry','arc',...
16 | 'FanSensorSpacing', angle_size, ...
17 | 'FanRotationIncrement',360/angle_num);
18 | d_water = d_water * pixel_size;
19 | y = exp(-d_water);
20 | p = -log(y);
21 |
22 | end
--------------------------------------------------------------------------------
/src/phantom_proj_poly.m:
--------------------------------------------------------------------------------
1 | function p = phantom_proj_poly(phantom, config)
2 | % PHANTOM_PROJ_POLY
3 | % calculate forward projection of the given phantom based on
4 | % polychromatic X-ray
5 |
6 | % Parse argments
7 | SOD = config.SOD;
8 | angle_size = config.angle_size;
9 | angle_num = config.angle_num;
10 | pixel_size = config.pixel_size;
11 | data = config.data;
12 | E0 = config.E0;
13 | energy_composition = config.energy_composition;
14 |
15 | % Forward Projection
16 | d_water = fanbeam(phantom, ...
17 | SOD,...
18 | 'FanSensorGeometry','arc',...
19 | 'FanSensorSpacing', angle_size, ...
20 | 'FanRotationIncrement',360/angle_num);
21 | d_water = d_water * pixel_size;
22 |
23 | % Energy Composition
24 | total_intensity = 0;
25 | v = zeros(size(d_water, 1), size(d_water, 2), numel(energy_composition));
26 |
27 | m0_water = data{E0, 'Water'};
28 |
29 | for ii = 1:numel(energy_composition)
30 | energy = energy_composition(ii);
31 |
32 | m_water = data{energy, 'Water'};
33 | intensity = data{energy, 'Intensity'};
34 | d_water_tmp = d_water*(m_water/m0_water);
35 | DRR = d_water_tmp;
36 | y = intensity * (exp(-DRR));
37 | v(:, :, ii) = y;
38 | total_intensity = total_intensity + intensity;
39 | end
40 | poly_y = sum(v, 3);
41 |
42 | % Reconstruction
43 | p = -log(poly_y/total_intensity);
44 | end
--------------------------------------------------------------------------------
/src/set_config_for_artifact_simulation.m:
--------------------------------------------------------------------------------
1 | function config = set_config_for_artifact_simulation(pixel_size)
2 | % SET_CONFIG_FOR_METAL_ARTRIFCT_SIMULATION
3 | % return struct valuable that contains parameters for metal artifact simulation
4 |
5 | % parameters for polychlomatic projection
6 | filters = {'Ram-Lak','Shepp-Logan','Cosine','Hann','Hamming','None'};
7 | metals = {'Titanium','Iron'};
8 | config.data = readtable('xray_characteristic_data.csv');
9 | config.E0 = 40; % equivalent monochromatic energy [keV]
10 | config.metal_name = metals{1}; % used metal
11 | config.metal_density = 6; % density of the metal
12 | config.noise_scale = 12; % variance of poisson noise
13 | config.filter_name = filters{4}; % Filter to use for frequency domain filtering
14 | config.freqscale = 1; % Scale factor for rescaling the frequency axis, specified as a positive number in the range (0, 1]
15 | config.mu_water = config.data{config.E0, 'Water'}; % linear coefficient of water with E0
16 | config.mu_air = 0; % linear coefficient of air with E0
17 | config.T1 = 100; % soft tissue threshold for threshold-based weighting
18 | config.T2 = 1500; % bone threshold for threshold-based weighting
19 | config.energy_composition = cast(linspace(1, 120, 120), 'uint8'); % sampled energy for polychromatic projection
20 | config.polynomial_order_for_correction = 3; % degree of polynomial fit used in water correction
21 |
22 | % geometric parameters
23 | config.output_size = 512; % output image size along x or y direction [pix]
24 | config.pixel_size = pixel_size; % the real size of each pixel [cm]
25 | config.angle_size = 0.1; % angle between two neighbor rays [deg]
26 | config.angle_num = 1000; % number of projection rays
27 | config.SOD = 50; % source-to-origin distance, [cm]
28 | config.SOD = config.SOD/config.pixel_size; % normalized source-to-origin distance, [cm]
29 | end
30 |
31 |
--------------------------------------------------------------------------------
/src/threshold_based_weighting.m:
--------------------------------------------------------------------------------
1 | function [water, bone] = threshold_based_weighting(image,T1,T2)
2 | % THRESHOLD_BASED_WEIGHTING
3 | % apply weight function to the image based on given two threshold
4 |
5 | if nargin < 3
6 | error('Missing arguments')
7 | end
8 |
9 | w_bone = single(image - T1) / (T2 - T1);
10 | w_bone = clip(w_bone, 0 , 1);
11 | bone = w_bone .* single(image);
12 |
13 | w_water = single(T2 - image) / (T2 - T1);
14 | w_water = clip(w_water, 0, 1);
15 | water = w_water .* single(image);
16 |
17 | end
18 |
19 | function clipped = clip(a,minimum,maximum)
20 | clipped = a;
21 | clipped(a > maximum) = maximum;
22 | clipped(a < minimum) = minimum;
23 | end
--------------------------------------------------------------------------------
/src/water_correction.m:
--------------------------------------------------------------------------------
1 | function corr_coeff = water_correction(phantom, config)
2 | % WATER_CORRECTION
3 | % finds the coefficients of a polynomial for water correction
4 |
5 | n = config.polynomial_order_for_correction;
6 |
7 | % monochromatic projection
8 | p_mono = phantom_proj_mono(phantom, config);
9 |
10 | % polychlomatic projection
11 | p_poly = phantom_proj_poly(phantom, config);
12 |
13 | % polynomial fitting
14 | corr_coeff = polyfit(p_poly,p_mono,n);
15 |
16 | end
--------------------------------------------------------------------------------
/src/xray_characteristic_data.csv:
--------------------------------------------------------------------------------
1 | Energy,Water,Bone,Titanium,Iron,Intensity
2 | 1,4077,3781,5870,9085,0
3 | 2,617.3,586.9,986,1627,0
4 | 3,192.8,295.8,332,557.6,0
5 | 4,82.77,133.1,152,256.7,0
6 | 5,42.59,191.7,684,139.9,0
7 | 6,24.64,117.1,432,84.84,0
8 | 7,15.5,67.60988261,283,55.56,0
9 | 8,10.4,37.3,306,305.6,0
10 | 9,7.29,26.8,148,225.7,49.73536278
11 | 10,5.33,19.9,111,170.7,238.5495208
12 | 11,4.03,15.2,85,132.3,862.8132977
13 | 12,3.13,11.9,66.8,104.7,2196.270332
14 | 13,2.49,9.48,53.5,84.33,4420.964307
15 | 14,2.02,7.69,43.5,68.94,10421.40312
16 | 15,1.67,6.33,35.9,57.09,18636.95161
17 | 16,1.41,5.27,29.9,47.79,37950.48968
18 | 17,1.2,4.45,25.2,40.41,61393.99747
19 | 18,1.04,3.79,21.4,34.47,79736.97466
20 | 19,0.913,3.26,18.4,29.65,100999.1641
21 | 20,0.81,2.83,15.9,25.68,123616.4965
22 | 21,0.725,2.48,13.8,22.4,148659.8902
23 | 22,0.656,2.18,12.1,19.65,176107.6524
24 | 23,0.598,1.94,10.6,17.34,205516.0089
25 | 24,0.549,1.73,9.41,15.38,230934.4377
26 | 25,0.508,1.56,8.37,13.7,255458.3578
27 | 26,0.473,1.4,7.48,12.26,275529.0111
28 | 27,0.443,1.28,6.72,11.02,295620.9604
29 | 28,0.418,1.16,6.05,9.942,312324.5385
30 | 29,0.395,1.07,5.48,9.001,329444.4456
31 | 30,0.376,0.982,4.97,8.176,340060.6186
32 | 31,0.358,0.908,4.53,7.451,350399.9242
33 | 32,0.343,0.842,4.14,6.81,357774.9053
34 | 33,0.33,0.785,3.79,6.242,365182.8133
35 | 34,0.318,0.733,3.49,5.737,368197.4839
36 | 35,0.308,0.688,3.21,5.285,370174.3253
37 | 36,0.298,0.647,2.97,4.881,370158.8536
38 | 37,0.289,0.61,2.75,4.518,369626.3968
39 | 38,0.282,0.577,2.55,4.192,368456.9322
40 | 39,0.275,0.548,2.37,3.896,367299.0802
41 | 40,0.268,0.521,2.21,3.629,363529.2904
42 | 41,0.263,0.496,2.07,3.387,359420.6743
43 | 42,0.257,0.474,1.94,3.166,354948.0588
44 | 43,0.252,0.454,1.82,2.965,350744.5569
45 | 44,0.248,0.436,1.71,2.782,344701.6915
46 | 45,0.244,0.419,1.61,2.614,337969.5247
47 | 46,0.24,0.403,1.51,2.46,333678.8909
48 | 47,0.236,0.389,1.43,2.318,329295.3548
49 | 48,0.233,0.376,1.35,2.188,320781.8885
50 | 49,0.23,0.364,1.28,2.068,312148.3633
51 | 50,0.227,0.352,1.21,1.957,305174.1673
52 | 51,0.224,0.342,1.15,1.855,298010.2179
53 | 52,0.222,0.332,1.1,1.76,290946.9606
54 | 53,0.219,0.323,1.04,1.672,283748.1728
55 | 54,0.217,0.315,0.995,1.591,278714.0505
56 | 55,0.215,0.307,0.95,1.515,273631.5296
57 | 56,0.213,0.3,0.908,1.444,369343.687
58 | 57,0.211,0.293,0.869,1.378,465565.0935
59 | 58,0.209,0.287,0.832,1.316,546765.4408
60 | 59,0.208,0.281,0.798,1.259,627747.0206
61 | 60,0.206,0.275,0.766,1.205,447779.1827
62 | 61,0.204,0.27,0.736,1.154,266566.3429
63 | 62,0.203,0.265,0.708,1.107,240859.4159
64 | 63,0.201,0.26,0.682,1.063,214937.5622
65 | 64,0.2,0.256,0.657,1.021,208670.0869
66 | 65,0.199,0.252,0.634,0.9816,201761.7268
67 | 66,0.197,0.248,0.612,0.9446,262349.2987
68 | 67,0.196,0.244,0.591,0.9097,323053.0165
69 | 68,0.195,0.24,0.572,0.8768,263911.8128
70 | 69,0.194,0.237,0.554,0.8457,203208.059
71 | 70,0.193,0.234,0.536,0.8164,172538.2732
72 | 71,0.192,0.231,0.52,0.7886,141902.938
73 | 72,0.191,0.228,0.504,0.7623,135249.5722
74 | 73,0.19,0.225,0.489,0.7374,128072.4682
75 | 74,0.189,0.222,0.476,0.7138,125819.8954
76 | 75,0.188,0.22,0.462,0.6915,123910.8011
77 | 76,0.187,0.217,0.45,0.6702,120084.8679
78 | 77,0.186,0.215,0.438,0.65,115706.5341
79 | 78,0.185,0.213,0.426,0.6308,112856.0653
80 | 79,0.185,0.211,0.416,0.6126,108417.7112
81 | 80,0.184,0.209,0.405,0.5952,105390.2737
82 | 81,0.183,0.207,0.395,0.5787,100520.3443
83 | 82,0.182,0.205,0.386,0.5629,99818.46531
84 | 83,0.181,0.203,0.377,0.5478,96275.41323
85 | 84,0.181,0.201,0.369,0.5335,92478.71927
86 | 85,0.18,0.2,0.361,0.5198,88651.63192
87 | 86,0.179,0.198,0.353,0.5067,86577.76786
88 | 87,0.179,0.196,0.345,0.4942,84557.14407
89 | 88,0.178,0.195,0.338,0.4822,80892.68974
90 | 89,0.177,0.194,0.331,0.4707,77195.90356
91 | 90,0.177,0.192,0.325,0.4597,74258.49674
92 | 91,0.176,0.191,0.318,0.4492,71242.6721
93 | 92,0.175,0.189,0.312,0.4391,68055.87902
94 | 93,0.175,0.188,0.307,0.4295,64602.08666
95 | 94,0.174,0.187,0.301,0.4202,61854.81207
96 | 95,0.174,0.186,0.296,0.4113,59123.60874
97 | 96,0.173,0.185,0.291,0.4028,56922.92375
98 | 97,0.172,0.183,0.286,0.3945,54747.21795
99 | 98,0.172,0.182,0.281,0.3866,52073.13183
100 | 99,0.171,0.181,0.277,0.3791,49397.68878
101 | 100,0.171,0.18,0.272,0.3717,47153.24848
102 | 101,0.17,0.179,0.268,0.3647,44825.74255
103 | 102,0.17,0.178,0.264,0.3579,42178.37574
104 | 103,0.169,0.177,0.26,0.3514,39190.23514
105 | 104,0.169,0.176,0.256,0.3451,36813.16526
106 | 105,0.168,0.176,0.252,0.3391,34479.26914
107 | 106,0.168,0.175,0.249,0.3332,31734.31846
108 | 107,0.167,0.174,0.246,0.3276,29046.87268
109 | 108,0.167,0.173,0.242,0.3221,26712.97656
110 | 109,0.166,0.172,0.239,0.3169,24240.83606
111 | 110,0.166,0.171,0.236,0.3118,21681.3743
112 | 111,0.165,0.171,0.233,0.3069,19199.43777
113 | 112,0.165,0.17,0.23,0.3021,17341.09087
114 | 113,0.164,0.169,0.227,0.2975,15640.08114
115 | 114,0.164,0.168,0.225,0.2931,13130.99815
116 | 115,0.164,0.168,0.222,0.2888,10419.69907
117 | 116,0.163,0.167,0.22,0.2846,8403.650404
118 | 117,0.163,0.166,0.217,0.2806,6312.050483
119 | 118,0.162,0.166,0.215,0.2767,4253.095729
120 | 119,0.162,0.165,0.212,0.2729,1971.380764
121 | 120,0.161,0.164,0.21,0.2693,669.987145
122 |
--------------------------------------------------------------------------------
/src/xray_characteristic_data.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NAIST-ICB/metal_artifact_simulation/ac816eee1a918ab7514b627fade762bf0b5a5165/src/xray_characteristic_data.mat
--------------------------------------------------------------------------------
/utils/save_config_as_json.m:
--------------------------------------------------------------------------------
1 | function save_config_as_json(save_path, config)
2 | % save config as json format in save path
3 | fileID = fopen(save_path, 'w');
4 | fprintf(fileID, jsonencode(config));
5 | fclose(fileID);
6 | end
7 |
8 |
--------------------------------------------------------------------------------
/utils/set_window.m:
--------------------------------------------------------------------------------
1 | function img = set_window(img, vmin, vmax)
2 | img(img>vmax) = vmax;
3 | img(img