Difference between revisions of "GXS700 FOSS"

From Nucwiki
Jump to: navigation, search
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
 +
TLDR 2020:
 +
 +
* This page is very out of date and needs editing
 +
* In 2019 the toolkit was overhauled to be generally a lot nicer but these instructions are out of date
 +
* sudo udev.sh
 +
** Makes sensor easier to use (no "sudo")
 +
* Plug in your sensor to USB port
 +
* python3 main.py --no-xray
 +
* Observe file written to out/ dir
 +
 +
 
Quick start guide to getting the sensor working.  Basically, follow sections below to:
 
Quick start guide to getting the sensor working.  Basically, follow sections below to:
* Install software
+
 
* Force a capture to verify the sensor works
+
*Install software
* Fire x-rays at sensor to test full functionality
+
*Force a capture to verify the sensor works
 +
*Fire x-rays at sensor to test full functionality
  
 
[[https://github.com/JohnDMcMaster/uvscada/tree/master/gxs700|driver here]]
 
[[https://github.com/JohnDMcMaster/uvscada/tree/master/gxs700|driver here]]
Line 8: Line 20:
 
[[https://siliconpr0n.org/nuc/doku.php?id=gendex:gxs700|Sensor info]]
 
[[https://siliconpr0n.org/nuc/doku.php?id=gendex:gxs700|Sensor info]]
  
= WARNING =
+
=WARNING=
  
 
x-rays are dangerous…make sure you know what you are doing.  Not responsible for death, injury etc
 
x-rays are dangerous…make sure you know what you are doing.  Not responsible for death, injury etc
  
= Supported devices =
+
=Supported devices=
  
{| class="wikitable sortable" border=1
+
{| class="wikitable sortable" border="1"
! Image !! Vendor !! Product               !! Works?   !! Notes                                                  
+
!Image!!Vendor!!Product!!Works?!!Notes
 
|-
 
|-
|         || Gendex   || GXS700 small (type 1)   || Yes       || Linux VM problematic from Windows VMWare and VirtualBox
+
| ||Gendex||GXS700 small (type 1)||Yes||Linux VM problematic from Windows VMWare and VirtualBox
 
|-
 
|-
|         || Gendex   || GXS700 large (type 2)   || Yes       || Primary device I develop for                            
+
| ||Gendex||GXS700 large (type 2)||Yes||Primary device I develop for
 
|-
 
|-
|         || Dexis   || Platinum               || Probably   || Test failed but DUT was likely broken                  
+
| ||Dexis||Platinum||Probably||Test failed but DUT was likely broken
 
|-
 
|-
|         || Dexis   || Plus 690               || Probably   || Test failed but DUT was likely broken                  
+
| ||Dexis||Plus 690||Probably||Test failed but DUT was likely broken
 
|-
 
|-
 
|}
 
|}
Line 30: Line 42:
  
  
= Installation =
+
=Installation=
  
 
Prereq:
 
Prereq:
  
* Linux
+
*Linux
** Tested on Ubuntu 12.04 x64, Ubuntu 16.04 x64
+
**Tested on Ubuntu 12.04 x64, Ubuntu 16.04 x64
* USB port (duh)
+
*USB port (duh)
* A supported sensor
+
*A supported sensor
* x-ray source: not needed for initial setup
+
*x-ray source: not needed for initial setup
* You DO NOT need calibration files
+
*You DO NOT need calibration files
** See below for details
+
**See below for details
  
 
"$ cmd" means type "cmd" into a terminal
 
"$ cmd" means type "cmd" into a terminal
Line 46: Line 58:
 
Do (I'll improve this as people run into problems):
 
Do (I'll improve this as people run into problems):
  
# $ sudo apt-get install -y git python-pip
+
#$ sudo apt-get install -y git python-pip
## Also maybe: sudo apt-get install -y python-serial python-numpy python-PIL
+
##Also maybe: sudo apt-get install -y python-serial python-numpy python-PIL
# $ sudo pip install libusb1
+
#$ sudo pip install libusb1
# $ git clone [[https://github.com/JohnDMcMaster/uvscada.git|https://github.com/JohnDMcMaster/uvscada.git]]
+
#$ git clone [[https://github.com/JohnDMcMaster/uvscada.git|https://github.com/JohnDMcMaster/uvscada.git]]
# $ cd uvscada
+
#$ cd uvscada
# $ ln -s $PWD/uvscada gxs700/
+
#$ ln -s $PWD/uvscada gxs700/
# $ ./gxs700/udev.sh
+
#$ ./gxs700/udev.sh
# Plug in your sensor to the USB port
+
#Plug in your sensor to the USB port
## Re-plug it if its already plugged in
+
##Re-plug it if its already plugged in
# $ python gxs700/dump_dev.py
+
#$ python gxs700/dump_dev.py
## Optional (highly recommended): backup sensor data
+
##Optional (highly recommended): backup sensor data
# $ python gxs700/capture.py -f -e
+
#$ python gxs700/capture.py -f -e
## Optional: test sensor by forcing a capture
+
##Optional: test sensor by forcing a capture
  
  
= Force capture =
+
=Force capture=
  
 
This step tests the sensor without actually firing x-rays at it.  This is also useful for calibrating sensor defects
 
This step tests the sensor without actually firing x-rays at it.  This is also useful for calibrating sensor defects
  
{{:uvscada:gxs700:good.png?300}}
+
[[File:mcmaster_gxs700_foss_good.png|300 px]]
  
# $ python gxs700/capture.py -f -e
+
#$ python gxs700/capture.py -f -e
# Check which you got:
+
#Check which you got:
## Waiting for image: expected response.  Continue below
+
##Waiting for image: expected response.  Continue below
## "Exception: Failed to find a device": plugged in?  Did you run permission script?
+
##"Exception: Failed to find a device": plugged in?  Did you run permission script?
# It should have written capture_000_e.png to the current directory
+
#It should have written capture_000_e.png to the current directory
# You should see an image roughly resembling the noise of the reference above.  If you do, your sensor probably works
+
#You should see an image roughly resembling the noise of the reference above.  If you do, your sensor probably works
  
= X-ray capture =
+
=X-ray capture=
  
 
[[File:mcmaster_gxs700_foss_sample.jpg|300 px]]
 
[[File:mcmaster_gxs700_foss_sample.jpg|300 px]]
Line 80: Line 92:
 
Suggest you force a capture first to verify your sensor is working
 
Suggest you force a capture first to verify your sensor is working
  
# $ python gxs700/capture.py
+
#$ python gxs700/capture.py
# Verify it says "Waiting for image".  It will spit out some dots to indicate its still polling
+
#Verify it says "Waiting for image".  It will spit out some dots to indicate its still polling
# Fire your x-ray source
+
#Fire your x-ray source
# It should notice the x-rays and begin downloading an image
+
#It should notice the x-rays and begin downloading an image
# It should have written capture_000.png to the current directory
+
#It should have written capture_000.png to the current directory
## Currently also writes capture_000.bin but will probably remove this soon
+
##Currently also writes capture_000.bin but will probably remove this soon
# You have your first x-ray!
+
#You have your first x-ray!
  
= Diagnostic dump =
+
=Diagnostic dump=
  
 
Please do this and send me the result.  This helps me understand the sensors better to provide better support
 
Please do this and send me the result.  This helps me understand the sensors better to provide better support
  
# $ python gxs700/dump_dev.py
+
#$ python gxs700/dump_dev.py
  
 
Send me the directory "dump" that it creates.  If you are going to send me data from multiple sensors, please move the directory before re-running as it will overwrite.
 
Send me the directory "dump" that it creates.  If you are going to send me data from multiple sensors, please move the directory before re-running as it will overwrite.
Line 99: Line 111:
  
  
= Troubleshooting =
+
=Troubleshooting=
  
 
Troubleshooting:
 
Troubleshooting:
  
# Couldn't find device
+
#Couldn't find device
## Did you run the udev permission script?
+
##Did you run the udev permission script?
## Try re-plugging it in and/or restarting Linux system
+
##Try re-plugging it in and/or restarting Linux system
## VM: did you connect USB to the guest?
+
##VM: did you connect USB to the guest?
# Didn't detect x-rays
+
#Didn't detect x-rays
## Can you turn up current higher?
+
##Can you turn up current higher?
### Only recently added mA monitoring…don't know approx current I was imaging at
+
###Only recently added mA monitoring…don't know approx current I was imaging at
## Too high or low kVp?
+
##Too high or low kVp?
### 60 kVp is a good place to start
+
###60 kVp is a good place to start
  
 
Known issues:
 
Known issues:
  
# Multiple sensors are not supported
+
#Multiple sensors are not supported
## Would slightly increase software complexity and no use case today for that
+
##Would slightly increase software complexity and no use case today for that
# Usually can be interrupted but sometimes will fail init if it is
+
#Usually can be interrupted but sometimes will fail init if it is
## Workaround: re-plug the USB port
+
##Workaround: re-plug the USB port
  
 
Misc:
 
Misc:
  
# USB speed limits frame rate to something like 0.3 FPS…don't expect this to work like a video camera
+
#USB speed limits frame rate to something like 0.3 FPS…don't expect this to work like a video camera
# Currently doesn't use fxload but maybe should
+
#Currently doesn't use fxload but maybe should
# .bin file is raw output.  .png is lossless compressed .bin equivalent (you can make the .bin from the .png) so .bin will probably get dropped
+
#.bin file is raw output.  .png is lossless compressed .bin equivalent (you can make the .bin from the .png) so .bin will probably get dropped
# Image decoding can probably be made much faster but usually I don't care
+
#Image decoding can probably be made much faster but usually I don't care
## For long runs (ex: CBCT) I'm waiting for sensor to cool anyway
+
##For long runs (ex: CBCT) I'm waiting for sensor to cool anyway
  
 
See also: GXS700 general troubleshooting
 
See also: GXS700 general troubleshooting
  
= Decoding =
+
=Decoding=
  
 
decode.py has a "-e" option to do histogram equalization.  This often brings out additional detail by re-mapping from 16 bit grayscale to shifted 8 bit grayscale.  This works because humans can see 8 bits much easier than 16.  TOOD: could we display usable 16 bit images by using two colors?
 
decode.py has a "-e" option to do histogram equalization.  This often brings out additional detail by re-mapping from 16 bit grayscale to shifted 8 bit grayscale.  This works because humans can see 8 bits much easier than 16.  TOOD: could we display usable 16 bit images by using two colors?
Line 142: Line 154:
 
NOTE: future revisions may require .png input instead of .bin
 
NOTE: future revisions may require .png input instead of .bin
  
= x-ray trigger =
+
=x-ray trigger=
  
 
I haven't messed with the default trigger settings but I suspect you could do very low x-ray triggering if desirable
 
I haven't messed with the default trigger settings but I suspect you could do very low x-ray triggering if desirable
  
= x-ray fire =
+
=x-ray fire=
  
 
I use a Gendex GE-100 x-ray head.  I've found these readily available for <$75 on both eBay and Craigslist.  This accepts near line level AC inputs for both HV and filament making this easy to control from commodity variacs.
 
I use a Gendex GE-100 x-ray head.  I've found these readily available for <$75 on both eBay and Craigslist.  This accepts near line level AC inputs for both HV and filament making this easy to control from commodity variacs.
Line 152: Line 164:
 
I control the setup via a DLI WPS7.  When wired correctly:
 
I control the setup via a DLI WPS7.  When wired correctly:
  
# Outlet 1: HV
+
#Outlet 1: HV
# Outlet 2: filament
+
#Outlet 2: filament
  
 
do something like:
 
do something like:
Line 169: Line 181:
 
TODO: use WPS7 scripting capability to make switch throws atomic
 
TODO: use WPS7 scripting capability to make switch throws atomic
  
= Calibration =
+
=Calibration=
  
 
Takes raw, uncalibrated images.  I've been asked a few times if I could provide calibration files for the Windows driver or could even use their calibration files on my driver.  However, I'm not really interested in supporting their proprietary format. If someone submits a patch though I'll probably merge it in.
 
Takes raw, uncalibrated images.  I've been asked a few times if I could provide calibration files for the Windows driver or could even use their calibration files on my driver.  However, I'm not really interested in supporting their proprietary format. If someone submits a patch though I'll probably merge it in.
  
== cal.py flow ==
+
==cal.py flow==
  
 
Quick scheme to get rid of the worst artifacts
 
Quick scheme to get rid of the worst artifacts
  
 
Basic idea:
 
Basic idea:
# Capture a dark field frame (no x-ray) to get the lowest possible pixel value
+
 
# Capture a flat field frame (x-ray with no object) to get the highest possible pixel value
+
#Capture a dark field frame (no x-ray) to get the lowest possible pixel value
# Rescale images to range found above
+
#Capture a flat field frame (x-ray with no object) to get the highest possible pixel value
 +
#Rescale images to range found above
  
 
Notes:
 
Notes:
* Decoded images invert pixel values (per x-ray industry convention), so high and low are relative
 
* As of late 2017 capture.py now spits out a sensor .json file with each image. Hopefully the scanner will add this soon as well
 
* As of this writing no bad pixel replacement is done
 
  
 +
*Decoded images invert pixel values (per x-ray industry convention), so high and low are relative
 +
*As of late 2017 capture.py now spits out a sensor .json file with each image. Hopefully the scanner will add this soon as well
 +
*As of this writing no bad pixel replacement is done
  
=== 1: Capture dark field ===
+
 
 +
===1: Capture dark field===
  
 
First, take a dark field capture using something like:
 
First, take a dark field capture using something like:
Line 203: Line 217:
  
  
=== 2: Capture flat field ===
+
===2: Capture flat field===
  
 
Now make sure the sensor and the x-ray head have the exact same position and settings you will use to take your actual image capture. Make sure there is nothing in the beam and do a standard capture (and also firing the x-ray head):
 
Now make sure the sensor and the x-ray head have the exact same position and settings you will use to take your actual image capture. Make sure there is nothing in the beam and do a standard capture (and also firing the x-ray head):
Line 220: Line 234:
  
  
=== 3: Capture data ===
+
===3: Capture data===
  
 
ie using capture.py or xray_plan_cli.py
 
ie using capture.py or xray_plan_cli.py
Line 227: Line 241:
  
  
=== 4: Correct images ===
+
===4: Correct images===
  
 
run something like
 
run something like
Line 234: Line 248:
  
 
Where:
 
Where:
* df.png is your dark field capture
+
 
* ff.png is your flat field capture
+
*df.png is your dark field capture
* png is a directory with your images to be corrected
+
*ff.png is your flat field capture
* cal is the output directory with corrected images
+
*png is a directory with your images to be corrected
 +
*cal is the output directory with corrected images
  
 
Here is a raw image as captured:
 
Here is a raw image as captured:
Line 256: Line 271:
 
[[File:mcmaster_gxs700_foss_ex_out_e.jpg|300 px]]
 
[[File:mcmaster_gxs700_foss_ex_out_e.jpg|300 px]]
  
= Quality =
+
=Quality=
  
 
I haven't played around too much with trying to maximize quality.  One thing that's clear though is that the sensor should be as close as possible to the object to be x-rayed.  The tube to sample distance doesn't seem to matter as much
 
I haven't played around too much with trying to maximize quality.  One thing that's clear though is that the sensor should be as close as possible to the object to be x-rayed.  The tube to sample distance doesn't seem to matter as much
  
= Stitching =
+
=Stitching=
  
 
stitch.sh has an example workflow using pr0ntools (panotools).  At the core its using mask.py to generate transparency masked images to use the full, albeit irregular, sensor area.
 
stitch.sh has an example workflow using pr0ntools (panotools).  At the core its using mask.py to generate transparency masked images to use the full, albeit irregular, sensor area.

Latest revision as of 07:04, 16 September 2020

TLDR 2020:

  • This page is very out of date and needs editing
  • In 2019 the toolkit was overhauled to be generally a lot nicer but these instructions are out of date
  • sudo udev.sh
    • Makes sensor easier to use (no "sudo")
  • Plug in your sensor to USB port
  • python3 main.py --no-xray
  • Observe file written to out/ dir


Quick start guide to getting the sensor working. Basically, follow sections below to:

  • Install software
  • Force a capture to verify the sensor works
  • Fire x-rays at sensor to test full functionality

[here]

[info]

WARNING

x-rays are dangerous…make sure you know what you are doing. Not responsible for death, injury etc

Supported devices

Image Vendor Product Works? Notes
Gendex GXS700 small (type 1) Yes Linux VM problematic from Windows VMWare and VirtualBox
Gendex GXS700 large (type 2) Yes Primary device I develop for
Dexis Platinum Probably Test failed but DUT was likely broken
Dexis Plus 690 Probably Test failed but DUT was likely broken

I don't know if any other vendors (ex: schick) use the same hardware


Installation

Prereq:

  • Linux
    • Tested on Ubuntu 12.04 x64, Ubuntu 16.04 x64
  • USB port (duh)
  • A supported sensor
  • x-ray source: not needed for initial setup
  • You DO NOT need calibration files
    • See below for details

"$ cmd" means type "cmd" into a terminal

Do (I'll improve this as people run into problems):

  1. $ sudo apt-get install -y git python-pip
    1. Also maybe: sudo apt-get install -y python-serial python-numpy python-PIL
  2. $ sudo pip install libusb1
  3. $ git clone [[1]]
  4. $ cd uvscada
  5. $ ln -s $PWD/uvscada gxs700/
  6. $ ./gxs700/udev.sh
  7. Plug in your sensor to the USB port
    1. Re-plug it if its already plugged in
  8. $ python gxs700/dump_dev.py
    1. Optional (highly recommended): backup sensor data
  9. $ python gxs700/capture.py -f -e
    1. Optional: test sensor by forcing a capture


Force capture

This step tests the sensor without actually firing x-rays at it. This is also useful for calibrating sensor defects

Mcmaster gxs700 foss good.png

  1. $ python gxs700/capture.py -f -e
  2. Check which you got:
    1. Waiting for image: expected response. Continue below
    2. "Exception: Failed to find a device": plugged in? Did you run permission script?
  3. It should have written capture_000_e.png to the current directory
  4. You should see an image roughly resembling the noise of the reference above. If you do, your sensor probably works

X-ray capture

Mcmaster gxs700 foss sample.jpg

Suggest you force a capture first to verify your sensor is working

  1. $ python gxs700/capture.py
  2. Verify it says "Waiting for image". It will spit out some dots to indicate its still polling
  3. Fire your x-ray source
  4. It should notice the x-rays and begin downloading an image
  5. It should have written capture_000.png to the current directory
    1. Currently also writes capture_000.bin but will probably remove this soon
  6. You have your first x-ray!

Diagnostic dump

Please do this and send me the result. This helps me understand the sensors better to provide better support

  1. $ python gxs700/dump_dev.py

Send me the directory "dump" that it creates. If you are going to send me data from multiple sensors, please move the directory before re-running as it will overwrite.

[dumps]


Troubleshooting

Troubleshooting:

  1. Couldn't find device
    1. Did you run the udev permission script?
    2. Try re-plugging it in and/or restarting Linux system
    3. VM: did you connect USB to the guest?
  2. Didn't detect x-rays
    1. Can you turn up current higher?
      1. Only recently added mA monitoring…don't know approx current I was imaging at
    2. Too high or low kVp?
      1. 60 kVp is a good place to start

Known issues:

  1. Multiple sensors are not supported
    1. Would slightly increase software complexity and no use case today for that
  2. Usually can be interrupted but sometimes will fail init if it is
    1. Workaround: re-plug the USB port

Misc:

  1. USB speed limits frame rate to something like 0.3 FPS…don't expect this to work like a video camera
  2. Currently doesn't use fxload but maybe should
  3. .bin file is raw output. .png is lossless compressed .bin equivalent (you can make the .bin from the .png) so .bin will probably get dropped
  4. Image decoding can probably be made much faster but usually I don't care
    1. For long runs (ex: CBCT) I'm waiting for sensor to cool anyway

See also: GXS700 general troubleshooting

Decoding

decode.py has a "-e" option to do histogram equalization. This often brings out additional detail by re-mapping from 16 bit grayscale to shifted 8 bit grayscale. This works because humans can see 8 bits much easier than 16. TOOD: could we display usable 16 bit images by using two colors?

Example

$ python decode.py -e capture_004.bin capture_004e.png

NOTE: future revisions may require .png input instead of .bin

x-ray trigger

I haven't messed with the default trigger settings but I suspect you could do very low x-ray triggering if desirable

x-ray fire

I use a Gendex GE-100 x-ray head. I've found these readily available for <$75 on both eBay and Craigslist. This accepts near line level AC inputs for both HV and filament making this easy to control from commodity variacs.

I control the setup via a DLI WPS7. When wired correctly:

  1. Outlet 1: HV
  2. Outlet 2: filament

do something like:

$ WPS7_HOST=wpsip WPS7_PASS=mypassword python fire.py

to fire an x-ray (ie when the sensor is armed. wpsip is something like 192.168.0.1

Note: you can also set these environment variables in files like .bashrc so you don't have to type them for each command

I recommend you use a hard wired ethernet line and have a way to cut power to the switch remotely if it fails. I do this by running an extension cord across the room so that it can be be pulled in event of WPS7 failure (stuck switch, etc).

TODO: use WPS7 scripting capability to make switch throws atomic

Calibration

Takes raw, uncalibrated images. I've been asked a few times if I could provide calibration files for the Windows driver or could even use their calibration files on my driver. However, I'm not really interested in supporting their proprietary format. If someone submits a patch though I'll probably merge it in.

cal.py flow

Quick scheme to get rid of the worst artifacts

Basic idea:

  1. Capture a dark field frame (no x-ray) to get the lowest possible pixel value
  2. Capture a flat field frame (x-ray with no object) to get the highest possible pixel value
  3. Rescale images to range found above

Notes:

  • Decoded images invert pixel values (per x-ray industry convention), so high and low are relative
  • As of late 2017 capture.py now spits out a sensor .json file with each image. Hopefully the scanner will add this soon as well
  • As of this writing no bad pixel replacement is done


1: Capture dark field

First, take a dark field capture using something like:

 $ gxs700-capture -f -e

This should yield a raw picture that looks something like this:

Mcmaster gxs700 foss df.jpg

And histogram equalized looks like this:

Mcmaster gxs700 foss dfe.jpg


2: Capture flat field

Now make sure the sensor and the x-ray head have the exact same position and settings you will use to take your actual image capture. Make sure there is nothing in the beam and do a standard capture (and also firing the x-ray head):

 $ gxs700-capture -e

This produces a flat field image like this:

Mcmaster gxs700 foss ff.jpg

Which might look like this when histogram equalized:

Mcmaster gxs700 foss ffe.jpg

For best results you should also let the sensor and x-ray head sit a while to warm up. I'm not sure how long matters, but maybe 10 minutes would be good


3: Capture data

ie using capture.py or xray_plan_cli.py

Put your sample in and use the exact setup as the flat field to capture data. Don't move the sensor or x-ray head


4: Correct images

run something like

 $ python cal.py  df.png ff.png png cal

Where:

  • df.png is your dark field capture
  • ff.png is your flat field capture
  • png is a directory with your images to be corrected
  • cal is the output directory with corrected images

Here is a raw image as captured:


Mcmaster gxs700 foss ex raw.jpg

And with histogram equalization:

Mcmaster gxs700 foss ex raw e.jpg

Now the corrected image:

Mcmaster gxs700 foss ex out.jpg

And it with histogram equalization:

Mcmaster gxs700 foss ex out e.jpg

Quality

I haven't played around too much with trying to maximize quality. One thing that's clear though is that the sensor should be as close as possible to the object to be x-rayed. The tube to sample distance doesn't seem to matter as much

Stitching

stitch.sh has an example workflow using pr0ntools (panotools). At the core its using mask.py to generate transparency masked images to use the full, albeit irregular, sensor area.