my offering

Section 01:
Ok, probably more info than you want to know, but here is the full scoop:

    I work as a medical physicist and as part of the job we have to verify that the radiation that we are giving to the patient is what we thought it was. How do we do this?

We plan the patient on a 3D planning system based off of a CT image set. We use the CT numbers (Hounsfield numbers) to determine the electron density in any given region, and then can determine how the radiation will be affected (attenuated) and converted into dose. When we have a plan that we like and the physician is happy with, we then take all of the parameters from the plan (beam angles, shapes…) and deliver that to a phantom. { a phantom is a device for which the makeup and geometry is well know, often it is made of solid water (a plastic with radiological properties within the range of treatment energies, 4MV ~ 20MV photons and 6MeV~22MeV electrons, nearly identical to that of water)}.

The phantom also has a CT study and we can get a 3D plan similar to the patient. In my case the phantom comes in 2 pieces, a 5cm thick piece on top, and a 5cm thick piece on the bottom. The top piece has 7 holes in the same orientation as shown in my post about the film. We put a piece of XV film between the 2 pieces of the phantom, mark the film with punctures at the holes and deliver the treatment. We can now compare the dose delivered to the film to the calculated does at the same plane as the film. To do this we have to register the film with the calculated plan. We will always align the phantom to the treatment machine, but the film has ~ .5-1cm of play, so we do not have consistency between films, so we can not assume that the points are always at the same location, but we can be fairly certain that they are in the same region. We can process up to 50 of these films a day (currently this number continues to increase).

The minimum number of points to have a good registration is 4.

What I have done so far is to write a macro for imageJ to find points that meet a certain criteria within the region of interest, and then write to a file the matching points.
ImageJ out puts it in the following format:

1 X Y 2 X Y 3 X Y . . . N X Y 1 X Y 2 X Y . . M X Y 1 -1 -1 1 X Y . .
[download]

The first column describes the points, every time there is a new “1” it is in a new ROI. I will get you the ROI order with the actual data. The second and third column is self explanatory. If there is a “-1” in it, it means that no points were contained in that ROI.

I wrote a very rough/simple script to import the data (it is ugly, I was only going for expedience in writing, I always clean things up after they work…and I am not good enough to write good code first time through) Here it is if you want it:

my $i = 0; my $toggle = -1; my @p = qw|ROI1 ROI2 ROI3 ROI4 ROI5 ROI6 ROI7|; my @points,%ROI; open (POINTS, "<points.txt"); while (<POINTS>) { chomp $_; my $a,$b,$c; ($a,$b,$c) = split(/\t/,$_); if ($a == 1) { $toggle *= -1; if ($toggle < 0) { $i++; $toggle = 1; } } if ($b == -1) { $i++; $toggle = -1; } else { push @{$p[$i]}, [$b,$c]; } }
[download]

Also I wrote a script to filter the points and remove any points that can not be valid (i.e. less then 4 adequate distances). This I did not test, do not have actual data yet, will have the data today or tomorrow.

# this is sent the roi info and the distances from that point to all o +f the other points from the template #$index pulls in the roi info, @deltas then pulls in the distances. #if there is a match from a point in the region in question and the re +gion it is testing against, it stops testing against that region and +increments its success, if it has 4 successes, it stops checking that + point. If at the end it does not have 4 successes it splices that p +oint….. again untested. sub filter1 { my $i = $j = $k = 0; my $index = shift; my @deltas = @_; foreach my $testreg (@{$p[$index]}) { my ($testX,$testY) = @$testreg; foreach my $region (@p) { do { if ($i == $index) {$i++} else { $k = 0; foreach my $points(@{$region}) { do { my ($X,$Y) = @$points; my $distance = sqrt(abs(($testX - $X)**2 + + ($testY - $Y)**2)); if (($deltas[$i] - $precision) <= $distanc +e) && ($deltas[$i] + $precision) >= $distance)){ $k++; $j++; } } unless ($k == 1); } } } unless ($j == 4); } if ($j < 4) { splice (@{$p[$index]},$i,1); } else { $i++; } } }
[download]

I think that after this first filter, the total number of points should be much more manageable.

Let me know if you have any questions.

Here is the data:

1 599 377 2 829 410 3 643 465 4 522 511 5 626 552 6 762 575 7 577 597 8 699 618 1 1474 13 2 1507 14 3 1882 15 4 1912 15 5 1704 16 6 1573 17 7 1685 21 8 1709 21 9 1795 90 10 1668 107 11 1732 131 12 1819 144 13 1755 159 14 1692 163 15 1936 213 16 1708 218 17 1808 227 18 1704 221 19 1747 229 20 1744 293 1 2673 619 2 2765 620 3 2839 638 4 2729 659 5 2779 688 6 2681 703 7 2744 729 8 2821 738 9 2807 788 10 2740 808 11 2560 822 12 2570 821 1 3308 1800 2 3371 1828 3 3280 1854 4 3412 1856 5 3274 1934 6 3360 1986 7 3308 1998 8 3366 2046 1 2235 2522 2 2408 2541 3 2335 2547 4 2267 2580 5 2383 2602 6 2296 2630 7 2214 2627 8 2426 2652 9 2425 2657 10 2228 2678 11 2364 2684 12 2283 2726 13 2358 2764 1 1768 2505 2 1696 2527 3 1800 2567 4 1650 2586 5 1733 2624 6 1835 2632 7 1621 2675 8 1689 2677 9 1650 2730 10 1770 2738 1 29 1746 2 30 1764 3 78 1781 4 30 1783 5 30 1806 6 320 1897 7 231 1944 8 31 1938 9 30 1968 10 376 1965 11 206 2013 12 260 2068 13 193 2096 14 401 2097 15 350 2133 16 32 2166 17 257 2187 18 32 2258 ____________________ 1 585 600 1 1715 280 1 2745 815 1 3240 2090 1 2280 2770 1 1715 2770 1 190 2090
[download]

