├── 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