Skip to content

Commit

Permalink
Merge pull request #70 from imr-framework/mri4all_console
Browse files Browse the repository at this point in the history
Mri4all console
  • Loading branch information
sairamgeethanath committed Aug 21, 2023
2 parents a8dc97b + c89d474 commit 66a322a
Show file tree
Hide file tree
Showing 582 changed files with 327,652 additions and 55 deletions.
22 changes: 1 addition & 21 deletions README.md
Expand Up @@ -8,7 +8,7 @@

Virtual Scanner is an end-to-end hybrid Magnetic Resonance Imaging (MRI) simulator/console designed to be zero-footprint, modular, and supported by open-source standards.

This project is a winning response to the [ISMRM 2019 Junior Fellow Challenge (Africa)](https://www.ismrm.org/2019-junior-fellow-challenge/africa/), which poses the task of boosting accessibility to MRI training resources for underserved areas such as sub-Saharan Africa. We designed Virtual Scanner to help develop local expertise in these areas so that sustained deployment of MRI hardware is possible. Importantly, Virtual Scanner will be continually developed as a research tool that provides functionalities for simulating and prototyping MRI acquisition methods as well as services for sharing computational methods and resources with researchers around the world. Please read our publication in the journal of open source software [here](https://joss.theoj.org/papers/10.21105/joss.01637).
This project is a winning response to the [ISMRM 2019 Junior Fellow Challenge (Africa)](https://www.ismrm.org/2019-junior-fellow-challenge/africa/), which poses the task of boosting accessibility to MRI training resources for underserved areas such as sub-Saharan Africa. We designed Virtual Scanner to help develop local expertise in these areas so that sustained deployment of MRI hardware is possible. Importantly, Virtual Scanner will be continually developed as a research tool that provides functionalities for simulating and prototyping MRI acquisition methods as well as services for sharing computational methods and resources with researchers around the world. Please read our publication in the journal of open souce software [here](https://joss.theoj.org/papers/10.21105/joss.01637).

Virtual Scanner consists of two modes: in Standard Mode, a console-like GUI allows users to perform virtual scans and conduct basic analysis; in Advanced Mode, modular simulation/analysis of the entire signal chain may be performed.

Expand Down Expand Up @@ -71,35 +71,15 @@ Read the API documentation [here](https://imr-framework.github.io/virtual-scanne
## Standard Mode
* The **Register** page allows you to choose a phantom for simulation. Its format is similar to the form for entering information of the subject when conducting real scans. Choose the "Numerical" phantom for all simulations now.

<p align="center"> <a>
<img title="Register Screenshot" src="https://github.com/imr-framework/virtual-scanner/blob/master/virtualscanner/coms/coms_ui/static/screenshots/register.JPG" width="600">
</a></p>

* The **Acquire** page allows the user to choose either a Gradient Echo (GRE) or a Spin Echo (SE, with optional inversion recovery) sequence, enter the parameters, and simulate them on a cylindrical phantom ("Numerical") containing spheres with different T1, T2, and PD values.

<p align="center"> <a>
<img title="Register Screenshot" src="https://github.com/imr-framework/virtual-scanner/blob/master/virtualscanner/coms/coms_ui/static/screenshots/acquire.JPG" width="600">
</a></p>

* The **Analyze** page allows the user to load a series of data acquired in ISMRM/NIST phantom for T1 or T2 mapping and conduct curve fitting to obtain T1 and T2 maps. In addition, it can detect spheres in the phantom, a feature useful for comparing generated parameter values to literature values.

<p align="center"> <a>
<img title="Register Screenshot" src="https://github.com/imr-framework/virtual-scanner/blob/master/virtualscanner/coms/coms_ui/static/screenshots/analyze.JPG" width="600">
</a></p>

## Advanced Mode
* The **Tx** (RF transmit) page allows one to calculate and plot SAR from pulseq .seq files. *This feature is under development.*

<p align="center"> <a>
<img title="Register Screenshot" src="https://github.com/imr-framework/virtual-scanner/blob/master/virtualscanner/coms/coms_ui/static/screenshots/tx.JPG" width="600">
</a></p>

* The **Rx** (RF receive) page allows one to visualize time-domain MR signal, generated from an arbitrary grayscale image, and see the effects of using different demodulation frequencies and ADC sampling rate. *This feature is under development.*

<p align="center"> <a>
<img title="Register Screenshot" src="https://github.com/imr-framework/virtual-scanner/blob/master/virtualscanner/coms/coms_ui/static/screenshots/rx.png" width="600">
</a></p>

* Other features, including phantom and sequence viewers and reconstruction methods, are in active development.

## Known Issues
Expand Down
Binary file added _build/_images/Logo_mri4all_v2.pdf
Binary file not shown.
Binary file added _build/_images/favicon_io (17).zip
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _build/_images/favicon_io (17)/favicon-16x16.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _build/_images/favicon_io (17)/favicon-32x32.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _build/_images/favicon_io (17)/favicon.ico
Binary file not shown.
1 change: 1 addition & 0 deletions _build/_images/favicon_io (17)/site.webmanifest
@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
Binary file modified _build/_images/virtual_scanner_logo_v1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _build/_images/virtual_scanner_logo_v2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/Logo_mri4all_v2.pdf
Binary file not shown.
Binary file added _images/favicon_io (17).zip
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/favicon_io (17)/apple-touch-icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/favicon_io (17)/favicon-16x16.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/favicon_io (17)/favicon-32x32.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/favicon_io (17)/favicon.ico
Binary file not shown.
1 change: 1 addition & 0 deletions _images/favicon_io (17)/site.webmanifest
@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
Binary file added _images/virtual_scanner_logo_v1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/virtual_scanner_logo_v2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions console/__init__.py
@@ -0,0 +1 @@
name = "virtual-scanner"
Empty file added console/coms/__init__.py
Empty file.
272 changes: 272 additions & 0 deletions console/coms/coms_ui/GUI_test_functions.py
@@ -0,0 +1,272 @@
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC # available since 2.26.0
from selenium.webdriver.common.by import By
import time
import subprocess
import sys
import unittest
from selenium.webdriver.common.action_chains import ActionChains
import webbrowser

from virtualscanner.utils.constants import COMS_UI_PATH

#subprocess.call(['python', str(constants.COMS_UI_PATH / 'coms_server_flask.py')], shell=True)

# Create a new instance of the Firefox driver


class GUItestclass(unittest.TestCase):
def get_vs_address(self):
print(sys.platform)
if sys.platform == 'win32':
vs_address = "http://127.0.0.1:5000/"
else:
vs_address = "http://0.0.0.0:5000/"

return vs_address

def setup_driver(self):
if sys.platform == 'win32':
driver_path = str(COMS_UI_PATH / "firefox_driver/geckodriver_windows.exe")
else:
driver_path = str(COMS_UI_PATH / "firefox_driver/geckodriver_mac")
print("Firefox driver path: ", driver_path)
driver = webdriver.Firefox(executable_path=driver_path)
# Go to Virtual Scanner

return driver

def run_test(self, test, expected_value):
driver = self.setUp()
value = test(driver)
print("Expected value: ", expected_value)
print("Test value: ", value)
assert value == expected_value, "Value is not the same as expected :("
driver.quit()

return value==expected_value


def login_std(self, driver):
# What does an implicit wait do?
driver.find_element_by_id("mode-selection").submit()
time.sleep(3)
result = driver.current_url
return result


def login_adv(self, driver):
driver.find_element_by_id("opt2").click()
time.sleep(1)
driver.find_element_by_id("mode-selection").submit()
time.sleep(3)
result = driver.current_url
return result


def register(self, driver):
# Login first
self.login_std(driver)

# Find register button and click
driver.find_element_by_id("reg-form-submit").click()
time.sleep(3)

# Check and return style of element with id="success-sentence"
success_sentence = driver.find_element_by_id("success-sentence")
time.sleep(3)
result = success_sentence.get_attribute("style") == "display: block;"
# return success_sentence.get_attribute("style")
return result


def acquire(self, driver):
self.register(driver)

driver.find_element_by_link_text("Acquire").click()
time.sleep(2)

orientations = ['axial']
seq_types = ['GRE']

result = None

for orientation in orientations:
for seq_type in seq_types:
ir = False
if seq_type == 'IRSE':
seq_name = 'SE'
ir = True
else:
seq_name = seq_type

# Add sequence
driver.find_element_by_id("addseq-btn").click() #
time.sleep(1)
driver.find_element_by_link_text(seq_name).click()
time.sleep(1)

# Change parameters for faster sim (5 x 5)
inputnx = driver.find_element_by_id("Nx")
inputnx.clear()
inputnx.send_keys("5")
driver.find_element_by_id("Ny").click()

# Inversion recovery
if ir:
driver.find_element_by_id("IRSE-check").click()

# Simulate
driver.find_element_by_css_selector(".submit-form-btn").click()

element_found_result = False
# Wait until image is shown
try:
element = WebDriverWait(driver, 300).until(
EC.presence_of_element_located((By.XPATH,"/html/body/div/div/div/div/div/div/img[1]"))
)
element_found_result = element is not None

finally:
result = element_found_result

# If image is not shown after a while, raise error
# Print success text
return result

def analyze(self, driver):
self.register(driver)
driver.find_element_by_link_text("Analyze").click()
time.sleep(2)

# T1 mapping
driver.find_element(By.ID, "load-btn").click()
element = driver.find_element(By.ID, "ui-id-4")
actions = ActionChains(driver)
actions.move_to_element(element).perform()
time.sleep(1)
t1 = driver.find_element(By.ID, "ui-id-6")
actions.move_to_element(t1).click().perform()

time.sleep(0.5)
driver.find_element(By.CSS_SELECTOR, ".btn:nth-child(1)").click()

t2_result = False
try:
element = WebDriverWait(driver, 600).until(
EC.presence_of_element_located((By.XPATH, "/html/body/div/div/div/img[1]"))
)
t2_result = element is not None

finally:
result = t2_result

time.sleep(3)
return result


def tx(self, driver):
self.login_adv(driver)
driver.find_element_by_xpath("/html/body/div/div/nav/ul/li/a[@href=\"/tx\"]").click()
time.sleep(1)
result = driver.current_url
return result
# How do you load a file?
#C:\Users\tongg\Documents\Research\Code\virtual-scanner\virtualscanner\server\rf\tx\SAR_calc\assets

def rx(self, driver):
self.login_adv(driver)

driver.find_element_by_xpath("/html/body/div/div/nav/ul/li/a[@href=\"/rx\"]").click()
time.sleep(1)
input_dsf = driver.find_element_by_id("dsf")
input_dsf.clear()
input_dsf.send_keys("2")

time.sleep(1)

driver.find_element_by_id("form-submit-btn").click()
result = False
try:
element = WebDriverWait(driver, 20).until(
# EC.presence_of_element_located((By.ID, "num0"))
EC.presence_of_element_located((By.XPATH, "/html/body/div/div/div/div[contains(text(),'Resulting Image')]"))

)
result = element is not None

finally:
return result

def test_login_std(self):
driver1 = self.setup_driver()
driver1.get(self.get_vs_address())
self.assertEqual(self.login_std(driver1), self.get_vs_address()+"register")
driver1.quit()

def test_login_adv(self):
driver2 = self.setup_driver()
driver2.get(self.get_vs_address())
self.assertEqual(self.login_adv(driver2),self.get_vs_address()+"recon")
driver2.quit()

def test_register(self):
driver3 = self.setup_driver()
driver3.get(self.get_vs_address())
self.assertTrue(self.register(driver3))
driver3.quit()

def test_acquire(self):
driver4 = self.setup_driver()
driver4.get(self.get_vs_address())
self.assertTrue(self.acquire(driver4))
driver4.quit()


def test_analyze(self):
driver5 = self.setup_driver()
driver5.get(self.get_vs_address())
self.assertTrue(self.analyze(driver5))
driver5.quit()

def test_tx(self):
driver6 = self.setup_driver()
driver6.get(self.get_vs_address())
self.assertEqual(self.tx(driver6),self.get_vs_address()+"tx")
driver6.quit()

def test_rx(self):
driver7 = self.setup_driver()
driver7.get(self.get_vs_address())
self.assertTrue(self.rx(driver7))
driver7.quit()



# def launch_tests():
# vsadr = get_vs_address()
# tx_address = vsadr + "tx"
# # webbrowser.open(vsadr)
# print(vsadr)
# # Run tests
# run_test(login_adv, vsadr + "recon")
# run_test(login_std, vsadr + "register")
# run_test(tx, tx_address)
#
# run_test(register, "display: block;")
# run_test(acquire, "success")
# # run_test(analyze, "success") # This takes a long time (T2 mapping)
# run_test(rx, "success")
# #webbrowser.close()
#
# return "Test Code"




if __name__ == '__main__':
unittest.main()


0 comments on commit 66a322a

Please sign in to comment.