The first set are from a film that I just created with a lot of noise, and 2 regions do not contain any true points. The second set are from the template, and the order for the roi's are the same and follow:
---------------------------------- | | | 2 | | | | 1 | | 3 | | | | | | 7 4 | | | | | | 6 5 | | | ----------------------------------
[download]


Film has a lattace of silver (a molecule containing silver) When the film is exposed to light/x-rays (photons), the silver which has a high probability of interaction becomes ionized. Then when the fixer is used the ionized portion remains and the rest is washed away. This is why in an xray, bone looks white. Compared to other tissue the photons are heavily attenuated by the bone, so most of the silver is washed away. When you damage film, i.e. punture or even just by pressure, it damages the lattace, and when the film is developed, even if it wasn't exposed, the damage can be seen.

As far as the template goes...Think of 2 blocks of styrofoam with dimensions 25cm x 25cm x 5cm, if you drilled holes in one block such that went completely though the 5cm thickness, and the holes were grouped in a known pattern, then when you placed the film between the 2 blocks, you can gain access to the film through the holes. So if you cause damage to the film at the locatoion of the holes, then you will always be able to maintain the alignment of the film to the blocks at the time of the exposure.

Does this help?



Ok...You are very close on many things. I think that you have the problem figure and understood. The geometric consistency IS there, but it is not a perfect 1:1. The jig is fine. The "plunger fits very snug into the holes, BUT there is no way to determine how the damage to the film will be represented (shape) when the film is processed/scanned. I have seen the full range of:

______ __________ / \ / -- / | -- | to | -- | | -- | | / \_______/ \____/
[download]
where the outside ring represents the darkening of the film due to the damage, and the in side marks represent the actual puncture. The resolution that we scan at is 89 microns per pixel, and the average darking per puncture is ~ 3mm across => 33 pixels. The digital processing that I do on the film after scanning finds the points, then it asigns the X,Y value to that point by way of center of mass. So in the first exampl above we would have a near perfect match, but we could be off by 10-15 pixels in the second example.

After getting some prelim. results I checked them against the film. here are the real points +/- 2 pixels:
ROI X Y 1 464 642 2 157 1756 3 687 2779 4 5 2631 2296 6 2625 1732 7
[download]
Notice that the X/Y are flipped from the input data, that is because the data given after points are found versus the software where the analysis is done call the columns/rows differently. So reverse the order to find the closest pair which would be:

ROI 1 3 643 465 ROI 2 13 1755 159 ROI 3 5 2779 688 ROI 4 None ROI 5 6 2296 2630 ROI 6 5 1733 2624 ROI 7 None
[download]

If we look at distance beween points:
True Point Distances for ROI1. ROI2 Distance = 1153.33429672407 ROI3 Distance = 2147.60913576004 ROI5 Distance = 2723.90051213329 ROI6 Distance = 2418.54935860321 Template Point Distances for ROI1. ROI2 Distance = 1174.4360348695 ROI3 Distance = 2170.67385850569 ROI5 Distance = 2753.52955313721 ROI6 Distance = 2446.58946290545 True Point Distances for ROI2. ROI1 Distance = 1153.33429672407 ROI3 Distance = 1152.56973758641 ROI5 Distance = 2529.5299958688 ROI6 Distance = 2465.09817248725 Template Point Distances for ROI2. ROI1 Distance = 1174.4360348695 ROI3 Distance = 1160.65714145048 ROI5 Distance = 2553.29688833868 ROI6 Distance = 2490 True Point Distances for ROI3. ROI1 Distance = 2147.60913576004 ROI2 Distance = 1152.56973758641 ROI5 Distance = 2001.16291190897 ROI6 Distance = 2200.50266984614 Template Point Distances for ROI3. ROI1 Distance = 2170.67385850569 ROI2 Distance = 1160.65714145048 ROI5 Distance = 2009.53974830059 ROI6 Distance = 2209.73414690546 True Point Distances for ROI5. ROI1 Distance = 2723.90051213329 ROI2 Distance = 2529.5299958688 ROI3 Distance = 2001.16291190897 ROI6 Distance = 563.031970673069 Template Point Distances for ROI5. ROI1 Distance = 2753.52955313721 ROI2 Distance = 2553.29688833868 ROI3 Distance = 2009.53974830059 ROI6 Distance = 565 True Point Distances for ROI6. ROI1 Distance = 2418.54935860321 ROI2 Distance = 2465.09817248725 ROI3 Distance = 2200.50266984614 ROI5 Distance = 563.031970673069 Template Point Distances for ROI6. ROI1 Distance = 2446.58946290545 ROI2 Distance = 2490 ROI3 Distance = 2209.73414690546 ROI5 Distance = 565
[download]

We can see fairly good agreement, but it does appear to be +/- 30

Well I am going to work further, and will start to implement some of your code for testing....
my offering

Section 02:


my offering

Section 03:


my offering

Section 04:


my offering

Section 05:


my offering

Section 06:


my offering

Section 07:


my offering

Section 08:


my offering

Section 09:


my offering

Section 10:


my offering

Section 11:


my offering

Section 12:


my offering

Section 13:


my offering

Section 14:


my offering

Section 15:


my offering

Section 16:


my offering

Section 17:


my offering

Section 18:


my offering

Section 19:


my offering

Section 20: