TPCCLIB
Loading...
Searching...
No Matches
radon.c File Reference

Radon transform. More...

#include "libtpcrec.h"

Go to the source code of this file.

Functions

void radonEmpty (RADON *radtra)
int radonSet (RADON *radtra, int mode, int imgDim, int viewNr, int binNr)
int radonGetMO (RADON *radtra)
int radonGetID (RADON *radtra)
int radonGetNV (RADON *radtra)
int radonGetNB (RADON *radtra)
float radonGetSD (RADON *radtra)
int radonGetHI (RADON *radtra)
int radonGetCB (RADON *radtra)
float radonGetSin (RADON *radtra, int nr)
int radonFwdTransform (RADON *radtra, int set, int setNr, float *imgdata, float *scndata)
int radonFwdTransformEA (RADON *radtra, int set, int setNr, float *imgdata, float *scndata)
int radonFwdTransformSA (RADON *radtra, int set, int setNr, float *imgdata, float *scndata)
int radonFwdTransformPRM (PRMAT *mat, int set, int setNr, float *imgdata, float *scndata)
int radonBackTransform (RADON *radtra, int set, int setNr, float *scndata, float *imgdata)
int radonBackTransformEA (RADON *radtra, int set, int setNr, float *scndata, float *imgdata)
int radonBackTransformSA (RADON *radtra, int set, int setNr, float *scndata, float *imgdata)
int radonBackTransformPRM (PRMAT *mat, int set, int setNr, float *scndata, float *imgdata)
int radonSetBases (RADON *radtra, ELLIPSE *elli, PRMAT *mat)
int radonSetBasesEA (RADON *radtra, ELLIPSE *elli, PRMAT *mat)
int radonSetLUT (RADON *radtra, ELLIPSE *elli, PRMAT *mat)
int radonSetLORS (RADON *radtra, ELLIPSE *elli, PRMAT *mat)

Variables

int RADON_TEST
 Drive in test mode if not 0.
int RADON_VERBOSE
 Drive in verbose mode if not 0.

Detailed Description

Radon transform.

Radon data structure contains the parameters defining a Radon transform. Transformations to and from the Radon domain are implemented in this file. Discretisation of a continuos Radon transform has five (5) different implementations in this file.

Author
Jarkko Johansson
Date
2006-06-16

Definition in file radon.c.

Function Documentation

◆ radonBackTransform()

int radonBackTransform ( RADON * radtra,
int set,
int setNr,
float * scndata,
float * imgdata )

Transforms the given sinogram in Radon domain to spatial domain. Parameters of the discrete Radon transform are stored in the RADON object. Transform is calculated only in those angles belonging into given subset. Subset contains angles starting from the index 'set' with spacing 'setNr'. Discretisation model utilised in this function is '0/1' or 'length of intersection' according to the given RADON object.

Precondition
scndata contains the projections in v x b lines of response.
Postcondition
scndata is mapped into the cartesian space.
Parameters
radtracontains an initialized radon transform object.
settells which set is to be utilized; 0 < set < setNr-1
setNrnumber of subsets
scndatav x b vector contains the projections.
imgdatan x n vector for storing the back-projection.
Returns
int 0 if ok

Definition at line 1428 of file radon.c.

1430 {
1431 float *imgptr, *scnptr; // pointers for the image and sinogram data
1432 float *Y, *X, *Xptr, *Yptr; // pointers for the values of LOR in integer points
1433 double sinus, cosinus, tanus; // sin, cosine and tangent
1434 double shift_x, shift_y; // shift for LOR
1435 int xp, xn, yp, yn, z; //integer points
1436 int x_left, x_right, y_top, y_bottom; // limits for fast search
1437 int col, row, view, bin; //counters
1438 int binNr, viewNr, imgDim;
1439 int half, center = -1, mode = 0;
1440 float sdist;
1441 float dx, dy , loi = 1; // delta x and y and length of intersection
1442
1443 //Check that the data for this radon transform is initialized
1444 if(radtra->status != RADON_STATUS_INITIALIZED) return -1;
1445
1446 //Retrieve the data from given radon transform object
1447 mode=radonGetMO(radtra);
1448 imgDim=radonGetID(radtra);
1449 binNr=radonGetNB(radtra);
1450 viewNr=radonGetNV(radtra);
1451 sdist=radonGetSD(radtra);
1452 half=radonGetHI(radtra);
1453 center=radonGetCB(radtra);
1454
1456 // Find pixel coordinates of the contributing pixels for lines of response
1457 // corresponding to first 1/4th of angles. From these pixel coordinates
1458 // others can be calculated via symmetries in projection space.
1459 // N.B. The line of response: a*x+b*y+c=cos(view)*x+sin(view)*y+k*bin=0
1460 // => solve y: y=-x*(cos(view)/sin(view)) - k*bin
1461 // solve x: x=-y*(sin(view)/cos(view))) - k*bin
1462
1463 X=(float*)calloc(imgDim+1,sizeof(float));
1464 Y=(float*)calloc(imgDim+1,sizeof(float));
1465 if(X==NULL || Y==NULL){
1466 return -2;
1467 }
1468 Xptr=X;
1469 Yptr=Y;
1470 imgptr=imgdata;
1471 scnptr=scndata;
1472 for(view=set; view<viewNr/4; view+=setNr){
1473 // Choose the type of the line of response according to view number
1474
1475 // Length of intersection is 1.
1476 loi = 1;
1477
1478 // 0. type: view=0 -> sin(view)=0
1479 if(view==0){
1480
1481 // Choose the pixels according to sample distance and pixel size,
1482 // for angles 0 and pi/2.
1483 for(bin=0; bin<binNr; bin++){
1484 col=floor((float)(bin+.5*sdist)*sdist);
1485 if(col==imgDim) col=imgDim-1;
1486
1487 // Iterate through the entries in the image matrix.
1488 // Calculate raysums for LORs in the same (absolute) distance from origin.
1489 for(row=0; row<imgDim; row++){
1490 imgptr[row*imgDim + col] += loi*scnptr[bin];
1491 imgptr[(imgDim - 1 - col)*imgDim + row] +=
1492 loi*scnptr[binNr*(viewNr/2) + bin];
1493 }
1494 }
1495 // End of view==0 (handles angles 0 and pi/2).
1496 } else {
1497 // Set sine and cosine for this angle.
1498 sinus=(double)radonGetSin(radtra,view);
1499 cosinus=(double)radonGetSin(radtra,viewNr/2 + view);
1500 tanus=sinus/cosinus;
1501
1503 // Set shift from origin for the first line of response (-n/2,theta).
1504 // NOTE that image matrix is on cartesian coordinate system where origin
1505 // is in the middle and shift is in pixels.
1506 shift_y = -(imgDim/2 -.5*sdist)/sinus;
1507 shift_x = -(imgDim/2 -.5*sdist)/cosinus;
1508
1509 // Evaluate the function of the first LOR in integer points [-n/2,n/2].
1510 // NOTE that image matrix is on cartesian coordinate system where origin
1511 // is in the middle.
1512 z=-imgDim/2;
1513 for(col=0; col<imgDim+1; col++){
1514 Yptr[col]=(float)(shift_y - z/tanus);
1515 Xptr[col]=(float)(shift_x - z*tanus);
1516 z++;
1517 }
1518
1519 // Set shift from the first LOR.
1520 shift_y = (double)(sdist/sinus);
1521 shift_x = (double)(sdist/cosinus);
1522
1523 // Iterate through half the bins in this view,
1524 // and determine coordinates of pixels contributing to this LOR.
1525 // NOTE that shift is added according to 'bin' in every loop.
1526 // Calculate also the length of intersection.
1527 // Others are determined via symmetry in projection space.
1528
1529 for(bin=0; bin<half; bin++){
1530
1531 // Limit (x-)indices for fast search.
1532 // Note that indices are non-negative integers.
1533
1534 x_left = floor((float)((Xptr[imgDim] + bin*shift_x) + imgDim/2));
1535 if(x_left < 0) x_left = 0;
1536 x_right = floor((float)((Xptr[0] + bin*shift_x) + imgDim/2));
1537 if(x_right <= 0) x_right = 1;
1538 if(x_right > imgDim) x_right = imgDim - 1;
1539
1540 /* Iterate through the values in vector Y, in integer points
1541 [x_left,x_rigth]. */
1542 for(z=x_left; z <= x_right; z++){
1543
1544 xp = z; //positive x-coordinate
1545 xn = imgDim - 1 - xp; //negative x-coordinate
1546
1547 // Look y from left.
1548 yp = imgDim/2 - floor(Yptr[xp + 1] + bin*shift_y) - 1;
1549 yn = imgDim - 1 - yp;
1550
1551 // If the y-value for this x (z) is inside the image grid.
1552 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
1553 xp < imgDim && xn < imgDim && xn >= 0)
1554 {
1555 if(!mode){
1556 loi = 1;
1557 } else {
1558 // Compute delta x and y from 'positive' coordinates.
1559 dx = 1 - (float)((Xptr[imgDim - yp] + bin*shift_x) + imgDim/2 - xp);
1560 dy = 1 - (float)(yp - (imgDim/2 - (Yptr[xp + 1] + bin*shift_y) - 1));
1561
1562 if(dx > 1 || dx < 0) dx = 1;
1563 if(dy > 1 || dy < 0) dy = 1;
1564 loi = sqrt(dx*dx + dy*dy);
1565 }
1566
1567 // Case: theta.
1568 // Add img(x,y)*k to the raysum of LOR (view,bin)
1569 imgptr[yp*imgDim + xp] += loi*scnptr[view*binNr + bin];
1570 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
1571 if(bin != center)
1572 imgptr[yn*imgDim + xn] +=
1573 loi*scnptr[view*binNr + binNr - 1 - bin];
1574
1575 if(view != viewNr/4){
1576 // Mirror the original LOR on y-axis, i.e. x->-x
1577 // Case: pi-theta.
1578 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
1579 imgptr[yp*imgDim + xn] += loi*scnptr[(viewNr - view)*binNr + bin];
1580 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
1581 if(bin != center)
1582 imgptr[yn*imgDim + xp] +=
1583 loi*scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
1584
1585 // Mirror the LOR on line x=y, i.e. x->y.
1586 // Case: pi/2-theta
1587 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,bin)
1588 imgptr[xn*imgDim + yn] += loi*scnptr[(viewNr/2 - view)*binNr + bin];
1589 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
1590 if(bin != center)
1591 imgptr[xp*imgDim + yp] +=
1592 loi*scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
1593 }
1594
1595 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
1596 // Case: pi/2+theta
1597 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
1598 imgptr[xn*imgDim + yp] += loi*scnptr[(viewNr/2 + view)*binNr + bin];
1599 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,binNr-bin)
1600 if(bin != center)
1601 imgptr[xp*imgDim + yn] +=
1602 loi*scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
1603
1604 }
1605 }
1606
1607 // Limit (y-)indices for fast search.
1608 // Note that indices are non-negative integers.
1609 y_bottom = floor((float)(Yptr[imgDim] + bin*shift_y + imgDim/2));
1610 if(y_bottom < 0) y_bottom = 0;
1611 if(y_bottom > imgDim) y_bottom = 0;
1612
1613 y_top = floor((float)(Yptr[0] + bin*shift_y + imgDim/2));
1614 if(y_top > imgDim) y_top = imgDim;
1615 if(y_top <= 0) y_top = 1;
1616
1617 /* Iterate through the values in vector X, in integer points
1618 [y_bottom,y_top]. */
1619 for(z=y_top; z >= y_bottom; z--) {
1620
1621 // Look y from this location.
1622 xp = floor(Xptr[z] + bin*shift_x) + imgDim/2;
1623 xn = imgDim - 1 - xp;
1624
1625 yp = imgDim - z - 1;
1626 yn = imgDim - yp - 1;
1627
1628 // If the x-value for this y (z) is inside the image grid.
1629 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
1630 xp < imgDim && xn < imgDim && xn >= 0)
1631 {
1632 if(!mode){
1633 loi = 1;
1634 } else{
1635 dx = (float)((Xptr[z] + bin*shift_x) + imgDim/2 - xp);
1636 dy = (float)(yp - (imgDim/2 - (Yptr[xp] + bin*shift_y) - 1));
1637 if(dy > 1 || dy < 0) dy = 1;
1638 loi = sqrt(dx*dx + dy*dy);
1639 }
1640 // Case: theta.
1641 // Add img(x,y)*k to the raysum of LOR (view,bin)
1642 imgptr[yp*imgDim + xp] += loi*scnptr[view*binNr + bin];
1643 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
1644 if(bin != center)
1645 imgptr[yn*imgDim + xn] +=
1646 loi*scnptr[view*binNr + binNr - 1 - bin];
1647
1648 if(view != viewNr/4){
1649 // Mirror the LOR on y-axis, i.e. x->-x
1650 // Case: pi-theta.
1651 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
1652 imgptr[yp*imgDim + xn] += loi*scnptr[(viewNr - view)*binNr + bin];
1653 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
1654 if(bin != center)
1655 imgptr[yn*imgDim + xp] +=
1656 loi*scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
1657
1658 // Mirror the LOR on line y=x, i.e. y->x.
1659 // Case: pi/2 - theta.
1660 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin)
1661 imgptr[xn*imgDim + yn] += loi*scnptr[(viewNr/2 - view)*binNr + bin];
1662 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
1663 if(bin != center)
1664 imgptr[xp*imgDim + yp] +=
1665 loi*scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
1666 }
1667
1668 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
1669 // Case: pi/2 + theta.
1670 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
1671 imgptr[xn*imgDim + yp] += loi*scnptr[(viewNr/2 + view)*binNr + bin];
1672 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
1673 if(bin != center)
1674 imgptr[xp*imgDim + yn] +=
1675 loi*scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
1676 }
1677 }
1678 } // END of X loop
1679 } // End of view>0.
1680 } // END OF VIEW LOOP
1681 free(X);
1682 free(Y);
1683 return 0;
1684} // END OF BACK (pro -> spa) TRANSFORM WITH 0/1 OR LOI-MODEL.
int radonGetMO(RADON *radtra)
Definition radon.c:119
int radonGetID(RADON *radtra)
Definition radon.c:128
int radonGetHI(RADON *radtra)
Definition radon.c:169
int radonGetNB(RADON *radtra)
Definition radon.c:148
int radonGetNV(RADON *radtra)
Definition radon.c:138
float radonGetSin(RADON *radtra, int nr)
Definition radon.c:192
int radonGetCB(RADON *radtra)
Definition radon.c:180
float radonGetSD(RADON *radtra)
Definition radon.c:159
char status
Definition libtpcrec.h:257

Referenced by radonBackTransform().

◆ radonBackTransformEA()

int radonBackTransformEA ( RADON * radtra,
int set,
int setNr,
float * scndata,
float * imgdata )

Same as 'radonBackTransform()' but discretisation model in this function is 'exact area'.

Parameters
radtracontains an initialized radon transform object.
settells which set is to be utilized; 0 < set < setNr-1
setNrnumber of subsets
scndatav x b vector contains the projections.
imgdatan x n vector for storing the back-projection.
Returns
int 0 if ok

Definition at line 1695 of file radon.c.

1697 {
1698 float *imgptr, *scnptr; // pointers for the image and sinogram data
1699 float *Y, *X, *Xptr, *Yptr; // pointers for the values of LOR in integer points
1700 double sinus, cosinus, tanus; // sin, cosine and tangent
1701 double shift_x, shift_y; // shift for LOR
1702 int xp, xn, yp, yn, z, xp2; //integer points
1703 int x_left, x_right, y_top, y_bottom; // limits for fast search
1704 int col, col1, col2, row, view, bin; //counters
1705 int binNr, viewNr, imgDim, errors=0;
1706 int half, center = -1;
1707 float sdist;
1708 float a=0,b=0, c=0, d=0, g=0, h=0, A;
1709 float dx, dy , eps1 = 0, eps2 = 0, eps3 = 0; // delta x and y and factors.
1710
1711 // Check that the data for this radon transform is initialized.
1712 if(radtra->status != RADON_STATUS_INITIALIZED) return -1;
1713
1714 // Retrieve the data from given radon transform object.
1715 //mode=radonGetMO(radtra); // Should be 2.
1716 imgDim=radonGetID(radtra);
1717 binNr=radonGetNB(radtra);
1718 viewNr=radonGetNV(radtra);
1719 sdist=radonGetSD(radtra);
1720 half=radonGetHI(radtra);
1721 center=radonGetCB(radtra);
1722
1723 // Array for storing values f_x.
1724 X=(float*)calloc(imgDim+1,sizeof(float));
1725 // Array for storing values f_y.
1726 Y=(float*)calloc(imgDim+1,sizeof(float));
1727 if(X==NULL || Y==NULL){
1728 return -2;
1729 }
1730 Xptr=X;
1731 Yptr=Y;
1732
1733 imgptr=imgdata;
1734 scnptr=scndata;
1735
1737 // Find pixel coordinates of the contributing pixels for tubes of response
1738 // belonging to first 1/4th of angles. From these pixel coordinates
1739 // others can be calculated via symmetries in projection space.
1740 // N.B. The line of response: a*x+b*y+c
1741 // => solve y: y=-x/tan(view) + s*(cos(theta)/tan(theta) + sin(theta))
1742 // solve x: x=-y*tan(theta) + s*(sin(theta)*tan(theta) + cos(theta))
1743
1744 for(view=set; view<=viewNr/4; view+=setNr){
1745 // view=0 -> sin(theta)=0
1746 if(view==0){
1747
1748 // Choose column(s) according to sample distance for angles 0 and pi/2.
1749 col1 = 0;
1750 col2 = 0;
1751 for(bin = 0; bin < half; bin++){
1752
1753 col1 = col2;
1754 col2 = floor((float)(bin + 1)*sdist);
1755
1756 // Determine factor epsilon.
1757 if(col1 == col2){
1758 eps1 = sdist;
1759 eps2 = 0;
1760 eps3 = 0;
1761 }
1762 if((col2-col1) == 1){
1763 eps1 = (float)(col2 - (bin)*sdist);
1764 eps2 = 0;
1765 eps3 = (float)((bin+1)*sdist - col2);
1766
1767 }
1768 // If sdist > pixel size!
1769 if((col2-col1) > 1){
1770 eps1 = (float)(col1 + 1 - (bin)*sdist);
1771 eps2 = 1; // middle pixel.
1772 eps3 = (float)((bin+1)*sdist - col2);
1773
1774 }
1775
1776 /* Iterate through the entries in the image matrix.
1777 Calculate raysums for two LORs in the same distance from origin
1778 (do halfturn). */
1779 for(row=0; row<imgDim; row++){
1780 if(!eps3){
1781 imgptr[row*imgDim + col1] += eps1 * scnptr[bin];
1782 if(bin != center)
1783 imgptr[row*imgDim + (imgDim - 1 - col1)]+=
1784 eps1 * scnptr[binNr-bin-1] ;
1785 imgptr[(imgDim - 1 - col1)*imgDim + row] +=
1786 eps1 * scnptr[binNr*(viewNr/2) + bin];
1787 if(bin != center)
1788 imgptr[col1*imgDim + row]+=
1789 eps1 * scnptr[binNr*(viewNr/2) + (binNr-bin-1)];
1790 }
1791 if(eps3 && !eps2){
1792 imgptr[row*imgDim + col1] += eps1 * scnptr[bin];
1793 imgptr[row*imgDim + col2] += eps3 *scnptr[bin];
1794 if(bin != center){
1795 imgptr[row*imgDim + (imgDim - 1 - col1)] +=
1796 eps1 * scnptr[binNr-bin-1];
1797 imgptr[row*imgDim+(imgDim-1-col2)] +=
1798 eps3*scnptr[binNr-bin-1];
1799 }
1800
1801 imgptr[(imgDim-1-col1)*imgDim+row] +=
1802 eps1* scnptr[binNr*(viewNr/2) + bin];
1803 imgptr[(imgDim-1-col2)*imgDim+row] +=
1804 eps3*scnptr[binNr*(viewNr/2) + bin];
1805 if(bin != center){
1806 imgptr[col1*imgDim + row] +=
1807 eps1 * scnptr[binNr*(viewNr/2) + (binNr-bin-1)];
1808 imgptr[col2*imgDim + row] +=
1809 eps3 *scnptr[binNr*(viewNr/2) + (binNr-bin-1)];
1810 }
1811 }
1812 if(eps3 && eps2){
1813 for(col = col1; col<=col2; col++){
1814 if(col == col1){
1815 imgptr[row*imgDim + col1]+= eps1 * scnptr[bin];
1816 if(bin != center)
1817 imgptr[row*imgDim + (imgDim - 1 - col1)]+=
1818 eps1 * scnptr[binNr-bin-1] ;
1819 imgptr[(imgDim - 1 - col1)*imgDim + row]+=
1820 eps1 * scnptr[binNr*(viewNr/2) + bin];
1821 if(bin != center)
1822 imgptr[col1*imgDim + row]+=
1823 eps1 * scnptr[binNr*(viewNr/2) + (binNr-bin-1)];
1824 }
1825 if(col == col2){
1826 imgptr[row*imgDim + col2]+= eps3 * scnptr[bin];
1827 if(bin != center)
1828 imgptr[row*imgDim + (imgDim - 1 - col2)]+=
1829 eps3 * scnptr[binNr-bin-1];
1830 imgptr[(imgDim - 1 - col2)*imgDim + row]+=
1831 eps3 * scnptr[binNr*(viewNr/2) + bin];
1832 if(bin != center)
1833 imgptr[col2*imgDim + row]+=
1834 eps3 * scnptr[binNr*(viewNr/2) + (binNr-bin-1)];
1835 }
1836 if(col != col1 && col != col2){
1837 imgptr[row*imgDim + col]+= eps2 * scnptr[bin] ;
1838 if(bin != center)
1839 imgptr[row*imgDim + (imgDim - 1 - col)]+=
1840 eps2 * scnptr[binNr-bin-1];
1841 imgptr[(imgDim - 1 - col)*imgDim + row]+=
1842 eps2 * scnptr[binNr*(viewNr/2) + bin];
1843 if(bin != center)
1844 imgptr[col*imgDim + row]+=
1845 eps2 * scnptr[binNr*(viewNr/2) + (binNr-bin-1)];
1846 }
1847 }
1848 }
1849 }
1850 }
1851 // End of view==0 (handles angles 0 and pi/2).
1852 } else {
1853
1854 // Set sine and cosine for this angle.
1855 sinus = (double)radonGetSin(radtra,view);
1856 cosinus = (double)radonGetSin(radtra,viewNr/2 + view);
1857 tanus = sinus/cosinus;
1858
1859 // Set shift from origin for the first line of response (-n/2,theta).
1860 // NOTE that image matrix is on cartesian coordinate system where origin
1861 // is in the middle and shift is in pixels.
1862 shift_y = -(imgDim/2)/sinus;
1863 shift_x = -(imgDim/2)/cosinus;
1864
1865 // Evaluate the function of the first LOR in integer points [-n/2,n/2].
1866 // NOTE that image matrix is on cartesian coordinate system where origin
1867 // is in the middle.
1868 z=-imgDim/2;
1869 for(col=0; col<imgDim+1; col++){
1870 Yptr[col]=(float)(-z/tanus + shift_y);
1871 Xptr[col]=(float)(-z*tanus + shift_x);
1872 z++;
1873 }
1874
1875 // Set shift from the first LOR.
1876 shift_y = (double)(sdist/sinus);
1877 shift_x = (double)(sdist/cosinus);
1878
1879 // Iterate through half the bins in this view,
1880 // and determine coordinates of pixels contributing to this LOR.
1881 // NOTE that shift is added according to 'bin' in every loop.
1882 // Calculate also the length of intersection.
1883 // Others are determined via symmetry in projection space.
1884
1885 for(bin=0; bin<half; bin++){
1886
1887 // Limit (x-)indices for fast search.
1888 // Note that indices are non-negative integers.
1889
1890 x_left = floor((float)(Xptr[imgDim] + bin*shift_x + imgDim/2));
1891 if(x_left < 0) x_left = 0;
1892
1893 x_right = floor((float)(Xptr[0] + bin*shift_x + imgDim/2));
1894 if(x_right <= 0) x_right = 1;
1895 if(x_right > imgDim) x_right = imgDim - 1;
1896
1897 /* Iterate through the values in vector Y, in integer points
1898 [x_left,x_rigth]. */
1899 for(z=x_left; z <= x_right; z++) {
1900
1901 xp = z; //positive x-coordinate
1902 xn = imgDim - 1 - xp; //negative x-coordinate
1903
1904 // Look y from left.
1905 yp = imgDim/2 - floor(Yptr[xp + 1] + bin*shift_y) - 1;
1906 yn = imgDim - 1 - yp;
1907
1908 // If the y-value for this x (z) is inside the image grid.
1909 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
1910 xp < imgDim && xn < imgDim && xn >= 0)
1911 {
1912
1913 // NOTE that pixels found in this part are always hit from right side.
1914 // Compute a := |AF| and b := |FB|.
1915 a = (float)(xp + 1 - (imgDim/2 + Xptr[imgDim - yp] + bin*shift_x));
1916 b = (float)(floor(Yptr[xp + 1] + bin*shift_y) + 1 - (Yptr[xp + 1] +
1917 bin*shift_y));
1918
1919 // Calculate the area of lower triangle.
1920 A = a*b/2;
1921
1922 // c := |FC|
1923 c = (float)(xp + 1 - (imgDim/2 + Xptr[imgDim - yp] +
1924 (bin+1)*shift_x));
1925
1926 if(c > 0){
1927 // d := |FD|
1928 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
1929 (Yptr[xp + 1] + (bin+1)*shift_y));
1930 // Subtract the area of upper triangle.
1931 A = A - c*d/2;
1932 }
1933
1934 eps1 = A;
1935 if((eps1 < 0 || eps1 > 1) && RADON_VERBOSE){
1936 printf("RADON: Error in factor: eps1=%.5f \n",eps1);
1937 errors++;
1938 }
1939
1940 // Case: theta.
1941 // Add img(x,y)*k to the raysum of TOR (view,bin)
1942 imgptr[yp*imgDim + xp]+= eps1 * scnptr[view*binNr + bin];
1943 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
1944 if(bin != center)
1945 imgptr[yn*imgDim + xn]+=
1946 eps1 * scnptr[view*binNr + binNr - 1 - bin];
1947
1948 if(view != viewNr/4){
1949 // Mirror the original LOR on y-axis, i.e. x->-x
1950 // Case: pi-theta.
1951 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
1952 imgptr[yp*imgDim + xn]+=
1953 eps1 * scnptr[(viewNr - view)*binNr + bin];
1954 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
1955 if(bin != center)
1956 imgptr[yn*imgDim + xp]+=
1957 eps1 * scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
1958
1959 // Mirror the LOR on line x=y, i.e. x->y.
1960 // Case: pi/2-theta
1961 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,bin)
1962 imgptr[xn*imgDim + yn]+=
1963 eps1 * scnptr[(viewNr/2 - view)*binNr + bin];
1964 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
1965 if(bin != center)
1966 imgptr[xp*imgDim + yp]+=
1967 eps1 * scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
1968 }
1969
1970 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
1971 // Case: pi/2+theta
1972 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
1973 imgptr[xn*imgDim + yp]+= eps1 * scnptr[(viewNr/2 + view)*binNr + bin];
1974 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,binNr-bin)
1975 if(bin != center)
1976 imgptr[xp*imgDim + yn]+=
1977 eps1 * scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
1978 }
1979 }
1980
1981 // Limit (y-)indices for fast search.
1982 // Note that indices are non-negative integers.
1983 y_bottom = floor((float)(Yptr[imgDim] + bin*shift_y + imgDim/2));
1984 if(y_bottom < 0) y_bottom = 0;
1985 if(y_bottom > imgDim) y_bottom = 0;
1986
1987 y_top = floor((float)(Yptr[0] + bin*shift_y + imgDim/2));
1988 if(y_top > imgDim) y_top = imgDim;
1989 if(y_top <= 0) y_top = 1;
1990
1991 // Iterate through the values in vector X, in integer points [y_bottom,y_top].
1992 for(z=y_top; z >= y_bottom; z--) {
1993
1994 // Look y from this location.
1995 xp = floor(Xptr[z] + bin*shift_x) + imgDim/2;
1996 xn = imgDim - 1 - xp;
1997
1998 yp = imgDim - z - 1;
1999 yn = imgDim - yp - 1;
2000
2001 // If the x-value for this y (z) is inside the image grid.
2002 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0
2003 && xp < imgDim && xn < imgDim && xn >= 0)
2004 {
2005 eps1=eps2=eps3=0;
2006
2007 dx = (float)(Xptr[z] + bin*shift_x + imgDim/2 - xp);
2008 dy = (float)(Yptr[xp] + bin*shift_y - z + imgDim/2);
2009
2010 if(dy < 1){ // Cases 3,4,5 and 6.
2011 // 1. PART
2012 // a := |HA|
2013 a = dy;
2014 // b := |HB| (b < 1 for angles in [0,pi/4))
2015 b = dx;
2016 // h := height of rectangle R.
2017 h = a + shift_y;
2018 if(h > 1){ // Cases 3,4 and 5.
2019 h = 1;
2020 g = b + shift_x;
2021 if(g > 1){ // Cases 3 and 4.
2022 g = 1;
2023 xp2 =floor(Xptr[z+1] + (bin+1)*shift_x) + imgDim/2;
2024 if(xp == xp2){ // Case 4.
2025 // c := |FC|
2026 c = (float)(xp + 1 - (imgDim/2 + Xptr[z+1] + (bin+1)*shift_x));
2027 // d := |FD|
2028 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
2029 (Yptr[xp + 1] + (bin+1)*shift_y));
2030 eps1 = 1 - (a*b + c*d)/2;
2031 eps2 = 0;
2032 // Lower triangle on the next pixel (x+1,y).
2033 eps3 = (1 - d)*(b + shift_x - 1)/2;
2034 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
2035 && RADON_VERBOSE) printf(
2036 "4: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
2037 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
2038 } else{ // Case 3.
2039 // c=d=0.
2040 eps1 = 1 - a*b/2;
2041 // Calculate area on pixel in place (xp+1,yp-1).
2042 dy = (float)(Yptr[xp+1] + (bin+1)*shift_y - (z + 1) +
2043 imgDim/2);
2044 if(dy < 1){ // Case 11.
2045 // c := |HC|
2046 c = dy;
2047 // d := |HD|
2048 d = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
2049 (bin+1)*shift_x));
2050 eps2 = c*d/2;
2051 } else { // Cases 9 and 10.
2052
2053 dx = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
2054 (bin+1)*shift_x));
2055 if(dx < 1) { // Case 10.
2056 // g := length of rectangle Q.
2057 g = dx;
2058 // c := |CD| (on x-axis).
2059 c = dx - (float)(xp + 2 - (imgDim/2 + Xptr[z+2] +
2060 (bin+1)*shift_x));
2061 // Rectangle Q - triangle c*h (h = 1).
2062 eps2 = g - c/2;
2063 } else { // Case 9.
2064 // c := |FC|
2065 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+2] +
2066 (bin+1)*shift_x));
2067 // d := |FD|
2068 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) + 2 -
2069 (Yptr[xp + 2] + (bin+1)*shift_y));
2070 // Rectangle Q - triangle CFD.
2071 eps2 = 1 - c*d/2;
2072 }
2073 }
2074 // Calculate area on pixel in place (xp+1,yp).
2075 dx = (float)(xp + 2 - (imgDim/2 + Xptr[z] + (bin+1)*shift_x));
2076 if(dx < 1){ // Case 10.
2077 // g := length of rectangle Q.
2078 g = dx;
2079 // c := |CD| (on x-axis).
2080 c = dx - (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
2081 (bin+1)*shift_x));
2082 // Rectangle Q - triangle c*h (h = 1).
2083 eps3 = g - c/2;
2084 } else { // Case 9.
2085 // c := |FC|
2086 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
2087 (bin+1)*shift_x));
2088 // d := |FD|
2089 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) + 1 -
2090 (Yptr[xp + 2] + (bin+1)*shift_y));
2091 // Rectangle Q - triangle CFD.
2092 eps3 = 1 - c*d/2;
2093 }
2094 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
2095 && RADON_VERBOSE) printf(
2096 "3/v%i: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
2097 view,xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
2098 }
2099 } else{ // Case 5. (g < 1)
2100 // c := |DC|.
2101 c = g - (imgDim/2 + Xptr[z+1] + (bin+1)*shift_x - xp);
2102 // d := heigth
2103 d = 1;
2104 eps1 = g*h - (a*b + c*d)/2;
2105 eps2 = 0;
2106 eps3 = 0;
2107 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
2108 && RADON_VERBOSE) printf(
2109 "5: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
2110 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
2111 }
2112 } else { // Case 6 (h <= 1).
2113 // g := legth of rectangle R
2114 g = b + shift_x;
2115 if(g > 1) // Should always be < 1 for angles in [0,pi/4)
2116 g = 1;
2117 eps1 = (g*h - a*b)/2;
2118 eps2 = 0;
2119 eps3 = 0;
2120 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1) &&
2121 RADON_VERBOSE) printf(
2122 "6: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
2123 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
2124 }
2125 } else { // 2. PART
2126 // Cases 2,7 and 8. (dy >= 1).
2127 // a := |HA|
2128 a = 1;
2129 // b := |HB| (>=1)
2130 b = dx - (float)(Xptr[z+1] + bin*shift_x + imgDim/2 - xp);
2131 // h := heigth of rectangle R
2132 h = 1;
2133 // g := length of rectangle R
2134 g = dx + shift_x;
2135 if(g > 1){ // Cases 2 and 8.
2136 g = 1 - (float)(Xptr[z+1] + bin*shift_x + imgDim/2 - xp);
2137 // positive x-coordinate (bin+1)
2138 xp2 = floor(Xptr[z+1] + (bin+1)*shift_x) + imgDim/2;
2139 if(xp == xp2){ // Case 8.
2140 // c := |FC|
2141 c = (float)(xp + 1 - (imgDim/2 + Xptr[z+1] + (bin+1)*shift_x));
2142 // d := |FD|
2143 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
2144 (Yptr[xp + 1] + (bin+1)*shift_y));
2145
2146 eps1 = g*h - (a*b + c*d)/2;
2147 eps2 = 0;
2148 // Lower triangle on the next pixel (x+1,y).
2149 eps3 = (1 - d)*((Xptr[z] + (bin+1)*shift_x + imgDim/2) -
2150 (xp+1))/2;
2151 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
2152 && RADON_VERBOSE) printf(
2153 "8: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
2154 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
2155 } else { // Case 2.
2156 // c=d=0.
2157 eps1 = g*h - a*b/2;
2158
2159 /* Pixel in place (xp+1,yp-1) should have been found in
2160 the previous step. */
2161 eps2 = 0;
2162
2163 // Calculate area on pixel in place (xp+1,yp).
2164
2165 dx = (float)((imgDim/2 + Xptr[z] + (bin+1)*shift_x) - (xp+1));
2166 if(dx < 1){ // Case 10 (trapezium).
2167 // g := bottom of trapezium Q.
2168 g = dx;
2169 // c := top of trapezium Q.
2170 c = (float)((imgDim/2 + Xptr[z+1] + (bin+1)*shift_x) -
2171 (xp+1));
2172 // Area of trapezium Q. Heigth = 1.
2173 eps3 = (g + c)/2;
2174 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 ||
2175 eps3>1) && RADON_VERBOSE) printf(
2176 "2/10: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
2177 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
2178 } else { // Case 9.
2179 // c := |FC|
2180 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
2181 (bin+1)*shift_x));
2182 // d := |FD|
2183 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) + 1 -
2184 (Yptr[xp + 2] + (bin+1)*shift_y));
2185 // Rectangle Q - triangle CFD.
2186 eps3 = 1 - c*d/2;
2187 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 ||
2188 eps3>1) && RADON_VERBOSE) printf(
2189 "2/9: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
2190 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
2191 }
2192 }
2193 } else { // Case 7. (g < = 1)
2194
2195 // Area of the parallelogram R.
2196 eps1 = sdist/cosinus;
2197 eps2 = 0;
2198 eps3 = 0;
2199 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1) &&
2200 RADON_VERBOSE) printf(
2201 "7: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
2202 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
2203 }
2204 }
2205 if(!eps2 && !eps3) { // Cases 5,6 and 7.
2206 // Case: theta.
2207 // Add img(x,y)*k to the raysum of LOR (view,bin)
2208 imgptr[yp*imgDim + xp]+= eps1 * scnptr[view*binNr + bin];
2209 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
2210 if(bin != center)
2211 imgptr[yn*imgDim + xn]+=
2212 eps1 * scnptr[view*binNr + binNr - 1 - bin];
2213
2214 if(view != viewNr/4) {
2215 // Mirror the LOR on y-axis, i.e. x->-x
2216 // Case: pi-theta.
2217 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
2218 imgptr[yp*imgDim + xn]+=
2219 eps1 * scnptr[(viewNr - view)*binNr + bin];
2220 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
2221 if(bin != center)
2222 imgptr[yn*imgDim + xp]+=
2223 eps1 * scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
2224
2225 // Mirror the LOR on line y=x, i.e. y->x.
2226 // Case: pi/2 - theta.
2227 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin)
2228 imgptr[xn*imgDim + yn]+=
2229 eps1 * scnptr[(viewNr/2 - view)*binNr + bin];
2230 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
2231 if(bin != center)
2232 imgptr[xp*imgDim + yp]+=
2233 eps1 * scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
2234 }
2235
2236 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
2237 // Case: pi/2 + theta.
2238 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
2239 imgptr[xn*imgDim + yp]+=
2240 eps1 * scnptr[(viewNr/2 + view)*binNr + bin];
2241 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
2242 if(bin != center)
2243 imgptr[xp*imgDim + yn]+=
2244 eps1 * scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
2245
2246 } else {
2247 if(!eps2) { // <=> eps3 != 0 & eps2 = 0 <=> Cases 3,4 and 8.
2248 if(xp + 1 < imgDim && xn - 1 >= 0) {
2249 // Case: theta.
2250 // Add img(x,y)*k to the raysum of LOR (view,bin)
2251 imgptr[yp*imgDim + xp] += eps1 * scnptr[view*binNr + bin];
2252 imgptr[yp*imgDim + xp+1] += eps3 *scnptr[view*binNr + bin];
2253 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
2254 if(bin != center){
2255 imgptr[yn*imgDim + xn] +=
2256 eps1 * scnptr[view*binNr + binNr - 1 - bin];
2257 imgptr[yn*imgDim + xn-1] +=
2258 eps3 * scnptr[view*binNr + binNr - 1 - bin];
2259 }
2260
2261 if(view != viewNr/4) {
2262 // Mirror the LOR on y-axis, i.e. x->-x
2263 // Case: pi-theta.
2264 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
2265 imgptr[yp*imgDim + xn]+=
2266 eps1 * scnptr[(viewNr - view)*binNr + bin];
2267 imgptr[yp*imgDim + xn-1] +=
2268 eps3 * scnptr[(viewNr - view)*binNr + bin];
2269 /* Add img(x,-y)*k to the raysum of LOR
2270 (viewNr-view,binNr-bin) */
2271 if(bin != center) {
2272 imgptr[yn*imgDim + xp] +=
2273 eps1 * scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
2274 imgptr[yn*imgDim + xp+1] +=
2275 eps3 *scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
2276 }
2277 // Mirror the LOR on line y=x, i.e. y->x.
2278 // Case: pi/2 - theta.
2279 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin)
2280 imgptr[xn*imgDim + yn]+=
2281 eps1 * scnptr[(viewNr/2 - view)*binNr + bin];
2282 imgptr[(xn-1)*imgDim + yn] +=
2283 eps3 *scnptr[(viewNr/2 - view)*binNr + bin];
2284 /* Add img(-y,-x)*k to the raysum of LOR
2285 (viewNr/2-view,binNr-bin) */
2286 if(bin != center) {
2287 imgptr[xp*imgDim + yp]+=
2288 eps1 * scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
2289 imgptr[(xp+1)*imgDim+yp]+=
2290 eps3 * scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
2291 }
2292 }
2293
2294 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
2295 // Case: pi/2 + theta.
2296 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
2297 imgptr[xn*imgDim + yp]+=
2298 eps1 * scnptr[(viewNr/2 + view)*binNr + bin];
2299 imgptr[(xn-1)*imgDim + yp] +=
2300 eps3 * scnptr[(viewNr/2 + view)*binNr + bin];
2301 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
2302 if(bin != center){
2303 imgptr[xp*imgDim + yn]+=
2304 eps1 * scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
2305 imgptr[(xp+1)*imgDim+yn] +=
2306 eps3*scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
2307 }
2308 }
2309 } else { // <=> eps2!=0 && eps3!=0 <=> Case 3.
2310 if(xp+1 < imgDim && xn-1 >= 0 && yp-1 >= 0 && yn+1 < imgDim) {
2311
2312 // Case: theta.
2313 // Add img(x,y)*k to the raysum of LOR (view,bin)
2314 imgptr[yp*imgDim + xp] += eps1 * scnptr[view*binNr + bin];
2315 imgptr[yp*imgDim + xp+1] += eps3 *scnptr[view*binNr + bin];
2316 imgptr[(yp-1)*imgDim + xp+1] +=
2317 eps2 * scnptr[view*binNr + bin];
2318 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
2319 if(bin != center){
2320 imgptr[yn*imgDim + xn] +=
2321 eps1 * scnptr[view*binNr + binNr - 1 - bin];
2322 imgptr[yn*imgDim + xn-1] +=
2323 eps3 * scnptr[view*binNr + binNr - 1 - bin];
2324 imgptr[(yn+1)*imgDim + xn-1] +=
2325 eps2 * scnptr[view*binNr + binNr - 1 - bin];
2326 }
2327 if(view != viewNr/4) {
2328 // Mirror the LOR on y-axis, i.e. x->-x
2329 // Case: pi-theta.
2330 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
2331 imgptr[yp*imgDim + xn] +=
2332 eps1 * scnptr[(viewNr - view)*binNr + bin];
2333 imgptr[yp*imgDim + xn-1] +=
2334 eps3 *scnptr[(viewNr - view)*binNr + bin];
2335 imgptr[(yp-1)*imgDim + xn-1]+=
2336 eps2 * scnptr[(viewNr - view)*binNr + bin];
2337 /* Add img(x,-y)*k to the raysum of LOR
2338 (viewNr-view,binNr-bin) */
2339 if(bin != center) {
2340 imgptr[yn*imgDim + xp] +=
2341 eps1 * scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
2342 imgptr[yn*imgDim + xp+1] +=
2343 eps3 * scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
2344 imgptr[(yn+1)*imgDim + xp+1] +=
2345 eps2 * scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
2346 }
2347
2348 // Mirror the LOR on line y=x, i.e. y->x.
2349 // Case: pi/2 - theta.
2350 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin)
2351 imgptr[xn*imgDim + yn]+=
2352 eps1 * scnptr[(viewNr/2 - view)*binNr + bin];
2353 imgptr[xn*imgDim + yn-1] +=
2354 eps3 *scnptr[(viewNr/2 - view)*binNr + bin];
2355 imgptr[(xn-1)*imgDim + (yn+1)] +=
2356 eps2 * scnptr[(viewNr/2 - view)*binNr + bin];
2357 /* Add img(-y,-x)*k to the raysum of LOR
2358 (viewNr/2-view,binNr-bin) */
2359 if(bin != center) {
2360 imgptr[xp*imgDim + yp]+=
2361 eps1 * scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
2362 imgptr[(xp+1)*imgDim+yp] +=
2363 eps3*scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
2364 imgptr[(xp+1)*imgDim+(yp-1)] +=
2365 eps2*scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
2366 }
2367 }
2368
2369 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
2370 // Case: pi/2 + theta.
2371 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin).
2372 imgptr[xn*imgDim + yp] +=
2373 eps1 * scnptr[(viewNr/2 + view)*binNr + bin];
2374 imgptr[(xn-1)*imgDim + yp] +=
2375 eps3 * scnptr[(viewNr/2 + view)*binNr + bin];
2376 imgptr[(xn-1)*imgDim + (yp-1)] +=
2377 eps2 *scnptr[(viewNr/2 + view)*binNr + bin];
2378 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
2379 if(bin != center){
2380 imgptr[xp*imgDim + yn]+=
2381 eps1 * scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
2382 imgptr[(xp+1)*imgDim+yn] +=
2383 eps3 * scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
2384 imgptr[(xp+1)*imgDim+yn+1] +=
2385 eps2*scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
2386 }
2387 }
2388 }
2389 }
2390 }
2391 }
2392 } // END of X loop
2393 } // End of view>0.
2394 } // END OF VIEW LOOP
2395 free(X);
2396 free(Y);
2397
2398 if(RADON_VERBOSE) {
2399 printf("RADON: radonBackTransformEA() finished with %d errors.\n", errors);
2400 fflush(stdout);
2401 }
2402
2403 return 0;
2404
2405} // END OF EXACT AREA BACK TRANSFORM.
int RADON_VERBOSE
Drive in verbose mode if not 0.
Definition radon.c:13

Referenced by radonBackTransformEA().

◆ radonBackTransformPRM()

int radonBackTransformPRM ( PRMAT * mat,
int set,
int setNr,
float * scndata,
float * imgdata )

Transforms the given sinogram in Radon domain to spatial domain. Transform is calculated by multiplying with the transpose of the given projection matrix from the right. Transform is calculated only in those angles belonging into given subset. Subset contains angles starting from the index 'set' with spacing 'setNr'. Discretisation model utilised in this function is '0/1', 'length of intersection' or 'exact area' according to the given projection matrix.

Precondition
scndata contains the projections with v x b lines of response.
Postcondition
scndata is mapped into the cartesian space.
Parameters
matpointer to structure where coordinates and values are stored.
settells which set is to be utilized; 0 < set < setNr-1
setNrnumber of subsets
scndatav x b vector contains the projections.
imgdatan x n vector for storing the back-projection.
Returns
int 0 if ok

Definition at line 2507 of file radon.c.

2509 {
2510 float *imgptr, *scnptr; // pointers for the image and sinogram data
2511 unsigned int imgDim=128, binNr=256, viewNr=192, view, bin, row, col;
2512 unsigned int half, centerbin;
2513 int xp, xn, yp, yn;
2514 float fact;
2515
2516 // Retrieve the data from given projection matrix.
2517 imgDim=prmatGetID(mat);
2518 binNr=prmatGetNB(mat); // Should be equal to imgDim.
2519 viewNr=prmatGetNV(mat);
2520
2521 // Calculate and set center bin for current geometrics.
2522 if((binNr%2) != 0){
2523 half = (binNr - 1)/2 + 1;
2524 centerbin = half - 1;
2525 } else {
2526 half = binNr/2;
2527 // In the case binNr is even there is no center bin.
2528 centerbin = -1;
2529 }
2530
2531 imgptr = imgdata;
2532 scnptr = scndata;
2533
2534 // Draw sinogram according to projection matrix.
2535 for(view=set; view<=viewNr/4; view=view+setNr){
2536 for(bin=0; bin<half; bin++){
2537 row = view*half + bin;
2538 for(col=0; col<prmatGetPixels(mat,row); col++){
2539
2540 fact = prmatGetFactor(mat,row,col);
2541 xp = prmatGetXCoord(mat,row,col);
2542 xn = imgDim - 1 - xp;
2543 yp = prmatGetYCoord(mat,row,col);
2544 yn = imgDim - 1 - yp;
2545
2546 // Add img(x,y)*k to the raysum of LOR (view,bin)
2547 imgptr[yp*imgDim + xp] += fact * scnptr[view*binNr + bin];
2548 if(bin != centerbin)
2549 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
2550 imgptr[yn*imgDim + xn] += fact * scnptr[view*binNr + binNr - 1 - bin];
2551
2552 if(view != 0 && view != viewNr/4){
2553 // Mirror the original LOR on y-axis, i.e. x->-x
2554 // Case: pi-theta.
2555 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
2556 imgptr[yp*imgDim + xn] += fact * scnptr[(viewNr - view)*binNr + bin];
2557 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
2558 if(bin != centerbin)
2559 imgptr[yn*imgDim + xp] +=
2560 fact * scnptr[(viewNr-view)*binNr + binNr - 1 - bin];
2561
2562 // Mirror the LOR on line x=y, i.e. x->y.
2563 // Case: pi/2-theta
2564 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,bin)
2565 imgptr[xn*imgDim + yn] += fact * scnptr[(viewNr/2 - view)*binNr + bin];
2566 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
2567 if(bin != centerbin)
2568 imgptr[xp*imgDim + yp] +=
2569 fact * scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin];
2570 }
2571
2572 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
2573 // Case: pi/2+theta
2574 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
2575 imgptr[xn*imgDim + yp] += fact * scnptr[(viewNr/2 + view)*binNr + bin];
2576 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,binNr-bin)
2577 if(bin != centerbin)
2578 imgptr[xp*imgDim + yn] +=
2579 fact * scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin];
2580
2581 }
2582 }
2583 }
2584
2585 return 0;
2586}
unsigned int prmatGetNV(PRMAT *mat)
Definition prmat.c:175
unsigned int prmatGetYCoord(PRMAT *mat, int row, int pix)
Definition prmat.c:327
unsigned int prmatGetXCoord(PRMAT *mat, int row, int pix)
Definition prmat.c:312
unsigned int prmatGetID(PRMAT *mat)
Definition prmat.c:197
float prmatGetFactor(PRMAT *mat, int row, int pix)
Definition prmat.c:342
unsigned int prmatGetPixels(PRMAT *mat, int row)
Definition prmat.c:282
unsigned int prmatGetNB(PRMAT *mat)
Definition prmat.c:186

Referenced by radonBackTransformPRM().

◆ radonBackTransformSA()

int radonBackTransformSA ( RADON * radtra,
int set,
int setNr,
float * scndata,
float * imgdata )

Same as 'radonBackTransform()' but discretisation model in this function is 'linear interpolation' or 'nearest neighbour interpolation' according to the given Radon transform object.

Parameters
radtracontains an initialized radon transform object.
settells which set is to be utilized; 0 < set < setNr-1
setNrnumber of subsets
scndatav x b vector contains the projections.
imgdatan x n vector for storing the back-projection.
Returns
int 0 if ok
Note
first written by Sakari Alenius 1998.

Definition at line 2419 of file radon.c.

2421 {
2422 float *imgptr, *scnptr, *imgorigin;
2423 float sinus, cosinus;
2424 float t; // distance between projection ray and origo.
2425 int mode, imgDim, binNr, viewNr, halfImg, centerBin, view;
2426 int x, y, xright, ybottom;
2427 float tpow2;
2428
2429 // Retrieve the data from given radon transform object.
2430 mode=radonGetMO(radtra); // Should be 3 or 4.
2431 imgDim=radonGetID(radtra);
2432 binNr=radonGetNB(radtra); // Should be equal to imgDim.
2433 viewNr=radonGetNV(radtra);
2434 // Set the center ray and the square of it.
2435 centerBin=binNr/2;
2436 tpow2 = centerBin*centerBin;
2437
2438 if(imgDim != binNr) return -1;
2439
2440 // Set half of the image dimension.
2441 halfImg = imgDim/2;
2442
2443 // Transform one angle at a time.
2444 for(view=set; view<viewNr; view+=setNr){
2445
2446 imgorigin = imgdata + imgDim*(halfImg - 1) + halfImg;
2447
2448 sinus = radonGetSin(radtra,view);
2449 cosinus = radonGetSin(radtra,viewNr/2 + view);
2450
2451 y = halfImg - 2;
2452
2453 if((float)y > centerBin){
2454 y = (int)(centerBin);
2455 ybottom = -y;
2456 } else{
2457 ybottom = -halfImg + 1;
2458 }
2459 for(; y >= ybottom; y--){
2460 xright =
2461 (int)sqrt(/*fabs(*/tpow2 - ((float)y+0.5) * ((float)y+0.5)/*)*/) + 1;
2462 if(xright >= halfImg){
2463 xright = halfImg - 1;
2464 x = -halfImg;
2465 }
2466 else
2467 x = -xright;
2468
2470 // t = centerBin - (float)y * sinus + ((float)(x + 1)) * cosinus;
2471 t = centerBin + (float)y * sinus + ((float)(x + 1)) * cosinus;
2472
2473 imgptr = imgorigin - y*imgDim + x;
2474 scnptr = scndata + view*binNr;
2475 for(; x <= xright; x++, t += cosinus){
2476 if(mode == 3){ // If the linear interpolation is to be utilised.
2477 *imgptr++ +=
2478 ( *(scnptr+(int)t) + (*(scnptr+(int)t+1) - *(scnptr+(int)t))
2479 * (t - (float)(int)t) );
2480 } else {// If the nearest neighbour interpolation is to be utilised.
2481 *imgptr++ += *(scnptr+(int)(t + 0.5)); /* (float)(1.0 / (float)views)*/
2482 }
2483 }
2484 }
2485 }
2486 return 0;
2487}

Referenced by radonBackTransformSA().

◆ radonEmpty()

void radonEmpty ( RADON * radtra)

Frees the memory allocated for radon transform. All data is cleared.

Postcondition
radon transform is emptied.
Parameters
radtrapointer to transform data to be emptied

Definition at line 27 of file radon.c.

28{
29 if(RADON_VERBOSE){
30 printf("RADON: radonEmpty() started. \n");
31 fflush(stdout);
32 }
33 //if radtra is already empty
34 if(radtra->status<RADON_STATUS_INITIALIZED){
35 if(RADON_VERBOSE){
36 printf("RADON: radon object already empty: status %i \n",radtra->status);
37 fflush(stdout);
38 }
39 //return;
40 }
41 //free the memory occupied by sine
42 free(radtra->sines);
43
44 if(RADON_VERBOSE){
45 printf("RADON: radonEmpty() finished. \n");
46 fflush(stdout);
47 }
48 return;
49}
float * sines
Definition libtpcrec.h:274

Referenced by radonEmpty().

◆ radonFwdTransform()

int radonFwdTransform ( RADON * radtra,
int set,
int setNr,
float * imgdata,
float * scndata )

Performs the perpendicular model of the radon transform for the given vector in spatial domain. The discretisation mode is chosen according to transform object, discretisation mode is 0 or 1. Transform is performed in those angles belonging in the given subset. The set of coincidence lines is divided into subsets in the following way: let i be the number of subsets, then every ith angle in the base set and the ones symmetrical with it belong to the same subset.

Precondition
imgdata contains pixel values for every pixel in dim*dim image grid
Postcondition
imgdata is mapped into the projection space.
Parameters
radtracontains an initialized radon transform object.
settells which set is to be utilized; 0 < set < setNr-1
setNrnumber of subsets
imgdatacontains pixel values for every pixel in dim*dim image grid.
scndataviewNr*binNr vector for storing the projection
Returns
int 0 if ok

Definition at line 216 of file radon.c.

218 {
219 float *imgptr, *scnptr; // pointers for the image and sinogram data
220 float *Y, *X, *Xptr, *Yptr; // pointers for the values of LOR in integer points
221 double sinus, cosinus, tanus; // sin, cosine and tangent
222 double shift_x, shift_y; // shift for LOR
223 double scalef; // scaling factor for angle
224 int xp, xn, yp, yn, z; //integer points
225 int x_left, x_right, y_top, y_bottom; // limits for fast search
226 int col, row, view, bin; //counters
227 int binNr, viewNr, imgDim, mode;
228 int half, center = -1;
229 float sdist;
230 float dx, dy , loi = 1; // delta x and y and length of intersection
231
232 if( RADON_VERBOSE ){
233 printf("RADON: radonFwdTransform() started.\n");
234 fflush(stdout);
235 }
236
237 // Check that the data for this radon transform is initialized.
238 if(radtra->status != RADON_STATUS_INITIALIZED) return -1;
239
240 // Retrieve the parameters from given radon transform object.
241 mode=radonGetMO(radtra);
242 imgDim=radonGetID(radtra);
243 binNr=radonGetNB(radtra);
244 viewNr=radonGetNV(radtra);
245 sdist=radonGetSD(radtra);
246 half=radonGetHI(radtra);
247 center=radonGetCB(radtra);
248
249 // Array for storing values f_x.
250 X=(float*)calloc(imgDim+1,sizeof(float));
251 // Array for storing values f_y.
252 Y=(float*)calloc(imgDim+1,sizeof(float));
253 if(X==NULL || Y==NULL){
254 return -2;
255 }
256 Xptr=X;
257 Yptr=Y;
258
259 imgptr=imgdata;
260 scnptr=scndata;
261
263 // Find pixel coordinates of the contributing pixels for lines of response
264 // belonging to first 1/4th of angles. From these pixel coordinates
265 // others can be calculated via symmetries in projection space.
266 // N.B. The line of response: a*x+b*y+c
267 // => solve y: y = (s - x*cos(theta))/sin(theta)
268 // solve x: x = (s - y*sin(theta))/cos(theta)
269
270 for(view=set; view<=viewNr/4; view=view+setNr){
271 // Choose the type of the line of response according to view number.
272
273 // view=0 -> sin(theta)=0
274 if(view==0){
275
276 // Length of intersection is 1.
277 loi = 1.;
278
279 // Choose column according to sample distance for angles 0 and pi/2.
280 col = 0;
281 for(bin=0; bin<half; bin++){
282 col = floor((float)(bin+.5*sdist)*sdist);
283
284 /* Iterate through the entries in the image matrix.
285 Calculate raysums for two LORs in the same distance from origin
286 (do halfturn). */
287 for(row=0; row<imgDim; row++) {
288
289 scnptr[bin] += loi * imgptr[row*imgDim + col];
290 if(bin != center)
291 scnptr[binNr-bin-1] += loi * imgptr[row*imgDim + (imgDim - 1 - col)];
292
293 scnptr[binNr*(viewNr/2) + bin] +=
294 loi * imgptr[(imgDim - 1 - col)*imgDim + row];
295 if(bin != center)
296 scnptr[binNr*(viewNr/2) + (binNr-bin-1)] +=
297 loi * imgptr[col*imgDim + row];
298 }
299
300 }
301 // End of view==0 (handles angles 0 and pi/2).
302 } else { // angles != 0
303
304 // Set sine and cosine for this angle.
305 sinus = (double)radonGetSin(radtra,view);
306 cosinus = (double)radonGetSin(radtra,viewNr/2 + view);
307 tanus = sinus/cosinus;
308
309 // Set shift from origin for the first line of response (-n/2,theta).
310 // NOTE that image matrix is on cartesian coordinate system where origin
311 // is in the middle and shift is in pixels.
312 shift_y = -(imgDim/2 -.5*sdist)/sinus;
313 shift_x = -(imgDim/2 -.5*sdist)/cosinus;
314
315 // Evaluate the function of the first LOR in integer points [-n/2,n/2].
316 // NOTE that image matrix is on cartesian coordinate system where origin
317 // is in the middle.
318 z=-imgDim/2;
319 for(col=0; col<imgDim+1; col++){
320 Yptr[col]=(float)(shift_y - z/tanus);
321 Xptr[col]=(float)(shift_x - z*tanus);
322 z++;
323 }
324
325 // Set shift from the first LOR.
326 shift_y = (double)(sdist/sinus);
327 shift_x = (double)(sdist/cosinus);
328
329 // Set scaling for angle.
330 scalef = sinus + cosinus;
331
332 // Iterate through half the bins in this view,
333 // and determine coordinates of pixels contributing to this LOR.
334 // NOTE that shift is added according to 'bin' in every loop.
335 // Calculate also the length of intersection.
336 // Others are determined via symmetry in projection space.
337
338 for(bin=0; bin<half; bin++) {
339
340 /* Set the number of intersected pixels to zero. */
341 /* np = 0; */
342
343 // Limit (x-)indices for fast search.
344 // Note that indices are non-negative integers.
345 x_left = floor((float)(Xptr[imgDim] + bin*shift_x + imgDim/2));
346 if(x_left < 0) x_left = 0;
347
348 x_right = floor((float)(Xptr[0] + bin*shift_x + imgDim/2));
349 if(x_right <= 0) x_right = 1;
350 if(x_right > imgDim) x_right = imgDim - 1;
351
352 /* Iterate through the values in vector Y, in integer points
353 [x_left,x_rigth]. */
354 for(z=x_left; z <= x_right; z++) {
355
356 xp = z; //positive x-coordinate
357 xn = imgDim - 1 - xp; //negative x-coordinate
358
359 // Look y from left. yp=positive y-coordinate
360 yp = imgDim/2 - floor(Yptr[xp + 1] + bin*shift_y) - 1;
361 yn = imgDim - 1 - yp;
362
363 // If the y-value for this x (z) is inside the image grid.
364 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
365 xp < imgDim && xn < imgDim && xn >= 0)
366 {
367
368 if(!mode) {
369 loi = 1;
370 } else {
371 // Compute delta x and y.
372 dx = fabs((float)(xp + 1 - (imgDim/2 + Xptr[imgDim - yp] +
373 bin*shift_x)));
374 dy = fabs((float)(floor(Yptr[xp + 1] + bin*shift_y) + 1 -
375 (Yptr[xp + 1] + bin*shift_y)));
376 if(dx > 1 || dx < 0) dx = 1;
377 if(dy > 1 || dy < 0) dy = 1;
378 loi = sqrt(dx*dx + dy*dy);
379 }
380 // Case: theta.
381 // Add img(x,y)*k to the raysum of LOR (view,bin)
382 scnptr[view*binNr + bin] += loi * imgptr[yp*imgDim + xp];
383 if(bin != center)
384 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
385 scnptr[view*binNr + binNr - 1 - bin] +=
386 loi * imgptr[yn*imgDim + xn];
387
388 if(view != viewNr/4) {
389 // Mirror the original LOR on y-axis, i.e. x->-x
390 // Case: pi-theta.
391 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
392 scnptr[(viewNr - view)*binNr + bin] +=
393 loi * imgptr[yp*imgDim + xn];
394 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
395 if(bin != center)
396 scnptr[(viewNr-view)*binNr + binNr - 1 - bin] +=
397 loi * imgptr[yn*imgDim + xp];
398
399 // Mirror the LOR on line x=y, i.e. x->y.
400 // Case: pi/2-theta
401 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,bin)
402 scnptr[(viewNr/2 - view)*binNr + bin] +=
403 loi * imgptr[xn*imgDim + yn];
404 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
405 if(bin != center)
406 scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] +=
407 loi * imgptr[xp*imgDim + yp];
408 }
409
410 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
411 // Case: pi/2+theta
412 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
413 scnptr[(viewNr/2 + view)*binNr + bin] +=
414 loi * imgptr[xn*imgDim + yp];
415 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,binNr-bin)
416 if(bin != center)
417 scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] +=
418 loi * imgptr[xp*imgDim + yn];
419 }
420 }
421
422 // Limit (y-)indices for fast search.
423 // Note that indices are non-negative integers.
424 y_bottom = floor((float)(Yptr[imgDim] + bin*shift_y + imgDim/2));
425 if(y_bottom < 0) y_bottom = 0;
426 if(y_bottom > imgDim) y_bottom = 0;
427
428 y_top = floor((float)(Yptr[0] + bin*shift_y + imgDim/2));
429 if(y_top > imgDim) y_top = imgDim-1;
430 if(y_top <= 0) y_top = 1;
431
432 /* Iterate through the values in vector X, in integer points
433 [y_bottom,y_top]. */
434 for(z=y_top; z >= y_bottom; z--) {
435
436 // Look y from this location.
437 xp = floor(Xptr[z] + bin*shift_x) + imgDim/2;
438 xn = imgDim - 1 - xp;
439
440 yp = imgDim - z - 1;
441 yn = imgDim - yp - 1;
442
443 // If the x-value for this y (z) is inside the image grid.
444 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
445 xp < imgDim && xn < imgDim && xn >= 0)
446 {
447
448 if(!mode) {
449 loi = 1;
450 } else {
451 dx = (float)(Xptr[z] + bin*shift_x + imgDim/2 - xp);
452 dy = (float)(Yptr[xp] + bin*shift_y - z + imgDim/2);
453 if(dy > 1 || dy < 0){
454 dx = dx - (float)(Xptr[z+1] + bin*shift_x + imgDim/2 - xp);
455 dy = 1;
456 }
457 loi = sqrt(dx*dx + dy*dy);
458 }
459
460 // Case: theta.
461 // Add img(x,y)*k to the raysum of LOR (view,bin)
462 scnptr[view*binNr + bin] += loi * imgptr[yp*imgDim + xp];
463 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
464 if(bin != center)
465 scnptr[view*binNr + binNr - 1 - bin] +=
466 loi * imgptr[yn*imgDim + xn];
467
468 if(view != viewNr/4) {
469 // Mirror the LOR on y-axis, i.e. x->-x
470 // Case: pi-theta.
471 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
472 scnptr[(viewNr - view)*binNr + bin] += loi * imgptr[yp*imgDim + xn];
473 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
474 if(bin != center)
475 scnptr[(viewNr-view)*binNr + binNr - 1 - bin] +=
476 loi * imgptr[yn*imgDim + xp];
477
478 // Mirror the LOR on line y=x, i.e. y->x.
479 // Case: pi/2 - theta.
480 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin)
481 scnptr[(viewNr/2 - view)*binNr + bin] +=
482 loi * imgptr[xn*imgDim + yn];
483 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
484 if(bin != center)
485 scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] +=
486 loi * imgptr[xp*imgDim + yp];
487 }
488
489 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
490 // Case: pi/2 + theta.
491 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
492 scnptr[(viewNr/2 + view)*binNr + bin] += loi * imgptr[xn*imgDim + yp];
493 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
494 if(bin != center)
495 scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] +=
496 loi * imgptr[xp*imgDim + yn];
497 }
498 }
499
500 // If mode==0 scale with sin(theta)+cos(theta).
501 if(mode==0) {
502 // Case: theta.
503 scnptr[view*binNr + bin] /= scalef;
504 if(bin != center)
505 scnptr[view*binNr + binNr - 1 - bin] /= scalef;
506
507 if(view != viewNr/4){
508 // Mirror the LOR on y-axis, i.e. x->-x
509 // Case: pi-theta.
510 scnptr[(viewNr - view)*binNr + bin] /= scalef;
511 if(bin != center)
512 scnptr[(viewNr-view)*binNr + binNr - 1 - bin] /= scalef;
513
514 // Mirror the LOR on line y=x, i.e. y->x.
515 // Case: pi/2 - theta.
516 scnptr[(viewNr/2 - view)*binNr + bin] /= scalef;
517 if(bin != center)
518 scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] /= scalef;
519 }
520
521 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
522 // Case: pi/2 + theta.
523 scnptr[(viewNr/2 + view)*binNr + bin] /= scalef;
524 if(bin != center)
525 scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] /= scalef;
526 }
527 }// END of X loop
528 }// End of view>0.
529 }// END OF VIEW LOOP
530 free(X);
531 free(Y);
532
533 if(RADON_VERBOSE) {
534 printf("RADON: radonFwdTransform() finished.\n");
535 fflush(stdout);
536 }
537
538 return 0;
539}// END OF FORWARD (spa -> pro) RADON TRANSFORM

Referenced by radonFwdTransform().

◆ radonFwdTransformEA()

int radonFwdTransformEA ( RADON * radtra,
int set,
int setNr,
float * imgdata,
float * scndata )

Same as 'radonFwdTransform()' but discretisation model in this function is 'exact area'.

Parameters
radtracontains an initialized radon transform object.
settells which set is to be utilized; 0 < set < setNr-1
setNrnumber of subsets
imgdatacontains pixel values for every pixel in dim*dim image grid.
scndataviewNr*binNr vector for storing the projection
Returns
int 0 if ok

Definition at line 549 of file radon.c.

551{
552 float *imgptr, *scnptr; // pointers for the image and sinogram data
553 float *Y, *X, *Xptr, *Yptr; // pointers for the values of LOR in integer points
554 double sinus, cosinus, tanus; // sin, cosine and tangent
555 double shift_x, shift_y; // shift for LOR
556 int xp, xn, yp, yn, z, xp2; //integer points
557 int x_left, x_right, y_top, y_bottom; // limits for fast search
558 int col, col1, col2, row, view, bin; //counters
559 int binNr, viewNr, imgDim, errors=0;
560 int half, center = -1;
561 float sdist;
562 float a=0,b=0, c=0, d=0, g=0, h=0, A;
563 float dx, dy , eps1 = 0, eps2 = 0, eps3 = 0; // delta x and y and factors.
564
565 if( RADON_VERBOSE ){
566 printf("RADON: radonFwdTransformEA() started.\n");
567 fflush(stdout);
568 }
569
570 // Check that the data for this radon transform is initialized.
571 if(radtra->status != RADON_STATUS_INITIALIZED) return -1;
572
573 // Retrieve the parameters from given radon transform object.
574 //mode=radonGetMO(radtra); // Should be 2.
575 imgDim=radonGetID(radtra);
576 binNr=radonGetNB(radtra);
577 viewNr=radonGetNV(radtra);
578 sdist=radonGetSD(radtra);
579 half=radonGetHI(radtra);
580 center=radonGetCB(radtra);
581
582 // Array for storing values f_x.
583 X=(float*)calloc(imgDim+1,sizeof(float));
584 // Array for storing values f_y.
585 Y=(float*)calloc(imgDim+1,sizeof(float));
586 if(X==NULL || Y==NULL){
587 return -2;
588 }
589 Xptr=X;
590 Yptr=Y;
591
592 imgptr=imgdata;
593 scnptr=scndata;
594
596 // Find pixel coordinates of the contributing pixels for tubes of response
597 // belonging to first 1/4th of angles. From these pixel coordinates
598 // others can be calculated via symmetries in projection space.
599 // N.B. The line of response: a*x+b*y+c
600 // => solve y: y = (s - x*cos(theta))/sin(theta)
601 // solve x: x = (s - y*sin(theta))/cos(theta)
602
603 for(view=set; view<=viewNr/4; view=view+setNr){
604 // Choose the type of the line of response according to view number.
605
606 // view=0 -> sin(theta)=0
607 if(view==0){
608
609 // Choose column(s) according to sample distance for angles 0 and pi/2.
610 col1 = 0;
611 col2 = 0;
612 for(bin = 0; bin < half; bin++){
613
614 col1 = col2;
615 col2 = floor((float)(bin + 1)*sdist);
616
617 // Determine factor epsilon.
618 if(col1 == col2){
619 eps1 = sdist;
620 eps2 = 0;
621 eps3 = 0;
622 }
623 if((col2-col1) == 1){
624 eps1 = (float)(col2 - (bin)*sdist);
625 eps2 = 0;
626 eps3 = (float)((bin+1)*sdist - col2);
627
628 }
629 // If sdist > pixel size!
630 if((col2-col1) > 1){
631 eps1 = (float)(col1 + 1 - (bin)*sdist);
632 eps2 = 1; // middle pixel.
633 eps3 = (float)((bin+1)*sdist - col2);
634
635 }
636
637 /* Iterate through the entries in the image matrix.
638 Calculate raysums for two LORs in the same distance from origin
639 (do halfturn). */
640 for(row=0; row<imgDim; row++) {
641
642 if(!eps3){
643 scnptr[bin] += eps1 * imgptr[row*imgDim + col1];
644 if(bin != center)
645 scnptr[binNr-bin-1] +=
646 eps1 * imgptr[row*imgDim + (imgDim - 1 - col1)];
647
648 scnptr[binNr*(viewNr/2) + bin] +=
649 eps1 * imgptr[(imgDim - 1 - col1)*imgDim + row];
650 if(bin != center)
651 scnptr[binNr*(viewNr/2) + (binNr-bin-1)] +=
652 eps1 * imgptr[col1*imgDim + row];
653 }
654
655 if(eps3 && !eps2){
656 scnptr[bin] += eps1 * imgptr[row*imgDim + col1] +
657 eps3 * imgptr[row*imgDim + col2];
658 if(bin != center)
659 scnptr[binNr-bin-1] +=
660 eps1 * imgptr[row*imgDim + (imgDim - 1 - col1)] +
661 eps3*imgptr[row*imgDim+(imgDim-1-col2)];
662
663 scnptr[binNr*(viewNr/2) + bin] +=
664 eps1*imgptr[(imgDim-1-col1)*imgDim+row] +
665 eps3*imgptr[(imgDim-1-col2)*imgDim+row];
666 if(bin != center)
667 scnptr[binNr*(viewNr/2) + (binNr-bin-1)] +=
668 eps1 * imgptr[col1*imgDim + row] +
669 eps3 * imgptr[col2*imgDim + row] ;
670 }
671
672 if(eps3 && eps2) {
673 for(col = col1; col<=col2; col++) {
674 if(col == col1){
675 scnptr[bin] += eps1 * imgptr[row*imgDim + col1];
676 if(bin != center)
677 scnptr[binNr-bin-1] += eps1 * imgptr[row*imgDim +
678 (imgDim - 1 - col1)];
679 scnptr[binNr*(viewNr/2) + bin] +=
680 eps1 * imgptr[(imgDim - 1 - col1)*imgDim + row];
681 if(bin != center)
682 scnptr[binNr*(viewNr/2) + (binNr-bin-1)] +=
683 eps1 * imgptr[col1*imgDim + row];
684 }
685 if(col == col2) {
686 scnptr[bin] += eps3 * imgptr[row*imgDim + col2];
687 if(bin != center)
688 scnptr[binNr-bin-1] += eps3 * imgptr[row*imgDim +
689 (imgDim - 1 - col2)];
690 scnptr[binNr*(viewNr/2) + bin] +=
691 eps3 * imgptr[(imgDim - 1 - col2)*imgDim + row];
692 if(bin != center)
693 scnptr[binNr*(viewNr/2) + (binNr-bin-1)] +=
694 eps3 * imgptr[col2*imgDim + row];
695 }
696 if(col != col1 && col != col2) {
697 scnptr[bin] += eps2 * imgptr[row*imgDim + col];
698 if(bin != center)
699 scnptr[binNr-bin-1] +=
700 eps2 * imgptr[row*imgDim + (imgDim - 1 - col)];
701 scnptr[binNr*(viewNr/2) + bin] +=
702 eps2 * imgptr[(imgDim - 1 - col)*imgDim + row];
703 if(bin != center)
704 scnptr[binNr*(viewNr/2) + (binNr-bin-1)] +=
705 eps2 * imgptr[col*imgDim + row];
706 }
707 }
708 }
709 }
710 }
711 // End of view==0 (handles angles 0 and pi/2).
712 } else {
713
714 // Set sine and cosine for this angle.
715 sinus = (double)radonGetSin(radtra,view);
716 cosinus = (double)radonGetSin(radtra,viewNr/2 + view);
717 tanus = sinus/cosinus;
718
719 // Set shift from origin for the first line of response (-n/2,theta).
720 // NOTE that image matrix is on cartesian coordinate system where origin
721 // is in the middle and shift is in pixels.
722 shift_y = -(imgDim/2)/sinus;
723 shift_x = -(imgDim/2)/cosinus;
724
725 // Evaluate the function of the first LOR in integer points [-n/2,n/2].
726 // NOTE that image matrix is on cartesian coordinate system where origin
727 // is in the middle.
728 z=-imgDim/2;
729 for(col=0; col<imgDim+1; col++){
730 Yptr[col]=(float)(-z/tanus + shift_y);
731 Xptr[col]=(float)(-z*tanus + shift_x);
732 z++;
733 }
734
735 // Set shift from the first TOR.
736 shift_y = (double)(sdist/sinus);
737 shift_x = (double)(sdist/cosinus);
738
739 // Iterate through half the bins in this view,
740 // and determine coordinates of pixels contributing to this TOR.
741 // NOTE that shift is added according to 'bin' in every loop.
742 // Others are determined via symmetry in projection space.
743
744 for(bin=0; bin<half; bin++){
745
746 // Limit (x-)indices for fast search.
747 // Note that indices are non-negative integers.
748
749 x_left = floor((float)(Xptr[imgDim] + bin*shift_x + imgDim/2));
750 if(x_left < 0) x_left = 0;
751
752 x_right = floor((float)(Xptr[0] + bin*shift_x + imgDim/2));
753 if(x_right <= 0) x_right = 1;
754 if(x_right > imgDim) x_right = imgDim - 1;
755
756 /* Iterate through the values in vector Y, in integer points
757 [x_left,x_rigth]. */
758 for(z=x_left; z <= x_right; z++) {
759
760 xp = z; //positive x-coordinate
761 xn = imgDim - 1 - xp; //negative x-coordinate
762
763 // Look y from left. yp=positive y-coordinate
764 yp = imgDim/2 - floor(Yptr[xp + 1] + bin*shift_y) - 1;
765 yn = imgDim - 1 - yp;
766
767 // If the y-value for this x (z) is inside the image grid.
768 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
769 xp < imgDim && xn < imgDim && xn >= 0)
770 {
771
772 /* NOTE that pixels found in this part are always hit from right
773 side. Compute a := |AF| and b := |FB|. */
774 a = (float)(xp + 1 - (imgDim/2 + Xptr[imgDim - yp] + bin*shift_x));
775 b = (float)(floor(Yptr[xp + 1] + bin*shift_y) + 1 - (Yptr[xp + 1] +
776 bin*shift_y));
777
778 // Calculate the area of lower triangle.
779 A = a*b/2;
780 // c := |FC|
781 c = (float)(xp + 1 - (imgDim/2 + Xptr[imgDim - yp] +
782 (bin+1)*shift_x));
783 if(c > 0){
784 // d := |FD|
785 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
786 (Yptr[xp + 1] + (bin+1)*shift_y));
787 // Subtract the area of upper triangle.
788 A = A - c*d/2;
789 }
790
791 eps1 = A;
792 if( (eps1 < 0 || eps1 > 1) && RADON_VERBOSE){
793 printf("RADON: Error in factor: eps1=%.5f \n",eps1);
794 errors++;
795 }
796
797 // Case: theta.
798 // Add img(x,y)*k to the raysum of TOR (view,bin)
799 scnptr[view*binNr + bin] += eps1 * imgptr[yp*imgDim + xp];
800 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
801 if(bin != center)
802 scnptr[view*binNr + binNr - 1 - bin] +=
803 eps1 * imgptr[yn*imgDim + xn];
804
805 if(view != viewNr/4){
806 // Mirror the original LOR on y-axis, i.e. x->-x
807 // Case: pi-theta.
808 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
809 scnptr[(viewNr - view)*binNr + bin] +=
810 eps1 * imgptr[yp*imgDim + xn];
811 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
812 if(bin != center)
813 scnptr[(viewNr-view)*binNr + binNr - 1 - bin] +=
814 eps1 * imgptr[yn*imgDim + xp];
815
816 // Mirror the LOR on line x=y, i.e. x->y.
817 // Case: pi/2-theta
818 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,bin)
819 scnptr[(viewNr/2 - view)*binNr + bin] +=
820 eps1 * imgptr[xn*imgDim + yn];
821 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
822 if(bin != center)
823 scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] +=
824 eps1 * imgptr[xp*imgDim + yp];
825 }
826
827 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
828 // Case: pi/2+theta
829 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
830 scnptr[(viewNr/2 + view)*binNr + bin] +=
831 eps1 * imgptr[xn*imgDim + yp];
832 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,binNr-bin)
833 if(bin != center)
834 scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] +=
835 eps1 * imgptr[xp*imgDim + yn];
836 }
837 }
838
839 // Limit (y-)indices for fast search.
840 // Note that indices are non-negative integers.
841 y_bottom = floor((float)(Yptr[imgDim] + bin*shift_y + imgDim/2));
842 if(y_bottom < 0) y_bottom = 0;
843 if(y_bottom > imgDim) y_bottom = 0;
844
845 y_top = floor((float)(Yptr[0] + bin*shift_y + imgDim/2));
846 if(y_top > imgDim) y_top = imgDim;
847 if(y_top <= 0) y_top = 1;
848
849 /* Iterate through the values in vector X, in integer points
850 [y_bottom,y_top]. */
851 for(z=y_top; z >= y_bottom; z--) {
852
853 // Look y from this location.
854 xp = floor(Xptr[z] + bin*shift_x) + imgDim/2;
855 xn = imgDim - 1 - xp;
856
857 yp = imgDim - z - 1;
858 yn = imgDim - yp - 1;
859
860 // If the x-value for this y (z) is inside the image grid.
861 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
862 xp < imgDim && xn < imgDim && xn >= 0)
863 {
864 eps1=eps2=eps3=0;
865 dx = (float)(Xptr[z] + bin*shift_x + imgDim/2 - xp);
866 dy = (float)(Yptr[xp] + bin*shift_y - z + imgDim/2);
867 if(dy < 1){ // Cases 3,4,5 and 6.
868 // 1. PART
869 // a := |HA|
870 a = dy;
871 // b := |HB| (b < 1 for angles in [0,pi/4))
872 b = dx;
873 // h := height of rectangle R.
874 h = a + shift_y;
875 if(h > 1){ // Cases 3,4 and 5.
876 h = 1;
877 g = b + shift_x;
878 if(g > 1){ // Cases 3 and 4.
879 g = 1;
880 xp2 =floor(Xptr[z+1] + (bin+1)*shift_x) + imgDim/2;
881 if(xp == xp2){ // Case 4.
882 // c := |FC|
883 c = (float)(xp + 1 - (imgDim/2 + Xptr[z+1] +
884 (bin+1)*shift_x));
885 // d := |FD|
886 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
887 (Yptr[xp + 1] + (bin+1)*shift_y));
888 eps1 = 1 - (a*b + c*d)/2;
889 eps2 = 0;
890 // Lower triangle on the next pixel (x+1,y).
891 eps3 = (1 - d)*(b + shift_x - 1)/2;
892 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
893 && RADON_VERBOSE) printf(
894 "4: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
895 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
896 } else { // Case 3.
897 // c=d=0.
898 eps1 = 1 - a*b/2;
899
900 // Calculate area on pixel in place (xp+1,yp-1).
901 dy = (float)(Yptr[xp+1] + (bin+1)*shift_y - (z + 1) +
902 imgDim/2);
903 if(dy < 1){ // Case 11.
904 // c := |HC|
905 c = dy;
906 // d := |HD|
907 d = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
908 (bin+1)*shift_x));
909 eps2 = c*d/2;
910 } else { // Cases 9 and 10.
911 dx = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
912 (bin+1)*shift_x));
913 if(dx < 1) { // Case 10.
914 // g := length of rectangle Q.
915 g = dx;
916 // c := |CD| (on x-axis).
917 c = dx - (float)(xp + 2 - (imgDim/2 + Xptr[z+2] +
918 (bin+1)*shift_x));
919 // Rectangle Q - triangle c*h (h = 1).
920 eps2 = g - c/2;
921 } else { // Case 9.
922 // c := |FC|
923 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+2] +
924 (bin+1)*shift_x));
925 // d := |FD|
926 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) + 2 -
927 (Yptr[xp + 2] + (bin+1)*shift_y));
928 // Rectangle Q - triangle CFD.
929 eps2 = 1 - c*d/2;
930 }
931 }
932
933 // Calculate area on pixel in place (xp+1,yp).
934 dx = (float)(xp + 2 - (imgDim/2 + Xptr[z] + (bin+1)*shift_x));
935 if(dx < 1){ // Case 10.
936 // g := length of rectangle Q.
937 g = dx;
938 // c := |CD| (on x-axis).
939 c = dx - (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
940 (bin+1)*shift_x));
941 // Rectangle Q - triangle c*h (h = 1).
942 eps3 = g - c/2;
943 } else { // Case 9.
944 // c := |FC|
945 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
946 (bin+1)*shift_x));
947 // d := |FD|
948 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) + 1 -
949 (Yptr[xp + 2] + (bin+1)*shift_y));
950 // Rectangle Q - triangle CFD.
951 eps3 = 1 - c*d/2;
952 }
953 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
954 && RADON_VERBOSE) printf(
955 "3/v%i: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
956 view,xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
957 }
958 } else { // Case 5. (g < 1)
959 // c := |DC|.
960 c = g - (imgDim/2 + Xptr[z+1] + (bin+1)*shift_x - xp);
961 // d := heigth
962 d = 1;
963 eps1 = g*h - (a*b + c*d)/2;
964 eps2 = 0;
965 eps3 = 0;
966 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
967 && RADON_VERBOSE) printf(
968 "5: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
969 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
970 }
971 } else{ // Case 6 (h <= 1).
972 // g := legth of rectangle R
973 g = b + shift_x;
974 if(g > 1) // Should always be < 1 for angles in [0,pi/4)
975 g = 1;
976 eps1 = (g*h - a*b)/2;
977 eps2 = 0;
978 eps3 = 0;
979 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1) &&
980 RADON_VERBOSE) printf(
981 "6: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
982 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
983 }
984 } else { // 2. PART
985 // Cases 2,7 and 8. (dy >= 1).
986 // a := |HA|
987 a = 1;
988 // b := |HB| (>=1)
989 b = dx - (float)(Xptr[z+1] + bin*shift_x + imgDim/2 - xp);
990 // h := heigth of rectangle R
991 h = 1;
992 // g := length of rectangle R
993 g = dx + shift_x;
994 if(g > 1){ // Cases 2 and 8.
995 g = 1 - (float)(Xptr[z+1] + bin*shift_x + imgDim/2 - xp);
996 // positive x-coordinate (bin+1)
997 xp2 = floor(Xptr[z+1] + (bin+1)*shift_x) + imgDim/2;
998 if(xp == xp2){ // Case 8.
999 // c := |FC|
1000 c = (float)(xp + 1 - (imgDim/2 + Xptr[z+1] +
1001 (bin+1)*shift_x));
1002 // d := |FD|
1003 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
1004 (Yptr[xp + 1] + (bin+1)*shift_y));
1005 eps1 = g*h - (a*b + c*d)/2;
1006 eps2 = 0;
1007 // Lower triangle on the next pixel (x+1,y).
1008 eps3 = (1 - d)*((Xptr[z] + (bin+1)*shift_x + imgDim/2) -
1009 (xp+1))/2;
1010 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
1011 && RADON_VERBOSE) printf(
1012 "8: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
1013 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
1014 } else{ // Case 2.
1015 // c=d=0.
1016 eps1 = g*h - a*b/2;
1017 /* Pixel in place (xp+1,yp-1) should have been found in
1018 the previous step. */
1019 eps2 = 0;
1020 // Calculate area on pixel in place (xp+1,yp).
1021 dx = (float)((imgDim/2 + Xptr[z] + (bin+1)*shift_x) - (xp+1));
1022 if(dx < 1){ // Case 10 (trapezium).
1023 // g := bottom of trapezium Q.
1024 g = dx;
1025 // c := top of trapezium Q.
1026 c = (float)((imgDim/2 + Xptr[z+1] + (bin+1)*shift_x) -
1027 (xp+1));
1028 // Area of trapezium Q. Heigth = 1.
1029 eps3 = (g + c)/2;
1030 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 ||
1031 eps3>1) && RADON_VERBOSE) printf(
1032 "2/10: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
1033 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
1034 } else { // Case 9.
1035 // c := |FC|
1036 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
1037 (bin+1)*shift_x));
1038 // d := |FD|
1039 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) + 1 -
1040 (Yptr[xp + 2] + (bin+1)*shift_y));
1041 // Rectangle Q - triangle CFD.
1042 eps3 = 1 - c*d/2;
1043 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 ||
1044 eps3>1) && RADON_VERBOSE) printf(
1045 "2/9: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
1046 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
1047 }
1048 }
1049 } else { // Case 7. (g < = 1)
1050 // Area of the parallelogram R.
1051 eps1 = sdist/cosinus;
1052 eps2 = 0;
1053 eps3 = 0;
1054 if((eps1<0 || eps1>1 || eps2<0 || eps2>1 || eps3<0 || eps3>1)
1055 && RADON_VERBOSE) printf(
1056 "7: (%i,%i) eps1=%f | (%i,%i) eps2=%f | (%i,%i) eps3=%f\n",
1057 xp,yp,eps1,xp+1,yp-1,eps2,xp+1,yp,eps3);
1058 }
1059 }
1060 if(!eps2 && !eps3){ // Cases 5,6 and 7.
1061 // Case: theta.
1062 // Add img(x,y)*k to the raysum of LOR (view,bin)
1063 scnptr[view*binNr + bin] += eps1 * imgptr[yp*imgDim + xp];
1064 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
1065 if(bin != center)
1066 scnptr[view*binNr + binNr - 1 - bin] +=
1067 eps1 * imgptr[yn*imgDim + xn];
1068 if(view != viewNr/4){
1069 // Mirror the LOR on y-axis, i.e. x->-x
1070 // Case: pi-theta.
1071 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
1072 scnptr[(viewNr - view)*binNr + bin] +=
1073 eps1 * imgptr[yp*imgDim + xn];
1074 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
1075 if(bin != center)
1076 scnptr[(viewNr-view)*binNr + binNr - 1 - bin] +=
1077 eps1 * imgptr[yn*imgDim + xp];
1078
1079 // Mirror the LOR on line y=x, i.e. y->x.
1080 // Case: pi/2 - theta.
1081 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin).
1082 scnptr[(viewNr/2 - view)*binNr + bin] +=
1083 eps1 * imgptr[xn*imgDim + yn];
1084 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
1085 if(bin != center)
1086 scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] +=
1087 eps1 * imgptr[xp*imgDim + yp];
1088 }
1089
1090 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
1091 // Case: pi/2 + theta.
1092 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
1093 scnptr[(viewNr/2 + view)*binNr + bin] +=
1094 eps1 * imgptr[xn*imgDim + yp];
1095 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
1096 if(bin != center)
1097 scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] +=
1098 eps1 * imgptr[xp*imgDim + yn];
1099 } else {
1100 if(!eps2) { // <=> eps3 != 0 & eps2 = 0 <=> Cases 3,4 and 8.
1101 if(xp + 1 < imgDim && xn - 1 >= 0){
1102 // Case: theta.
1103 // Add img(x,y)*k to the raysum of LOR (view,bin)
1104 scnptr[view*binNr + bin] +=
1105 eps1 * imgptr[yp*imgDim + xp] +
1106 eps3 * imgptr[yp*imgDim + xp+1];
1107 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
1108 if(bin != center)
1109 scnptr[view*binNr + binNr - 1 - bin] +=
1110 eps1 * imgptr[yn*imgDim + xn] +
1111 eps3 * imgptr[yn*imgDim + xn-1];
1112 if(view != viewNr/4) {
1113 // Mirror the LOR on y-axis, i.e. x->-x
1114 // Case: pi-theta.
1115 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
1116 scnptr[(viewNr - view)*binNr + bin] +=
1117 eps1 * imgptr[yp*imgDim + xn] +
1118 eps3 * imgptr[yp*imgDim + xn-1];
1119 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
1120 if(bin != center)
1121 scnptr[(viewNr-view)*binNr + binNr - 1 - bin] +=
1122 eps1 * imgptr[yn*imgDim + xp] +
1123 eps3 * imgptr[yn*imgDim + xp+1];
1124
1125 // Mirror the LOR on line y=x, i.e. y->x.
1126 // Case: pi/2 - theta.
1127 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin).
1128 scnptr[(viewNr/2 - view)*binNr + bin] +=
1129 eps1 * imgptr[xn*imgDim + yn] +
1130 eps3 * imgptr[(xn-1)*imgDim + yn];
1131 /* Add img(-y,-x)*k to the raysum of LOR
1132 (viewNr/2-view,binNr-bin) */
1133 if(bin != center)
1134 scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] +=
1135 eps1 * imgptr[xp*imgDim + yp] +
1136 eps3*imgptr[(xp+1)*imgDim+yp];
1137 }
1138 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
1139 // Case: pi/2 + theta.
1140 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
1141 scnptr[(viewNr/2 + view)*binNr + bin] +=
1142 eps1 * imgptr[xn*imgDim + yp] +
1143 eps3 * imgptr[(xn-1)*imgDim + yp];
1144 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
1145 if(bin != center)
1146 scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] +=
1147 eps1 * imgptr[xp*imgDim + yn] +
1148 eps3*imgptr[(xp+1)*imgDim+yn];
1149 }
1150 } else { // <=> eps2!=0 && eps3!=0 <=> Case 3.
1151 if(xp + 1 < imgDim && xn - 1 >= 0 && yp-1 >= 0 && yn+1 < imgDim) {
1152 // Case: theta.
1153 // Add img(x,y)*k to the raysum of LOR (view,bin)
1154 scnptr[view*binNr + bin] +=
1155 eps1 * imgptr[yp*imgDim + xp] +
1156 eps3 * imgptr[yp*imgDim + xp+1] +
1157 eps2 * imgptr[(yp-1)*imgDim + xp+1];
1158 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
1159 if(bin != center)
1160 scnptr[view*binNr + binNr - 1 - bin] +=
1161 eps1 * imgptr[yn*imgDim + xn] +
1162 eps3 * imgptr[yn*imgDim + xn-1] +
1163 eps2 * imgptr[(yn+1)*imgDim + xn-1];
1164
1165 if(view != viewNr/4){
1166 // Mirror the LOR on y-axis, i.e. x->-x
1167 // Case: pi-theta.
1168 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
1169 scnptr[(viewNr - view)*binNr + bin] +=
1170 eps1 * imgptr[yp*imgDim + xn] +
1171 eps3 * imgptr[yp*imgDim + xn-1] +
1172 eps2 * imgptr[(yp-1)*imgDim + xn-1];
1173 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
1174 if(bin != center)
1175 scnptr[(viewNr-view)*binNr + binNr - 1 - bin] +=
1176 eps1 * imgptr[yn*imgDim + xp] +
1177 eps3 * imgptr[yn*imgDim + xp+1] +
1178 eps2 * imgptr[(yn+1)*imgDim + xp+1];
1179
1180 // Mirror the LOR on line y=x, i.e. y->x.
1181 // Case: pi/2 - theta.
1182 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin)
1183 scnptr[(viewNr/2 - view)*binNr + bin] +=
1184 eps1 * imgptr[xn*imgDim + yn] +
1185 eps3 * imgptr[xn*imgDim + yn-1] +
1186 eps2 * imgptr[(xn-1)*imgDim + (yn+1)];
1187 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
1188 if(bin != center)
1189 scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] +=
1190 eps1 * imgptr[xp*imgDim + yp] +
1191 eps3*imgptr[(xp+1)*imgDim+yp] +
1192 eps2*imgptr[(xp+1)*imgDim+(yp-1)];
1193 }
1194
1195 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
1196 // Case: pi/2 + theta.
1197 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
1198 scnptr[(viewNr/2 + view)*binNr + bin] +=
1199 eps1 * imgptr[xn*imgDim + yp] +
1200 eps3 * imgptr[(xn-1)*imgDim + yp] +
1201 eps2 * imgptr[(xn-1)*imgDim + (yp-1)];
1202 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
1203 if(bin != center)
1204 scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] +=
1205 eps1 * imgptr[xp*imgDim + yn] +
1206 eps3*imgptr[(xp+1)*imgDim+yn] +
1207 eps2*imgptr[(xp+1)*imgDim+yn+1];
1208 }
1209 }
1210 }
1211 }
1212 }
1213 }// END of X loop
1214 }// End of view>0.
1215 }// END OF VIEW LOOP
1216 free(X);
1217 free(Y);
1218 if(RADON_VERBOSE) {
1219 printf("RADON: radonFwdTransformEA() finished with %d errors.\n", errors);
1220 fflush(stdout);
1221 }
1222 return 0;
1223} // END OF EXACT AREA FORWARD TRANSFORM

Referenced by radonFwdTransformEA().

◆ radonFwdTransformPRM()

int radonFwdTransformPRM ( PRMAT * mat,
int set,
int setNr,
float * imgdata,
float * scndata )

Transforms the given intensity image in spatial domain to Radon domain. Transform is calculated by multiplying with the given projection matrix from the left. Transform is calculated only in those angles belonging into given subset. Subset contains angles starting from the index 'set' with spacing 'setNr'. Discretisation model utilised in this function is '0/1', 'length of intersection' or 'exact area' according to the given projection matrix.

Precondition
imgdata contains pixel values for every pixel in n x n image grid
Postcondition
imgdata is mapped into the projection space.
Parameters
matcontains an initialised projection matrix
settells which set is to be utilized; 0 < set < setNr-1
setNrnumber of subsets (spacing between indices)
imgdatacontains pixel values for every pixel in dim*dim image grid.
scndataviewNr*binNr vector for storing the projection
Returns
int 0 if ok

Definition at line 1327 of file radon.c.

1329 {
1330 float *imgptr, *scnptr; // pointers for the image and sinogram data
1331 unsigned int imgDim=128, binNr=256, viewNr=192, view, bin, row, col;
1332 unsigned int half, center;
1333 int xp, xn, yp, yn;
1334 float fact;
1335
1336 // Retrieve the data from given projection matrix.
1337 imgDim=prmatGetID(mat);
1338 binNr=prmatGetNB(mat); // Should be equal to imgDim.
1339 viewNr=prmatGetNV(mat);
1340
1341 // Calculate and set the center bin.
1342 if((binNr%2) != 0){
1343 half = (binNr - 1)/2 + 1;
1344 center = half - 1;
1345 } else{
1346 half = binNr/2;
1347 // In the case binNr is even there is no center bin.
1348 center = -1;
1349 }
1350
1351 imgptr = imgdata;
1352 scnptr = scndata;
1353
1354 // Draw sinogram according to projection matrix.
1355 for(view=set; view<=viewNr/4; view=view+setNr){
1356 for(bin=0; bin<half; bin++){
1357 row = view*half + bin;
1358 for(col=0; col<prmatGetPixels(mat,row); col++){
1359
1360 fact = prmatGetFactor(mat,row,col);
1361 xp = prmatGetXCoord(mat,row,col);
1362 xn = imgDim - xp - 1;
1363
1364 yp = prmatGetYCoord(mat,row,col);
1365 yn = imgDim - yp - 1;
1366
1367 // Case: theta.
1368 // Add img(x,y)*k to the raysum of LOR (view,bin)
1369 scnptr[view*binNr + bin] += fact * imgptr[yp*imgDim + xp];
1370 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
1371 if(bin != center)
1372 scnptr[view*binNr + binNr - 1 - bin] += fact * imgptr[yn*imgDim + xn];
1373
1374 if(view != 0 && view != viewNr/4){
1375 // Mirror the LOR on y-axis, i.e. x->-x
1376 // Case: pi-theta.
1377 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
1378 scnptr[(viewNr - view)*binNr + bin] += fact * imgptr[yp*imgDim + xn];
1379 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
1380 if(bin != center)
1381 scnptr[(viewNr-view)*binNr + binNr - 1 - bin] +=
1382 fact * imgptr[yn*imgDim + xp];
1383
1384 // Mirror the LOR on line y=x, i.e. y->x.
1385 // Case: pi/2 - theta.
1386 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,bin)
1387 scnptr[(viewNr/2 - view)*binNr + bin] += fact * imgptr[xn*imgDim + yn];
1388 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
1389 if(bin != center)
1390 scnptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] +=
1391 fact * imgptr[xp*imgDim + yp];
1392 }
1393
1394 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
1395 // Case: pi/2 + theta.
1396 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
1397 scnptr[(viewNr/2 + view)*binNr + bin] += fact * imgptr[xn*imgDim + yp];
1398 // Add img(-y,x)*k to the raysum of LOR (viewNr-view,binNr-bin)
1399 if(bin != center)
1400 scnptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] +=
1401 fact * imgptr[xp*imgDim + yn];
1402 }
1403 }
1404 }
1405
1406 return 0;
1407
1408}// END OF FORWARD TRANSFORM WITH A PROJECTION MATRIX

Referenced by radonFwdTransformPRM().

◆ radonFwdTransformSA()

int radonFwdTransformSA ( RADON * radtra,
int set,
int setNr,
float * imgdata,
float * scndata )

Same as 'radonFwdTransform()' but discretisation model in this function is 'linear interpolation' or 'nearest neighbour interpolation' according to the given Radon transform object.

Parameters
radtracontains an initialized radon transform object.
settells which set is to be utilized; 0 < set < setNr-1
setNrnumber of subsets
imgdatacontains pixel values for every pixel in dim*dim image grid.
scndataviewNr*binNr vector for storing the projection
Returns
int 0 if ok
Note
First written by Sakari Alenius 1998.

Definition at line 1237 of file radon.c.

1239 {
1240 float *imgptr, *scnptr, *imgorigin;
1241 float sinus, cosinus;
1242 float t; // distance between projection ray and origo.
1243 int mode, imgDim, binNr, viewNr, halfImg, centerBin, view;
1244 int x, y, xright, ybottom;
1245 float fract, tpow2;
1246
1247 // Retrieve the data from given radon transform object.
1248 mode=radonGetMO(radtra); // Should be 3 or 4.
1249 imgDim=radonGetID(radtra);
1250 binNr=radonGetNB(radtra); // Should be equal to imgDim.
1251 viewNr=radonGetNV(radtra);
1252 // Set the center ray and the square of it.
1253 centerBin=binNr/2;
1254 tpow2 = centerBin*centerBin;
1255
1256 if(imgDim != binNr) return -1;
1257
1258 // Set half of the image dimension.
1259 halfImg = imgDim/2;
1260
1261 // Transform one angle at a time.
1262 for(view=set; view<viewNr; view+=setNr) {
1263
1264 imgorigin = imgdata + imgDim*(halfImg - 1) + halfImg;
1265
1266 sinus = radonGetSin(radtra,view);
1267 cosinus = radonGetSin(radtra,viewNr/2 + view);
1268
1269 y = halfImg - 2;
1270
1271 if((float)y > centerBin){
1272 y = (int)(centerBin);
1273 ybottom = -y;
1274 } else{
1275 ybottom = -halfImg + 1;
1276 }
1277
1278 for(; y >= ybottom; y--) {
1279 xright = (int)sqrt(/*fabs(*/tpow2 - ((float)y+0.5) *
1280 ((float)y+0.5)/*)*/) + 1;
1281 if(xright >= halfImg){
1282 xright = halfImg - 1;
1283 x = -halfImg;
1284 } else
1285 x = -xright;
1286
1288 // t = centerBin - (float)y * sinus + ((float)(x + 1)) * cosinus;
1289 t = centerBin + (float)y * sinus + ((float)(x + 1)) * cosinus;
1290
1291 imgptr = imgorigin - y*imgDim + x;
1292 scnptr = scndata + view*binNr;
1293 // for(; x <= xright; x++, t += cosinus){
1294 for(; x <= xright; x++, t += cosinus){
1295 if(mode == 3){ // If the linear interpolation is to be utilised.
1296 fract = t - (float)(int)t;
1297 *(scnptr+(int)t) += *imgptr * (1.0 - fract);
1298 *(scnptr+(int)t + 1) += *imgptr++ * fract;
1299 }
1300 else // If the nearest neighbour interpolation is to be utilised.
1301 *(scnptr+(int)(t + 0.5)) += *imgptr++;
1302 }
1303 }
1304 }
1305
1306 return 0;
1307}// END OF FORWARD TRANSFORM USING THE IMAGE ROTATION APPROACH

Referenced by radonFwdTransformSA().

◆ radonGetCB()

int radonGetCB ( RADON * radtra)

Returns the center bin in this radon transform.

Parameters
radtraradon transform for which the center bin is to be returned.
Returns
int index of the center bin.

Definition at line 180 of file radon.c.

181{
182 return radtra->centerBin;
183}
int centerBin
Definition libtpcrec.h:269

Referenced by radonBackTransform(), radonBackTransformEA(), radonFwdTransform(), radonFwdTransformEA(), radonGetCB(), and radonSetLUT().

◆ radonGetHI()

int radonGetHI ( RADON * radtra)

Returns the half index of the bins in this radon transform.

Parameters
radtraradon transform for which the half index is to be returned.
Returns
int half index of the bins.

Definition at line 169 of file radon.c.

170{
171 return radtra->half;
172}
int half
Definition libtpcrec.h:267

Referenced by radonBackTransform(), radonBackTransformEA(), radonFwdTransform(), radonFwdTransformEA(), radonGetHI(), radonSetBases(), radonSetBasesEA(), and radonSetLUT().

◆ radonGetID()

int radonGetID ( RADON * radtra)

Returns the image dimension in this radon transform.

Parameters
radtraradon transform for which the image dimension is to be returned.
Returns
int image dimension.

Definition at line 128 of file radon.c.

129{
130 return radtra->imgDim;
131}
int imgDim
Definition libtpcrec.h:261

Referenced by radonBackTransform(), radonBackTransformEA(), radonBackTransformSA(), radonFwdTransform(), radonFwdTransformEA(), radonFwdTransformSA(), radonGetID(), radonSetBases(), radonSetBasesEA(), radonSetLORS(), and radonSetLUT().

◆ radonGetMO()

int radonGetMO ( RADON * radtra)

Returns the discretization model of this radon transform.

Parameters
radtraradon transform for which the mode is to be returned.
Returns
int mode

Definition at line 119 of file radon.c.

120{
121 return radtra->mode;
122}
char mode
Definition libtpcrec.h:259

Referenced by radonBackTransform(), radonBackTransformSA(), radonFwdTransform(), radonFwdTransformSA(), radonGetMO(), radonSetBases(), and radonSetBasesEA().

◆ radonGetNB()

int radonGetNB ( RADON * radtra)

Returns the number of bins in this radon transform.

Parameters
radtraradon transform for which the number of bins is to be returned.
Returns
int number of bins.

Definition at line 148 of file radon.c.

149{
150 return radtra->binNr;
151}
int binNr
Definition libtpcrec.h:265

Referenced by radonBackTransform(), radonBackTransformEA(), radonBackTransformSA(), radonFwdTransform(), radonFwdTransformEA(), radonFwdTransformSA(), radonGetNB(), radonSetBases(), radonSetBasesEA(), radonSetLORS(), and radonSetLUT().

◆ radonGetNV()

int radonGetNV ( RADON * radtra)

Returns the number of views in this radon transform.

Parameters
radtraradon transform for which the number of views is to be returned.
Returns
int number of views.

Definition at line 138 of file radon.c.

139{
140 return radtra->viewNr;
141}
int viewNr
Definition libtpcrec.h:263

Referenced by radonBackTransform(), radonBackTransformEA(), radonBackTransformSA(), radonFwdTransform(), radonFwdTransformEA(), radonFwdTransformSA(), radonGetNV(), radonSetBases(), radonSetBasesEA(), radonSetLORS(), and radonSetLUT().

◆ radonGetSD()

float radonGetSD ( RADON * radtra)

Returns the sample distance in this radon transform.

Parameters
radtraradon transform for which the sample distance is to be returned.
Returns
float sample distance.

Definition at line 159 of file radon.c.

160{
161 return radtra->sampleDist;
162}
float sampleDist
Definition libtpcrec.h:271

Referenced by radonBackTransform(), radonBackTransformEA(), radonFwdTransform(), radonFwdTransformEA(), radonGetSD(), radonSetBases(), radonSetBasesEA(), and radonSetLUT().

◆ radonGetSin()

float radonGetSin ( RADON * radtra,
int nr )

Returns the sine for given angle (index).

Parameters
radtraradon transform for which the sine is to be returned.
nrindex of the angle to be returned (angle=nr*pi/radonGetNB(RADON)).
Returns
float sin(nr*pi/binNr).

Definition at line 192 of file radon.c.

193{
194 return radtra->sines[nr];
195}

Referenced by radonBackTransform(), radonBackTransformEA(), radonBackTransformSA(), radonFwdTransform(), radonFwdTransformEA(), radonFwdTransformSA(), radonGetSin(), radonSetBases(), and radonSetBasesEA().

◆ radonSet()

int radonSet ( RADON * radtra,
int mode,
int imgDim,
int viewNr,
int binNr )

Sets the data for the 2-D Radon transform.

Precondition
dim > 0
Postcondition
Parameters for the radon transform are set
Parameters
radtraradon transform for which the paramaters are to be set
modediscretisation mode
imgDimimage dimension
viewNrNumber of views (angles)
binNrNumber of bins (distances)
Returns
0 if ok

Definition at line 62 of file radon.c.

63{
64 int i;
65
66 if( RADON_VERBOSE ){
67 printf("RADON: radonSet() started.\n");
68 fflush(stdout);
69 }
70
71 // Set the parameters.
72 radtra->mode=mode;
73
74 if(imgDim <= 0) return -1;
75 else radtra->imgDim=imgDim;
76
77 if(viewNr <= 0) return -2;
78 else radtra->viewNr=viewNr;
79
80 if(binNr <= 0) return -3;
81 else radtra->binNr=binNr;
82
83 radtra->sampleDist=(float)imgDim/(float)binNr;
84
85 // Calculate and set center bin for current geometrics.
86 if((binNr%2) != 0){
87 radtra->half = (binNr - 1)/2 + 1;
88 radtra->centerBin = radtra->half - 1;
89 } else {
90 radtra->half = binNr/2;
91 // In the case binNr is even there is no center bin.
92 radtra->centerBin = -1;
93 }
94
95 /* Set the sine table to contain values of sine to cover the required values
96 of cosine as well. */
97 radtra->sines=(float*)calloc(3*viewNr/2,sizeof(float));
98 if(radtra->sines==NULL) return -5;
99 //Put the values sin(view*pi/viewNr) for view=0:3*viewNr/2 - 1 in the table
100 for(i=0; i< 3*viewNr/2; i++) {
101 radtra->sines[i]=(float)sin((M_PI/(double)viewNr) * (double)i);
102 }
103 radtra->status=RADON_STATUS_INITIALIZED;
104
105 if( RADON_VERBOSE ){
106 printf("RADON: radonSet() done.\n");
107 fflush(stdout);
108 }
109 return 0;
110}

Referenced by radonSet().

◆ radonSetBases()

int radonSetBases ( RADON * radtra,
ELLIPSE * elli,
PRMAT * mat )

Sets the coordinates and factors for intersected pixels according to given special Radon transform operator for every coincidence line in the BASE set. Base set includes coincidence lines in range [0,pi/4].

Precondition
radtra is a radon transform operator && elli defines a field of view && mat is initialized.
Postcondition
coordinates and factors for pixels contributing to coincidence lines in the base set.
Parameters
radtraspecial Radon transform operator.
ellifield of view.
matpointer to the datastructure where coordinates and values are to be stored.
Returns
0 if ok.

Definition at line 2606 of file radon.c.

2608 {
2609 // temporary pointers for storing the coordinates and factors
2610 unsigned short int **coords, *factors, **coptr, *facptr;
2611 // pointers for the values of LOR in integer points
2612 float *Y, *X, *Xptr, *Yptr;
2613 double sinus, cosinus, tanus; // sin, cosine and tangent
2614 double shift_x, shift_y; // shift for LOR
2615 int xp, xn, yp, yn, z; //integer points
2616 int x_left, x_right, y_top, y_bottom; // limits for fast search
2617 int col, row, view, bin, pix; //counters
2618 int binNr, viewNr, imgDim, views, rows, mode, half; // properties
2619 float diam, sdist;
2620 float scale, sum=0, sqr_sum=0, min=0, max=0;
2621 float dx, dy , loi = 1; // delta x and y and length of intersection
2622
2623 // Check that the data for this radon transform is initialized.
2624 if(radtra->status != RADON_STATUS_INITIALIZED) return -1;
2625
2626 // Retrieve the data from given radon transform object.
2627 mode=radonGetMO(radtra);
2628 imgDim=radonGetID(radtra);
2629 binNr=radonGetNB(radtra);
2630 viewNr=radonGetNV(radtra);
2631 sdist=radonGetSD(radtra);
2632 half=radonGetHI(radtra);
2633
2634 // Set information in the projection matrix data stucture.
2635 if(binNr == 192) {
2636 mat->type=PRMAT_TYPE_ECAT931;
2637 } else if(binNr == 281){
2638 mat->type=PRMAT_TYPE_GE;
2639 } else
2640 mat->type=PRMAT_TYPE_NA;
2641
2642 mat->viewNr=viewNr;
2643 mat->binNr=binNr;
2644 mat->imgDim=imgDim;
2645
2646 mat->mode = mode;
2647 // Allocate memory in PRMAT struct and set fov.
2648 mat->prmatfov = (int*)calloc(2,sizeof(int));
2649 mat->prmatfov[0] = ellipseGetMajor(elli);
2650 mat->prmatfov[1] = ellipseGetMinor(elli);
2651
2652 // rows := number of lines in the base set = (views*half)
2653 views = viewNr/4 + 1;
2654 rows = views*half;
2655
2656 mat->factor_sqr_sum=calloc(rows,sizeof(float));
2657 mat->dimr=rows;
2658 //entries in one line
2659 mat->dime=calloc(rows,sizeof(int));
2660 mat->_factdata=(unsigned short int***)calloc(rows,sizeof(unsigned short int**));
2661 //if not enough memory
2662 if(!mat->_factdata || !mat->dime) return(4);
2663
2664 // Compute scaling factor, assuming that maximum value is 1.
2665 scale=65534./1;
2666 mat->scaling_factor=1./scale; //is the inverse of scale
2667
2668 /* Allocate (temporary) coordinate and factor arrays to maximum size
2669 (= 2*imgDim).
2670 Coords contains pairs (x,y), coordinates in cartesian coordinate system. */
2671 coords = (unsigned short int**)calloc(2*imgDim,sizeof(unsigned short int*));
2672 factors = (unsigned short int*)calloc(2*imgDim,sizeof(unsigned short int));
2673 if(!coords || !factors) return 5;
2674
2675 for(col=0; col<2*imgDim; col++){
2676 coords[col] = (unsigned short int*)calloc(2,sizeof(unsigned short int));
2677 if(!coords[col]) return -1;
2678 }
2679
2680 coptr = coords;
2681 facptr = factors;
2682
2684 // Set diameter of a pixel.
2685 diam = sqrt(2);
2686
2687 // Array for storing values A_x.
2688 X=(float*)calloc(imgDim+1,sizeof(float));
2689 // Array for storing values A_y.
2690 Y=(float*)calloc(imgDim+1,sizeof(float));
2691 if(X==NULL || Y==NULL){
2692 return -2;
2693 }
2694 Xptr=X;
2695 Yptr=Y;
2696
2698 // Find pixel coordinates of the contributing pixels for lines of response
2699 // belonging to first 1/4th of angles. From these pixel coordinates
2700 // others can be calculated via symmetries in projection space.
2701 // N.B. The line of response: a*x+b*y+c
2702 // => solve y: y=-x/tan(view) + s*(cos(theta)/tan(theta) + sin(theta))
2703 // solve x: x=-y*tan(theta) + s*(sin(theta)*tan(theta) + cos(theta))
2704
2705 for(view=0; view<views; view++){
2706 // Angle theta=0 -> sin(theta)=0.
2707 if(view==0){
2708
2709 //If the mode switch is on zero do the 0-1 model transform.
2710 if(mode == 0)
2711 loi = 1.;
2712 else
2713 loi=1/diam;
2714
2715 // Choose column according to sample distance for angle 0.
2716 col = 0;
2717 for(bin=0; bin<half; bin++){
2718 col = floor((float)(bin+.5*sdist)*sdist);
2719
2720 pix = 0; // length of list pixels (and factors)
2721 sqr_sum = 0;
2722
2723 // Iterate through the entries in the image matrix.
2724 // Set factors for pixels intersected by lines in the base set.
2725 for(row=0; row<imgDim; row++){
2726
2727 /* Check that pixel and pixels hit by symmetrical lines lay inside
2728 the FOV. */
2729 if(ellipseIsInside(elli,row,col) && ellipseIsInside(elli,row,imgDim -
2730 1 - col) && ellipseIsInside(elli,imgDim-1-col,row) &&
2731 ellipseIsInside(elli,col,row))
2732 {
2733 coptr[pix][0] = (unsigned short int)col;
2734 coptr[pix][1] = (unsigned short int)row;
2735 // Convert loi to unsigned short int.
2736 facptr[pix] = (unsigned short int)(scale*loi);
2737 // Look for minimal and maximal factor.
2738 if(min>loi) min=loi;
2739 if(max<loi) max=loi;
2740 // Compute square sums in every row.
2741 sqr_sum += loi*loi;
2742 sum += loi;
2743 pix++;
2744 }
2745 }
2746
2747 /* Allocate memory in factor pointer (dynamically according to number
2748 of pixels intersected). */
2749 if(pix){
2750 mat->_factdata[bin]=
2751 (unsigned short int**)calloc(pix,sizeof(unsigned short int*));
2752 if(!mat->_factdata[bin]) return -1;
2753 }
2754
2755 // Allocate leaves.
2756 for(col=0; col<pix; col++) {
2757 mat->_factdata[bin][col]=
2758 (unsigned short int*)calloc(3,sizeof(unsigned short int));
2759 if(!mat->_factdata[bin][col]) return -1;
2760 }
2761
2762 // Put now values in coordinates and factors array to result pointer.
2763 mat->fact = mat->_factdata;
2764 for(col=0; col<pix; col++) {
2765 mat->fact[bin][col][0] = coptr[col][0]; // x-coodinate
2766 mat->fact[bin][col][1] = coptr[col][1]; // y-coordinate
2767 mat->fact[bin][col][2] = facptr[col]; // factor
2768 }
2769
2770 //Set also the number of pixels belonging to each row and square sums.
2771 mat->dime[bin]=pix;
2772 mat->factor_sqr_sum[bin]=sqr_sum;
2773
2774 } // END OF BIN-LOOP FOR ANGLE 0.
2775 // End of view=0.
2776 } else {
2777
2778 // Set sine and cosine for this angle.
2779 sinus = (double)radonGetSin(radtra,view);
2780 cosinus = (double)radonGetSin(radtra,viewNr/2 + view);
2781 tanus = sinus/cosinus;
2782
2783 // Set shift from origin for the first line of response (-n/2,theta).
2784 // NOTE that image matrix is on cartesian coordinate system where origin
2785 // is in the middle and shift is in pixels.
2786 shift_y = -(imgDim/2 -.5*sdist)/sinus;
2787 shift_x = -(imgDim/2 -.5*sdist)/cosinus;
2788
2789 // Evaluate the function of the first LOR in integer points [-n/2,n/2].
2790 // NOTE that image matrix is on cartesian coordinate system where origin
2791 // is in the middle.
2792 z=-imgDim/2;
2793 for(col=0; col<imgDim+1; col++){
2794 Yptr[col]=(float)(shift_y - z/tanus);
2795 Xptr[col]=(float)(shift_x - z*tanus);
2796 z++;
2797 }
2798
2799 // Set shift from the first LOR.
2800 shift_y = (double)(sdist/sinus);
2801 shift_x = (double)(sdist/cosinus);
2802
2803 // Iterate through half the bins in this view,
2804 // and determine coordinates of pixels contributing to this LOR.
2805 // NOTE that shift is added according to 'bin' in every loop.
2806 // Calculate also the length of intersection.
2807 // Others are determined via symmetry in projection space.
2808
2809 for(bin=0; bin<half; bin++){
2810
2811 coptr = coords;
2812 facptr = factors;
2813 pix = 0;
2814 sqr_sum = 0;
2815
2816 // Limit (x-)indices for fast search.
2817 // Note that indices are non-negative integers.
2818
2819 x_left = floor((float)(Xptr[imgDim] + bin*shift_x + imgDim/2));
2820 if(x_left < 0) x_left = 0;
2821
2822 x_right = floor((float)(Xptr[0] + bin*shift_x + imgDim/2));
2823 if(x_right <= 0) x_right = 1;
2824 if(x_right > imgDim) x_right = imgDim - 1;
2825
2826 /* Iterate through the values in vector Y, in integer points
2827 [x_left,x_rigth]. */
2828 for(z=x_left; z <= x_right; z++) {
2829
2830 xp = z; //positive x-coordinate
2831 xn = imgDim - 1 - xp; //negative x-coordinate
2832
2833 // Look y from left.
2834 yp = imgDim/2 - floor(Yptr[xp + 1] + bin*shift_y) - 1;
2835 yn = imgDim - 1 - yp;
2836
2837 // If the y-value for this x (z) is inside the image grid.
2838 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
2839 xp < imgDim && xn < imgDim && xn >= 0) {
2840
2841 if(!mode) {
2842 loi = 1;
2843 } else {
2844 // Compute delta x and y.
2845 dx = (float)(xp + 1 - (imgDim/2 + Xptr[imgDim - yp] + bin*shift_x));
2846 dy = (float)(floor(Yptr[xp + 1] + bin*shift_y) + 1 -
2847 (Yptr[xp + 1] + bin*shift_y));
2848 if(dx > 1 || dx < 0) dx = 1;
2849 if(dy > 1 || dy < 0) dy = 1;
2850 loi = sqrt(dx*dx + dy*dy);
2851 loi=loi/diam;
2852 }
2853
2854 /* Check that pixel and pixels hit by symmetrical lines lay inside
2855 the FOV. */
2856 if(ellipseIsInside(elli,yp,xp) && ellipseIsInside(elli,yn,xn) &&
2857 ellipseIsInside(elli,yp,xn) && ellipseIsInside(elli,yn,xp) &&
2858 ellipseIsInside(elli,xn,yn) && ellipseIsInside(elli,xp,yp) &&
2859 ellipseIsInside(elli,xn,yp) && ellipseIsInside(elli,xp,yn)) {
2860
2861 // Put coordinates and factors in the list.
2862 coptr[pix][0] = xp;
2863 coptr[pix][1] = yp;
2864 facptr[pix] = (unsigned short int)(scale*loi);
2865
2866 // Look for minimal and maximal factor.
2867 if(min>loi) min=loi;
2868 if(max<loi) max=loi;
2869 sqr_sum += loi*loi;
2870 sum += loi;
2871 pix++;
2872 }
2873 }
2874 }
2875
2876 // Limit (y-)indices for fast search.
2877 // Note that indices are non-negative integers.
2878 y_bottom = floor((float)(Yptr[imgDim] + bin*shift_y + imgDim/2));
2879 if(y_bottom < 0) y_bottom = 0;
2880 if(y_bottom > imgDim) y_bottom = 0;
2881
2882 y_top = floor((float)(Yptr[0] + bin*shift_y + imgDim/2));
2883 if(y_top > imgDim) y_top = imgDim-1;
2884 if(y_top <= 0) y_top = 1;
2885
2886 /* Iterate through the values in vector X, in integer points
2887 [y_bottom,y_top]. */
2888 for(z=y_top; z >= y_bottom; z--) {
2889
2890 // Look y from this location.
2891 xp = floor(Xptr[z] + bin*shift_x) + imgDim/2;
2892 xn = imgDim - 1 - xp;
2893
2894 yp = imgDim - z - 1;
2895 yn = imgDim - yp - 1;
2896
2897 // If the x-value for this y (z) is inside the image grid.
2898 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
2899 xp < imgDim && xn < imgDim && xn >= 0) {
2900
2901 if(!mode){
2902 loi = 1;
2903 } else {
2904 dx = (float)(Xptr[z] + bin*shift_x + imgDim/2 - xp);
2905 dy = (float)(Yptr[xp] + bin*shift_y - z + imgDim/2);
2906 if(dy > 1 || dy < 0) {
2907 dx = dx - (float)(Xptr[z+1] + bin*shift_x + imgDim/2 - xp);
2908 dy = 1;
2909 }
2910 loi = sqrt(dx*dx + dy*dy)/diam;
2911 }
2912
2913 /* Check that pixel and pixels hit by symmetrical lines lay inside
2914 the FOV. */
2915 if(ellipseIsInside(elli,yp,xp) && ellipseIsInside(elli,yn,xn) &&
2916 ellipseIsInside(elli,yp,xn) && ellipseIsInside(elli,yn,xp) &&
2917 ellipseIsInside(elli,xn,yn) && ellipseIsInside(elli,xp,yp) &&
2918 ellipseIsInside(elli,xn,yp) && ellipseIsInside(elli,xp,yn)){
2919
2920 // Put coordinates and factors in the list.
2921 coptr[pix][0] = xp;
2922 coptr[pix][1] = yp;
2923 facptr[pix] = (unsigned short int)(scale*loi);
2924
2925 // Look for minimal and maximal factor.
2926 if(min>loi) min=loi;
2927 if(max<loi) max=loi;
2928 sqr_sum += loi*loi;
2929 sum += loi;
2930 pix++;
2931 }
2932 }
2933 }
2934 // Allocate memory in result pointer.
2935 if(pix){
2936 mat->_factdata[view*half + bin]=
2937 (unsigned short int**)calloc(pix,sizeof(unsigned short int*));
2938 if(!mat->_factdata[view*half + bin]) return -1;
2939 }
2940
2941 // Allocate leaves.
2942 for(col=0; col<pix; col++){
2943 mat->_factdata[view*half + bin][col]=
2944 (unsigned short int*)calloc(3,sizeof(unsigned short int));
2945 if(!mat->_factdata[view*half + bin][col]) return -1;
2946 }
2947
2948 // Put now values in coordinates and factors array to result pointer.
2949 mat->fact = mat->_factdata;
2950 for(col=0; col<pix; col++){
2951 mat->fact[view*half + bin][col][0] = coptr[col][0];
2952 mat->fact[view*half + bin][col][1] = coptr[col][1];
2953 mat->fact[view*half + bin][col][2] = facptr[col];
2954 }
2955
2956 // Update also lists mat->dime and mat->factor_sqr_sums
2957 mat->dime[view*half + bin]=pix;
2958
2959 mat->factor_sqr_sum[view*half + bin]=sqr_sum;
2960
2961 }// END of bin loop
2962
2963 }// End of view>0.
2964
2965 }// END OF VIEW LOOP
2966
2967 free(X);
2968 free(Y);
2969 free(coords);
2970 free(factors);
2971
2972 mat->min = min;
2973 mat->max = max;
2974 mat->factor_sum = sum;
2975 mat->status = PRMAT_STATUS_BS_OCCUPIED;
2976 return 0;
2977
2978} // END OF SETTING BASE LINES.
float ellipseGetMinor(ELLIPSE *ell)
Definition ellipse.c:265
float ellipseGetMajor(ELLIPSE *ell)
Definition ellipse.c:254
int ellipseIsInside(ELLIPSE *ell, int row, int col)
Definition ellipse.c:352
float max
Maximal factor value in the projection matrix.
Definition libtpcrec.h:181
float min
Minimal factor value in the projection matrix.
Definition libtpcrec.h:179
char type
Scanner information on the prmat. 0=ECAT931 1=GE Advance.
Definition libtpcrec.h:166
int * prmatfov
Definition libtpcrec.h:177
char status
Prmat status.
Definition libtpcrec.h:164
float * factor_sqr_sum
Square sums of factors in each row in the projection matrix.
Definition libtpcrec.h:202
unsigned short int *** fact
Definition libtpcrec.h:208
float scaling_factor
Scaling factor for factors (notice that factors are stored in integers).
Definition libtpcrec.h:185
unsigned int * dime
Number of pixels hit by a line for every line.
Definition libtpcrec.h:204
unsigned int imgDim
Scanner geometrics, field imgDim.
Definition libtpcrec.h:172
float factor_sum
The sum of all factors in the projection matrix.
Definition libtpcrec.h:183
unsigned int dimr
Dimension of rows (lines of response) in the projection matrix.
Definition libtpcrec.h:200
unsigned int viewNr
Scanner geometrics, field viewNr.
Definition libtpcrec.h:168
int mode
Discretisation model utilised.
Definition libtpcrec.h:174
unsigned int binNr
Scanner geometrics, field binNr.
Definition libtpcrec.h:170
unsigned short int *** _factdata
Hidden pointer for the actual data.
Definition libtpcrec.h:210

Referenced by radonSetBases().

◆ radonSetBasesEA()

int radonSetBasesEA ( RADON * radtra,
ELLIPSE * elli,
PRMAT * mat )

Same as 'radonSetBases()' but discretisation model in this function is 'exact area'.

Parameters
radtraspecial Radon transform operator.
ellifield of view.
matpointer to the datastructure where coordinates and values are to be stored.
Returns
0 if ok.

Definition at line 2988 of file radon.c.

2989{
2990 // temporary pointers for storing the coordinates and factors
2991 unsigned short int **coords, *factors, **coptr, *facptr;
2992 // pointers for the values of LOR in integer points
2993 float *Y, *X, *Xptr, *Yptr;
2994 double sinus, cosinus, tanus; // sin, cosine and tangent
2995 double shift_x, shift_y; // shift for LOR
2996 int xp, xn, yp, yn, z, xp2; //integer points
2997 int x_left, x_right, y_top, y_bottom; // limits for fast search
2998 int col, col1, col2, row, view, bin, pix, errors=0; //counters
2999 int binNr, viewNr, imgDim, mode, views, rows, half;
3000 float sdist;
3001 float a=0,b=0, c=0, d=0, g=0, h=0, A;
3002 // delta x and y and factors epsilon.
3003 float dx, dy , eps1 = 0, eps2 = 0, eps3 = 0;
3004 float min=0, max=0, sum=0, scale, sqr_sum=0;
3005
3006 // Check that the data for this radon transform is initialized.
3007 if(radtra->status != RADON_STATUS_INITIALIZED) return -1;
3008
3009 // Retrieve the data from given radon transform object.
3010 mode=radonGetMO(radtra); // Should be 2.
3011 imgDim=radonGetID(radtra);
3012 binNr=radonGetNB(radtra);
3013 viewNr=radonGetNV(radtra);
3014 sdist=radonGetSD(radtra);
3015 half=radonGetHI(radtra);
3016
3017 /*printf("radonSetBases(): m=%i, id=%i, b=%i, v=%i, sd=%f, h=%i.\n",
3018 mode,imgDim,binNr,viewNr,sdist,half);*/
3019
3020 // Set information in the projection matrix data stucture.
3021 if(binNr == 192){
3022 mat->type=PRMAT_TYPE_ECAT931;
3023 } else if(binNr == 281) {
3024 mat->type=PRMAT_TYPE_GE;
3025 } else
3026 mat->type=PRMAT_TYPE_NA;
3027
3028 mat->viewNr=viewNr;
3029 mat->binNr=binNr;
3030 mat->imgDim=imgDim;
3031
3032 mat->mode = mode;
3033 // Allocate memory in PRMAT struct and set fov.
3034 mat->prmatfov = (int*)calloc(2,sizeof(int));
3035 mat->prmatfov[0] = ellipseGetMajor(elli);
3036 mat->prmatfov[1] = ellipseGetMinor(elli);
3037
3038 // rows := number of lines in the base set = (views*half)
3039 views = viewNr/4 + 1;
3040 rows = views*half;
3041
3042 mat->factor_sqr_sum=calloc(rows,sizeof(float));
3043 mat->dimr=rows;
3044 //entries in one line
3045 mat->dime=calloc(rows,sizeof(int));
3046 mat->_factdata=(unsigned short int***)calloc(rows,sizeof(unsigned short int**));
3047 //if not enough memory
3048 if(!mat->_factdata || !mat->dime) return(4);
3049
3050 // Compute scaling factor, assuming that maximum value is 1.
3051 scale=65534./1;
3052 mat->scaling_factor=1.0/scale; //is the inverse of scale
3053
3054 /* Allocate (temporary) coordinate and factor arrays to maximum size
3055 (= 4*imgDim). Coords contains pairs (x,y), coordinates in cartesian
3056 coordinate system. */
3057 coords = (unsigned short int**)calloc(4*imgDim,sizeof(unsigned short int*));
3058 factors = (unsigned short int*)calloc(4*imgDim,sizeof(unsigned short int));
3059 if(!coords || !factors) return 5;
3060
3061 for(col=0; col<4*imgDim; col++){
3062 coords[col] = (unsigned short int*)calloc(2,sizeof(unsigned short int));
3063 if(!coords[col]) return -1;
3064 }
3065
3066 coptr = coords;
3067 facptr = factors;
3068
3069 // Array for storing values f_x.
3070 X=(float*)calloc(imgDim+1,sizeof(float));
3071 // Array for storing values f_y.
3072 Y=(float*)calloc(imgDim+1,sizeof(float));
3073 if(X==NULL || Y==NULL){
3074 return -2;
3075 }
3076 Xptr=X;
3077 Yptr=Y;
3078
3080 // Find pixel coordinates of the contributing pixels for tubes of response
3081 // belonging to first 1/4th of angles. From these pixel coordinates
3082 // others can be calculated via symmetries in projection space.
3083 // N.B. The line of response: a*x+b*y+c
3084 // => solve y: y=-x/tan(view) + s*(cos(theta)/tan(theta) + sin(theta))
3085 // solve x: x=-y*tan(theta) + s*(sin(theta)*tan(theta) + cos(theta))
3086 for(view=0; view<views; view++){
3087 // view=0 -> sin(theta)=0
3088 if(view==0){
3089
3090 // Choose column(s) according to sample distance for angles 0 and pi/2.
3091 col1 = 0;
3092 col2 = 0;
3093 for(bin = 0; bin < half; bin++){
3094
3095 pix = 0; // length of list pixels (and factors)
3096 sqr_sum = 0;
3097
3098 col1 = col2;
3099 col2 = floor((float)(bin + 1)*sdist);
3100
3101 // Determine factor epsilon.
3102 if(col1 == col2){
3103 eps1 = sdist;
3104 eps2 = 0;
3105 eps3 = 0;
3106 }
3107 if((col2-col1) == 1){
3108 eps1 = (float)(col2 - (bin)*sdist);
3109 eps2 = 0;
3110 eps3 = (float)((bin+1)*sdist - col2);
3111 }
3112 // If sdist > pixel size!
3113 if((col2-col1) > 1){
3114 eps1 = (float)(col1 + 1 - (bin)*sdist);
3115 eps2 = 1; // middle pixel.
3116 eps3 = (float)((bin+1)*sdist - col2);
3117 }
3118
3119 // Iterate through the entries in the image matrix.
3120 for(row=0; row<imgDim; row++){
3121
3122 /* Check that pixel and pixels hit by symmetrical lines lay inside
3123 the FOV. */
3124 if(ellipseIsInside(elli,row,col1) &&
3125 ellipseIsInside(elli,row,imgDim - 1 - col1) &&
3126 ellipseIsInside(elli,imgDim-1-col1,row) &&
3127 ellipseIsInside(elli,col1,row)) {
3128
3129 if(!eps3){
3130 coptr[pix][0] = (unsigned short int)col1;
3131 coptr[pix][1] = (unsigned short int)row;
3132 // Convert eps to unsigned short int.
3133 facptr[pix] = (unsigned short int)(scale*eps1);
3134 // Look for minimal and maximal factor.
3135 if(min>eps1) min=eps1;
3136 if(max<eps1) max=eps1;
3137 // Compute square sums in every row.
3138 sqr_sum += eps1*eps1;
3139 sum += eps1;
3140 pix++;
3141 }
3142
3143 if(eps3 && !eps2){
3144 coptr[pix][0] = (unsigned short int)col1;
3145 coptr[pix][1] = (unsigned short int)row;
3146 // Convert eps to unsigned short int.
3147 facptr[pix] = (unsigned short int)(scale*eps1);
3148 // Look for minimal and maximal factor.
3149 if(min>eps1) min=eps1;
3150 if(max<eps1) max=eps1;
3151 // Compute square sums in every row.
3152 sqr_sum += eps1*eps1;
3153 sum += eps1;
3154 pix++;
3155
3156 coptr[pix][0] = (unsigned short int)col2;
3157 coptr[pix][1] = (unsigned short int)row;
3158 // Convert eps to unsigned short int.
3159 facptr[pix] = (unsigned short int)(scale*eps3);
3160 // Look for minimal and maximal factor.
3161 if(min>eps3) min=eps3;
3162 if(max<eps3) max=eps3;
3163 // Compute square sums in every row.
3164 sqr_sum += eps3*eps3;
3165 sum += eps3;
3166 pix++;
3167 }
3168
3169 if(eps3 && eps2){
3170 for(col = col1; col<=col2; col++){
3171
3172 if(col == col1){
3173 coptr[pix][0] = (unsigned short int)col1;
3174 coptr[pix][1] = (unsigned short int)row;
3175 // Convert eps to unsigned short int.
3176 facptr[pix] = (unsigned short int)(scale*eps1);
3177 // Look for minimal and maximal factor.
3178 if(min>eps1) min=eps1;
3179 if(max<eps1) max=eps1;
3180 // Compute square sums in every row.
3181 sqr_sum += eps1*eps1;
3182 sum += eps1;
3183 pix++;
3184 }
3185
3186 if(col == col2){
3187 coptr[pix][0] = (unsigned short int)col2;
3188 coptr[pix][1] = (unsigned short int)row;
3189 // Convert eps to unsigned short int.
3190 facptr[pix] = (unsigned short int)(scale*eps3);
3191 // Look for minimal and maximal factor.
3192 if(min>eps3) min=eps3;
3193 if(max<eps3) max=eps3;
3194 // Compute square sums in every row.
3195 sqr_sum += eps3*eps3;
3196 sum += eps3;
3197 pix++;
3198 }
3199
3200 if(col != col1 && col != col2){
3201 coptr[pix][0] = (unsigned short int)col;
3202 coptr[pix][1] = (unsigned short int)row;
3203 // Convert eps to unsigned short int.
3204 facptr[pix] = (unsigned short int)(scale*eps2);
3205 // Look for minimal and maximal factor.
3206 if(min>eps2) min=eps2;
3207 if(max<eps2) max=eps2;
3208 // Compute square sums in every row.
3209 sqr_sum += eps2*eps2;
3210 sum += eps2;
3211 pix++;
3212 }
3213 }
3214 }
3215 }// Pixel is inside the fov
3216 }// END OF ROW-LOOP
3217
3218 /* Allocate memory in factor pointer (dynamically according to number
3219 of pixels intersected). */
3220 if(pix){
3221 mat->_factdata[bin]= // 0 angle
3222 (unsigned short int**)calloc(pix,sizeof(unsigned short int*));
3223 if(!mat->_factdata[bin]) return -1;
3224 }
3225 // Allocate leaves.
3226 for(col=0; col<pix; col++){
3227 mat->_factdata[bin][col]=
3228 (unsigned short int*)calloc(3,sizeof(unsigned short int));
3229 if(!mat->_factdata[bin][col]) return -1;
3230 }
3231
3232 // Put now values in coordinates and factors array to result pointer.
3233 mat->fact = mat->_factdata;
3234 for(col=0; col<pix; col++){
3235 mat->fact[bin][col][0] = coptr[col][0]; // x-coodinate
3236 mat->fact[bin][col][1] = coptr[col][1]; // y-coordinate
3237 mat->fact[bin][col][2] = facptr[col]; // factor
3238 }
3239
3240 //Set also the number of pixels belonging to each row and square sums.
3241 mat->dime[bin]=pix;
3242 mat->factor_sqr_sum[bin]=sqr_sum;
3243
3244 } // END OF BIN-LOOP FOR ANGLE 0
3245 // End of view==0 (handles angles 0,pi/4,pi/2,3pi/4).
3246 } else { // Angles in (0,pi)
3247
3248 // Set sine and cosine for this angle.
3249 sinus = (double)radonGetSin(radtra,view);
3250 cosinus = (double)radonGetSin(radtra,viewNr/2 + view);
3251 tanus = sinus/cosinus;
3252
3253 // Set shift from origin for the first line of response (-n/2,theta).
3254 // NOTE that image matrix is on cartesian coordinate system where origin
3255 // is in the middle and shift is in pixels.
3256 shift_y = -(imgDim/2)/sinus;
3257 shift_x = -(imgDim/2)/cosinus;
3258
3259 // Evaluate the function of the first LOR in integer points [-n/2,n/2].
3260 // NOTE that image matrix is on cartesian coordinate system where origin
3261 // is in the middle.
3262 z=-imgDim/2;
3263 for(col=0; col<imgDim+1; col++){
3264 Yptr[col]=(float)(-z/tanus + shift_y);
3265 Xptr[col]=(float)(-z*tanus + shift_x);
3266 z++;
3267 }
3268
3269 // Set shift from the first LOR.
3270 shift_y = (double)(sdist/sinus);
3271 shift_x = (double)(sdist/cosinus);
3272
3273 // Iterate through half the bins in this view,
3274 // and determine coordinates of pixels contributing to this LOR.
3275 // NOTE that shift is added according to 'bin' in every loop.
3276 // Calculate also the length of intersection.
3277 // Others are determined via symmetry in projection space.
3278
3279 for(bin=0; bin<half; bin++){
3280
3281 pix = 0;
3282 sqr_sum = 0;
3283
3284 // Limit (x-)indices for fast search.
3285 // Note that indices are non-negative integers.
3286
3287 x_left = floor((float)(Xptr[imgDim] + bin*shift_x + imgDim/2));
3288 if(x_left < 0) x_left = 0;
3289
3290 x_right = floor((float)(Xptr[0] + bin*shift_x + imgDim/2));
3291 if(x_right <= 0) x_right = 1;
3292 if(x_right > imgDim) x_right = imgDim - 1;
3293
3294 /* Iterate through the values in vector Y, in integer points
3295 [x_left,x_rigth]. */
3296 for(z=x_left; z <= x_right; z++) {
3297
3298 xp = z; //positive x-coordinate
3299 xn = imgDim - 1 - xp; //negative x-coordinate
3300
3301 // Look y from left.
3302 yp = imgDim/2 - floor(Yptr[xp + 1] + bin*shift_y) - 1;
3303 yn = imgDim - 1 - yp;
3304
3305 // If the y-value for this x (z) is inside the image grid.
3306 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
3307 xp < imgDim && xn < imgDim && xn >= 0) {
3308
3309 /* Check that pixel and pixels hit by symmetrical lines lay inside
3310 the FOV. */
3311 if(ellipseIsInside(elli,yp,xp) && ellipseIsInside(elli,yn,xn) &&
3312 ellipseIsInside(elli,yp,xn) && ellipseIsInside(elli,yn,xp) &&
3313 ellipseIsInside(elli,xn,yn) && ellipseIsInside(elli,xp,yp) &&
3314 ellipseIsInside(elli,xn,yp) && ellipseIsInside(elli,xp,yn)){
3315
3316 /* NOTE that pixels found in this part are always hit from right
3317 side. */
3318 // Compute a := |AF| and b := |FB|.
3319 a = (float)(xp + 1 - (imgDim/2 + Xptr[imgDim - yp] + bin*shift_x));
3320 b = (float)(floor(Yptr[xp + 1] + bin*shift_y) + 1 -
3321 (Yptr[xp + 1] + bin*shift_y));
3322
3323 // Calculate the area of lower triangle.
3324 A = a*b/2;
3325
3326 // c := |FC|
3327 c = (float)(xp + 1 - (imgDim/2 + Xptr[imgDim - yp] +
3328 (bin+1)*shift_x));
3329
3330 if(c > 0) {
3331
3332 // d := |FD|
3333 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
3334 (Yptr[xp + 1] + (bin+1)*shift_y));
3335
3336 // Subtract the area of upper triangle.
3337 A = A - c*d/2;
3338 }
3339
3340 eps1 = A;
3341
3342 if(eps1 < 0 || eps1 > 1) errors++;
3343
3344 // Put coordinates and factors in the list.
3345 coptr[pix][0] = xp;
3346 coptr[pix][1] = yp;
3347 facptr[pix] = (unsigned short int)(scale*eps1);
3348
3349 // Look for minimal and maximal factor.
3350 if(min>eps1) min=eps1;
3351 if(max<eps1) max=eps1;
3352 sqr_sum += eps1*eps1;
3353 sum += eps1;
3354 pix++;
3355 }// Is inside the FOV.
3356 }
3357 }
3358
3359 // Limit (y-)indices for fast search.
3360 // Note that indices are non-negative integers.
3361 y_bottom = floor((float)(Yptr[imgDim] + bin*shift_y + imgDim/2));
3362 if(y_bottom < 0) y_bottom = 0;
3363 if(y_bottom > imgDim) y_bottom = 0;
3364
3365 y_top = floor((float)(Yptr[0] + bin*shift_y + imgDim/2));
3366 if(y_top > imgDim) y_top = imgDim;
3367 if(y_top <= 0) y_top = 1;
3368
3369 /* Iterate through the values in vector X, in integer points
3370 [y_bottom,y_top]. */
3371 for(z=y_top; z >= y_bottom; z--) {
3372
3373 // Look y from this location.
3374 xp = floor(Xptr[z] + bin*shift_x) + imgDim/2;
3375 xn = imgDim - 1 - xp;
3376
3377 yp = imgDim - z - 1;
3378 yn = imgDim - yp - 1;
3379
3380 // If the x-value for this y (z) is inside the image grid.
3381 if(yp < imgDim && yp >= 0 && yn < imgDim && yn >= 0 && xp >= 0 &&
3382 xp < imgDim && xn < imgDim && xn >= 0) {
3383
3384 /* Check that pixel and pixels hit by symmetrical lines lay inside
3385 the FOV. */
3386 if(ellipseIsInside(elli,yp,xp) && ellipseIsInside(elli,yn,xn) &&
3387 ellipseIsInside(elli,yp,xn) && ellipseIsInside(elli,yn,xp) &&
3388 ellipseIsInside(elli,xn,yn) && ellipseIsInside(elli,xp,yp) &&
3389 ellipseIsInside(elli,xn,yp) && ellipseIsInside(elli,xp,yn)){
3390
3391 eps1=eps2=eps3=0;
3392
3393 dx = (float)(Xptr[z] + bin*shift_x + imgDim/2 - xp);
3394 dy = (float)(Yptr[xp] + bin*shift_y - z + imgDim/2);
3395
3396 if(dy < 1){ // Cases 3,4,5 and 6.
3397
3398 // 1. PART
3399 // a := |HA|
3400 a = dy;
3401
3402 // b := |HB| (b < 1 for angles in [0,pi/4))
3403 b = dx;
3404
3405 // h := height of rectangle R.
3406 h = a + shift_y;
3407
3408 if(h > 1){ // Cases 3,4 and 5.
3409 h = 1;
3410 g = b + shift_x;
3411 if(g > 1){ // Cases 3 and 4.
3412 g = 1;
3413 xp2 =floor(Xptr[z+1] + (bin+1)*shift_x) + imgDim/2;
3414
3415 if(xp == xp2){ // Case 4.
3416 // c := |FC|
3417 c = (float)(xp + 1 - (imgDim/2 + Xptr[z+1] +
3418 (bin+1)*shift_x));
3419 // d := |FD|
3420 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
3421 (Yptr[xp + 1] + (bin+1)*shift_y));
3422 eps1 = 1 - (a*b + c*d)/2;
3423 eps2 = 0;
3424 // Lower triangle on the next pixel (x+1,y).
3425 eps3 = (1 - d)*(b + shift_x - 1)/2;
3426 } else { // Case 3.
3427 // c=d=0.
3428 eps1 = 1 - a*b/2;
3429 // Calculate area on pixel in place (xp+1,yp-1).
3430 dy = (float)(Yptr[xp+1] + (bin+1)*shift_y - (z + 1) +
3431 imgDim/2);
3432 if(dy < 1){ // Case 11.
3433 // c := |HC|
3434 c = dy;
3435 // d := |HD|
3436 d = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
3437 (bin+1)*shift_x));
3438 eps2 = c*d/2;
3439 } else{ // Cases 9 and 10.
3440 dx = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
3441 (bin+1)*shift_x));
3442 if(dx < 1) { // Case 10.
3443 // g := length of rectangle Q.
3444 g = dx;
3445 // c := |CD| (on x-axis).
3446 c = dx - (float)(xp + 2 - (imgDim/2 + Xptr[z+2] +
3447 (bin+1)*shift_x));
3448 // Rectangle Q - triangle c*h (h = 1).
3449 eps2 = g - c/2;
3450 } else { // Case 9.
3451 // c := |FC|
3452 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+2] +
3453 (bin+1)*shift_x));
3454 // d := |FD|
3455 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) +
3456 2 - (Yptr[xp + 2] + (bin+1)*shift_y));
3457 // Rectangle Q - triangle CFD.
3458 eps2 = 1 - c*d/2;
3459 }
3460 }
3461
3462 // Calculate area on pixel in place (xp+1,yp).
3463 dx = (float)(xp + 2 - (imgDim/2 + Xptr[z] +
3464 (bin+1)*shift_x));
3465 if(dx < 1) { // Case 10.
3466 // g := length of rectangle Q.
3467 g = dx;
3468 // c := |CD| (on x-axis).
3469 c = dx - (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
3470 (bin+1)*shift_x));
3471 // Rectangle Q - triangle c*h (h = 1).
3472 eps3 = g - c/2;
3473 } else { // Case 9.
3474 // c := |FC|
3475 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
3476 (bin+1)*shift_x));
3477 // d := |FD|
3478 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) +
3479 1 - (Yptr[xp + 2] + (bin+1)*shift_y));
3480 // Rectangle Q - triangle CFD.
3481 eps3 = 1 - c*d/2;
3482 }
3483 }
3484 } else { // Case 5. (g < 1)
3485 // c := |DC|.
3486 c = g - (imgDim/2 + Xptr[z+1] + (bin+1)*shift_x - xp);
3487 // d := heigth
3488 d = 1;
3489
3490 eps1 = g*h - (a*b + c*d)/2;
3491 eps2 = 0;
3492 eps3 = 0;
3493 }
3494 } else { // Case 6 (h <= 1).
3495 // g := legth of rectangle R
3496 g = b + shift_x;
3497 if(g > 1) // Should always be < 1 for angles in [0,pi/4)
3498 g = 1;
3499
3500 eps1 = (g*h - a*b)/2;
3501 eps2 = 0;
3502 eps3 = 0;
3503 }
3504 } else { // 2. PART. Cases 2,7 and 8. (dy >= 1).
3505
3506 // a := |HA|
3507 a = 1;
3508
3509 // b := |HB| (>=1)
3510 b = dx - (float)(Xptr[z+1] + bin*shift_x + imgDim/2 - xp);
3511
3512 // h := heigth of rectangle R
3513 h = 1;
3514
3515 // g := length of rectangle R
3516 g = dx + shift_x;
3517
3518 if(g > 1){ // Cases 2 and 8.
3519 g = 1 - (float)(Xptr[z+1] + bin*shift_x + imgDim/2 - xp);
3520 xp2 = floor(Xptr[z+1] + (bin+1)*shift_x) + imgDim/2;
3521 if(xp == xp2){ // Case 8.
3522 // c := |FC|
3523 c = (float)(xp + 1 - (imgDim/2 + Xptr[z+1] +
3524 (bin+1)*shift_x));
3525 // d := |FD|
3526 d = (float)(floor(Yptr[xp + 1] + (bin+1)*shift_y) + 1 -
3527 (Yptr[xp + 1] + (bin+1)*shift_y));
3528 eps1 = g*h - (a*b + c*d)/2;
3529 eps2 = 0;
3530 // Lower triangle on the next pixel (x+1,y).
3531 eps3 = (1 - d)*((Xptr[z] + (bin+1)*shift_x + imgDim/2)
3532 - (xp+1))/2;
3533 } else { // Case 2.
3534 // c=d=0.
3535 eps1 = g*h - a*b/2;
3536 /* Pixel in place (xp+1,yp-1) should have been found in
3537 the previous step. */
3538 eps2 = 0;
3539
3540 // Calculate area on pixel in place (xp+1,yp).
3541 dx = (float)((imgDim/2 + Xptr[z] + (bin+1)*shift_x) - (xp+1));
3542 if(dx < 1){ // Case 10 (trapezium).
3543 // g := bottom of trapezium Q.
3544 g = dx;
3545 // c := top of trapezium Q.
3546 c = (float)((imgDim/2 + Xptr[z+1] + (bin+1)*shift_x) -
3547 (xp+1));
3548 // Area of trapezium Q. Heigth = 1.
3549 eps3 = (g + c)/2;
3550 } else { // Case 9.
3551 // c := |FC|
3552 c = (float)(xp + 2 - (imgDim/2 + Xptr[z+1] +
3553 (bin+1)*shift_x));
3554 // d := |FD|
3555 d = (float)(floor(Yptr[xp + 2] + (bin+1)*shift_y) + 1 -
3556 (Yptr[xp + 2] + (bin+1)*shift_y));
3557 // Rectangle Q - triangle CFD.
3558 eps3 = 1 - c*d/2;
3559 }
3560 }
3561 } else { // Case 7. (g < = 1)
3562 // Area of the parallelogram R.
3563 eps1 = sdist/cosinus;
3564 eps2 = 0;
3565 eps3 = 0;
3566 }
3567 }
3568 if(eps1 <= 0 || eps1 > 1) {
3569 errors++;
3570 printf("Error: eps1 = %f \n",eps1);
3571 eps1 = fabs(eps1);
3572 }
3573 if(eps2 < 0 || eps2 > 1){
3574 errors++;
3575 eps2 = fabs(eps2);
3576 }
3577 if(eps3 < 0 || eps3 > 1){
3578 errors++;
3579 eps1 = fabs(eps3);
3580 }
3581 if(!eps2 && !eps3){ // Cases 5,6 and 7.
3582 // Put coordinates and factors in the list.
3583 coptr[pix][0] = xp;
3584 coptr[pix][1] = yp;
3585 facptr[pix] = (unsigned short int)(scale*eps1);
3586 pix++;
3587 // Look for minimal and maximal factor.
3588 if(min>eps1) min=eps1;
3589 if(max<eps1) max=eps1;
3590 sqr_sum += eps1*eps1;
3591 sum += eps1;
3592 } else{
3593 if(!eps2){ // <=> eps3 != 0 & eps2 = 0 <=> Cases 3,4 and 8.
3594 if(xp + 1 < imgDim && xn - 1 >= 0){
3595 // Put coordinates and factors in the list.
3596 coptr[pix][0] = xp;
3597 coptr[pix][1] = yp;
3598 facptr[pix] = (unsigned short int)(scale*eps1);
3599
3600 // Look for minimal and maximal factor.
3601 if(min>eps1) min=eps1;
3602 if(max<eps1) max=eps1;
3603 sqr_sum += eps1*eps1;
3604 sum += eps1;
3605 pix++;
3606
3607 // Put coordinates and factors in the list.
3608 coptr[pix][0] = xp+1;
3609 coptr[pix][1] = yp;
3610 facptr[pix] = (unsigned short int)(scale*eps3);
3611
3612 // Look for minimal and maximal factor.
3613 if(min>eps3) min=eps3;
3614 if(max<eps3) max=eps3;
3615 sqr_sum += eps3*eps3;
3616 sum += eps3;
3617 pix++;
3618 }
3619 } else{ // <=> eps2!=0 && eps3!=0 <=> Case 3.
3620 if(xp+1 < imgDim && xn-1 >= 0 && yp-1 >= 0 && yn+1 < imgDim) {
3621 // Put coordinates and factors in the list.
3622 coptr[pix][0] = xp;
3623 coptr[pix][1] = yp;
3624 facptr[pix] = (unsigned short int)(scale*eps1);
3625
3626 // Look for minimal and maximal factor.
3627 if(min>eps1) min=eps1;
3628 if(max<eps1) max=eps1;
3629 sqr_sum += eps1*eps1;
3630 sum += eps1;
3631 pix++;
3632
3633 // Put coordinates and factors in the list.
3634 coptr[pix][0] = xp+1;
3635 coptr[pix][1] = yp;
3636 facptr[pix] = (unsigned short int)(scale*eps3);
3637
3638 // Look for minimal and maximal factor.
3639 if(min>eps3) min=eps3;
3640 if(max<eps3) max=eps3;
3641 sqr_sum += eps3*eps3;
3642 sum += eps3;
3643 pix++;
3644
3645 // Put coordinates and factors in the list.
3646 coptr[pix][0] = xp+1;
3647 coptr[pix][1] = yp-1;
3648 facptr[pix] = (unsigned short int)(scale*eps2);
3649
3650 // Look for minimal and maximal factor.
3651 if(min>eps2) min=eps2;
3652 if(max<eps2) max=eps2;
3653 sqr_sum += eps2*eps2;
3654 sum += eps2;
3655 pix++;
3656 }
3657 }
3658 }
3659
3660 }// Pixel is inside the FOV.
3661 }
3662 }
3663 /* Allocate memory in factor pointer (dynamically according to number
3664 of pixels intersected). */
3665 if(pix){
3666 mat->_factdata[half*view + bin]=
3667 (unsigned short int**)calloc(pix,sizeof(unsigned short int*));
3668 if(!mat->_factdata[half*view + bin]) return -1;
3669 }
3670
3671 // Allocate leaves.
3672 for(col=0; col<pix; col++){
3673 mat->_factdata[half*view + bin][col]=
3674 (unsigned short int*)calloc(3,sizeof(unsigned short int));
3675 if(!mat->_factdata[half*view + bin][col]) return -1;
3676 }
3677
3678 // Put now values in coordinates and factors array to result pointer.
3679 mat->fact = mat->_factdata;
3680 for(col=0; col<pix; col++){
3681 mat->fact[half*view + bin][col][0] = coptr[col][0]; // x-coodinate
3682 mat->fact[half*view + bin][col][1] = coptr[col][1]; // y-coordinate
3683 mat->fact[half*view + bin][col][2] = facptr[col]; // factor
3684 }
3685
3686 //Set also the number of pixels belonging to each row and square sums.
3687 mat->dime[half*view + bin]=pix;
3688 mat->factor_sqr_sum[half*view + bin]=sqr_sum;
3689
3690 }// END OF BIN-LOOP
3691
3692 }// End of view>0.
3693
3694 }// END OF VIEW LOOP
3695
3696 free(X);
3697 free(Y);
3698 free(coords);
3699 free(factors);
3700
3701 mat->min = min;
3702 mat->max = max;
3703 mat->factor_sum = sum;
3704 mat->status = PRMAT_STATUS_BS_OCCUPIED;
3705
3706 if(RADON_VERBOSE) {
3707 printf("RADON: radonSetBasesEA() finished with %d errors.\n", errors);
3708 fflush(stdout);
3709 }
3710
3711 return 0;
3712}// END OF SETTING BASE LINES (EXACT AREA).

Referenced by radonSetBasesEA().

◆ radonSetLORS()

int radonSetLORS ( RADON * radtra,
ELLIPSE * elli,
PRMAT * mat )

Sets the coordinates and factors for intersected pixels according to given special Radon transform operator for EVERY line of response.

Precondition
radtra is a radon transform operator && elli defines a field of view && mat is initialized.
Postcondition
coordinates and factors for pixels contributing to all lines of response are set.
Parameters
radtraspecial Radon transform operator.
ellifield of view.
matpointer to the datastructure where coordinates and values are stored for the base lines.
Returns
0 if ok.

Definition at line 3934 of file radon.c.

3935{
3936 unsigned int *coords, *iptr;
3937 unsigned int imgDim=128, binNr=256, viewNr=192, view, bin, pixNr=0;
3938 unsigned int row, col, rows, half, centerbin, p;
3939 int ret=0;
3940 int xp, xn, yp, yn;
3941 float fact, sqr_sum;
3942 PRMAT ext_mat; // temporary extented projection matrix
3943
3944 if(elli) {} // to prevent compiler warning about not being used.
3945
3946 printf("radonSetLors() started. \n");
3947
3948 //Retrieve data from given radon transform object
3949 imgDim=radonGetID(radtra);
3950 binNr=radonGetNB(radtra);
3951 viewNr=radonGetNV(radtra);
3952
3953 // Calculate and set center bin for the current geometrics.
3954 if((binNr%2) != 0){
3955 half = (binNr - 1)/2 + 1;
3956 centerbin = half - 1;
3957 }
3958 else{
3959 half = binNr/2;
3960 // In the case binNr is even there is no center bin.
3961 centerbin = -1;
3962 }
3963
3964 // Initiate extented projection matrix.
3965 prmatInit(&ext_mat);
3966
3967 // Prepare to allocate extented projection matrix.
3968 rows = viewNr*binNr;
3969 coords = (unsigned int*)calloc(rows,sizeof(int));
3970 iptr = coords;
3971 // Determine the number of hit pixels for EVERY row.
3972 p = viewNr/4;
3973 // Extend the projection matrix according to given base set.
3974 for(view=0; view<p + 1; view++){
3975 for(bin=0; bin<half; bin++){
3976 row = view*half + bin;
3977 pixNr = prmatGetPixels(mat,row);
3978 // Line in the base set.
3979 iptr[view*binNr + bin] = pixNr;
3980 // Symmetrical lines.
3981 if(bin != centerbin)
3982 iptr[view*binNr + binNr - 1 - bin] = pixNr;
3983
3984 if(view != 0 && view != viewNr/4){
3985 // Mirror the original LOR on y-axis, i.e. x->-x
3986 // Case: pi-theta.
3987 iptr[(viewNr - view)*binNr + bin] = pixNr;
3988 if(bin != centerbin)
3989 iptr[(viewNr-view)*binNr + binNr - 1 - bin] = pixNr;
3990
3991 // Mirror the LOR on line x=y, i.e. x->y.
3992 // Case: pi/2-theta
3993 iptr[(viewNr/2 - view)*binNr + bin] = pixNr;
3994 if(bin != centerbin)
3995 iptr[(viewNr/2 - view)*binNr + binNr - 1 - bin] = pixNr;
3996 }
3997
3998 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
3999 // Case: pi/2+theta
4000 iptr[(viewNr/2 + view)*binNr + bin] = pixNr;
4001 if(bin != centerbin)
4002 iptr[(viewNr/2 + view)*binNr + binNr - 1 - bin] = pixNr;
4003
4004 }
4005 }
4006
4007 // Allocate the extented projection matrix.
4008 ret = prmatAllocate(&ext_mat,1,rows,coords);
4009 if(ret){
4010 free(coords);
4011 return(ret);
4012 }
4013 printf("Allocation done \n");
4014
4015 // Extend the projection matrix according to given base set.
4016 for(view=0; view<p + 1; view++){
4017 for(bin=0; bin<half; bin++){
4018 row = view*half + bin;
4019 for(col=0; col<prmatGetPixels(mat,row); col++){
4020
4021 sqr_sum = prmatGetFactorSqrSum(mat,row);
4022 // Notice that we want the factor in unsigned short int.
4023 fact = mat->fact[row][col][2];
4024 xp = prmatGetXCoord(mat,row,col);
4025 xn = imgDim - 1 - xp;
4026 yp = prmatGetYCoord(mat,row,col);
4027 yn = imgDim - 1 - yp;
4028
4029 // Line in the base set.
4030 ext_mat.fact[view*binNr + bin][col][0] = xp;
4031 ext_mat.fact[view*binNr + bin][col][1] = yp;
4032 ext_mat.fact[view*binNr + bin][col][2] = fact;
4033 ext_mat.factor_sqr_sum[view*binNr + bin] = sqr_sum;
4034
4035 // Then symmetrical lines.
4036 if(bin != centerbin){
4037 ext_mat.fact[view*binNr + binNr - 1 - bin][col][0] = xn;
4038 ext_mat.fact[view*binNr + binNr - 1 - bin][col][1] = yn;
4039 ext_mat.fact[view*binNr + binNr - 1 - bin][col][2] = fact;
4040 ext_mat.factor_sqr_sum[view*binNr + binNr - 1 - bin] = sqr_sum;
4041 }
4042
4043 if(view != 0 && view != viewNr/4){
4044 // Mirror the original LOR on y-axis, i.e. x->-x
4045 // Case: pi-theta.
4046 ext_mat.fact[(viewNr - view)*binNr + bin][col][0] = xn;
4047 ext_mat.fact[(viewNr - view)*binNr + bin][col][1] = yp;
4048 ext_mat.fact[(viewNr - view)*binNr + bin][col][2] = fact;
4049 ext_mat.factor_sqr_sum[(viewNr - view)*binNr + bin] = sqr_sum;
4050
4051 if(bin != centerbin){
4052
4053 ext_mat.fact[(viewNr - view)*binNr +binNr - 1 - bin][col][0] = xp;
4054 ext_mat.fact[(viewNr - view)*binNr +binNr - 1 - bin][col][1] = yn;
4055 ext_mat.fact[(viewNr - view)*binNr +binNr - 1 - bin][col][2] = fact;
4056 ext_mat.factor_sqr_sum[(viewNr - view)*binNr +binNr - 1 - bin] =
4057 sqr_sum;
4058 }
4059
4060 // Mirror the LOR on line x=y, i.e. x->y.
4061 // Case: pi/2-theta
4062 ext_mat.fact[(viewNr/2 - view)*binNr + bin][col][0] = yn;
4063 ext_mat.fact[(viewNr/2 - view)*binNr + bin][col][1] = xn;
4064 ext_mat.fact[(viewNr/2 - view)*binNr + bin][col][2] = fact;
4065 ext_mat.factor_sqr_sum[(viewNr/2 - view)*binNr + bin] = sqr_sum;
4066
4067 if(bin != centerbin){
4068 ext_mat.fact[(viewNr/2 - view)*binNr +binNr-1-bin][col][0] = yp;
4069 ext_mat.fact[(viewNr/2 - view)*binNr +binNr-1-bin][col][1] = xp;
4070 ext_mat.fact[(viewNr/2 - view)*binNr +binNr-1-bin][col][2] = fact;
4071 ext_mat.factor_sqr_sum[(viewNr/2-view)*binNr+binNr-1-bin] = sqr_sum;
4072 }
4073 }
4074
4075 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
4076 // Case: pi/2+theta
4077 ext_mat.fact[(viewNr/2 + view)*binNr + bin][col][0] = yp;
4078 ext_mat.fact[(viewNr/2 + view)*binNr + bin][col][1] = xn;
4079 ext_mat.fact[(viewNr/2 + view)*binNr + bin][col][2] = fact;
4080 ext_mat.factor_sqr_sum[(viewNr/2 + view)*binNr + bin] = sqr_sum;
4081
4082 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,binNr-bin)
4083 if(bin != centerbin){
4084 ext_mat.fact[(viewNr/2 + view)*binNr + binNr-1-bin][col][0] = yn;
4085 ext_mat.fact[(viewNr/2 + view)*binNr + binNr-1-bin][col][1] = xp;
4086 ext_mat.fact[(viewNr/2 + view)*binNr + binNr-1-bin][col][2] = fact;
4087 ext_mat.factor_sqr_sum[(viewNr/2 +view)*binNr +binNr-1-bin] = sqr_sum;
4088 }
4089 }
4090 }
4091 }
4092
4093
4094 // Empty old data from the given projection matrix.
4095 free((float*)mat->factor_sqr_sum);
4096
4097 for(row=0; row<mat->dimr; row++){ //every row
4098 for(col=0; col<mat->dime[row]; col++){ //every factor
4099 free((unsigned short int*)mat->_factdata[row][col]);
4100 }
4101 }
4102
4103 free((int*)mat->dime);
4104
4105 if(mat->dimr>0) free(mat->_factdata);
4106 mat->dimr=0;
4107
4108 // Allocate memory in mat structure for new extented matrix.
4109 ret = prmatAllocate(mat, 1, rows, coords);
4110 if(ret){
4111 free(coords);
4112 prmatEmpty(&ext_mat);
4113 return(ret);
4114 }
4115 printf("Allocation done \n");
4116
4117 // Copy the matrix from the temporary projection matrix.
4118 for(row=0; row<prmatGetRows(&ext_mat); row++){
4119 // Square sums.
4120 mat->factor_sqr_sum[row] = prmatGetFactorSqrSum(&ext_mat,row);
4121 for(col=0; col<prmatGetPixels(&ext_mat,row); col++){
4122 // Coordinates and factors.
4123 mat->fact[row][col][0] = prmatGetXCoord(&ext_mat,row,col);
4124 mat->fact[row][col][1] = prmatGetYCoord(&ext_mat,row,col);
4125 mat->fact[row][col][2] = ext_mat.fact[row][col][2];
4126 }
4127 }
4128
4129 // Release the temporary projection matrix.
4130 prmatEmpty(&ext_mat);
4131 free(coords);
4132
4133 return 0;
4134
4135
4136}//END OF radonSetLORS
unsigned int prmatGetRows(PRMAT *mat)
Definition prmat.c:267
void prmatEmpty(PRMAT *mat)
Definition prmat.c:56
void prmatInit(PRMAT *mat)
Definition prmat.c:22
float prmatGetFactorSqrSum(PRMAT *mat, int row)
Definition prmat.c:409
int prmatAllocate(PRMAT *mat, int set, unsigned int rows, unsigned int *coords)
Definition prmat.c:105

Referenced by radonSetLORS().

◆ radonSetLUT()

int radonSetLUT ( RADON * radtra,
ELLIPSE * elli,
PRMAT * mat )

Sets a look-up table containing coordinates of lines of response intersecting pixels inside a field of view. Lines of response contributing to a pixel are searched from already set projection matrix.

Precondition
radtra is a radon transform operator && elli defines a field of view && projections are set in structure mat.
Postcondition
coordinates of lines response intersecting a pixel are set in a table.
Parameters
radtraspecial Radon transform operator.
ellifield of view.
matpointer to the datastructure where coordinates and values are to be stored.
Returns
0 if ok.

Definition at line 3728 of file radon.c.

3729{
3730 unsigned int **tmpData, **tmpptr; // coordinates of lines response.
3731 unsigned int *coords, *iptr;
3732 unsigned int col, row, pix=0, p=0, lors=0, view, bin; //counters
3733 unsigned int binNr, viewNr, imgDim, views, half, center;
3734 int ret=0;
3735 int xp, xn, yp, yn;
3736 float diam, sampledist;
3737
3738 //Check that projections are set.
3739 if(mat->status < PRMAT_STATUS_BS_OCCUPIED) return -1;
3740
3741 //Retrieve data from given radon transform object
3742 imgDim=radonGetID(radtra);
3743 binNr=radonGetNB(radtra);
3744 viewNr=radonGetNV(radtra);
3745 sampledist=radonGetSD(radtra);
3746 half=radonGetHI(radtra);
3747 center=radonGetCB(radtra);
3748 diam=sqrt(2);
3749
3750 /* Allocate memory for temporary list where we store coordinates of lines of
3751 response. Maximum number of lines (in one angle) hitting a pixel is
3752 [diameter of a pixel]/[sample distance]. */
3753 lors = ceil(diam/sampledist) + 1;
3754 tmpData = (unsigned int**)calloc(imgDim*imgDim,sizeof(unsigned int*));
3755 for(p=0; p<imgDim*imgDim; p++){
3756 tmpData[p]=(unsigned int*)calloc(lors*viewNr,sizeof(unsigned int));
3757 if(!tmpData[p]){
3758 fprintf(stderr, "Error: not enough memory.\n");
3759 return(4);
3760 }
3761 }
3762 tmpptr = tmpData;
3763
3764 /* Initialize the first entry in the list, to keep the number of entries
3765 in each row. And then fill the list from second entry. */
3766 for(p=0; p<imgDim*imgDim; p++) tmpptr[p][0]=0;
3767 views = viewNr/4;
3768 // Analyse the given projection matrix.
3769 for(view=0; view<views + 1; view++){
3770 for(bin=0; bin<half; bin++){
3771 row = view*half + bin;
3772 for(col=0; col<prmatGetPixels(mat,row); col++){
3773
3774 xp = prmatGetXCoord(mat,row,col);
3775 xn = imgDim - 1 - xp;
3776 yp = prmatGetYCoord(mat,row,col);
3777 yn = imgDim - 1 - yp;
3778
3779 if(xp != 0 || yp != 0){
3780 if(view == 0){
3781 /* Put coordinates of coincidence line in the next free place and
3782 increase the counter. */
3783 tmpptr[yp*imgDim + xp][++tmpptr[yp*imgDim + xp][0]] = bin;
3784 if(bin != center)
3785 tmpptr[yp*imgDim+(imgDim-1-xp)][++tmpptr[yp*imgDim+(imgDim-1-xp)][0]]=
3786 binNr-bin-1;
3787 tmpptr[(imgDim-1-xp)*imgDim+yp][++tmpptr[(imgDim-1-xp)*imgDim+yp][0]]=
3788 binNr*(viewNr/2) + bin;
3789 if(bin != center)
3790 tmpptr[xp*imgDim+yp][++tmpptr[xp*imgDim+yp][0]] =
3791 binNr*(viewNr/2) + (binNr-bin-1);
3792 }
3793
3794 if(view == viewNr/4) {
3795
3796 // Add img(x,y)*k to the raysum of LOR (view,bin)
3797 tmpptr[yp*imgDim + xp][++tmpptr[yp*imgDim + xp][0]] =
3798 (viewNr/4)*binNr + bin;
3799 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
3800 if(bin != center)
3801 tmpptr[yn*imgDim + xn][++tmpptr[yn*imgDim + xn][0]] =
3802 (viewNr/4)*binNr + binNr - 1 - bin;
3803
3804 // Rotate the LOR 90 degrees, i.e. x->-x.
3805 // Case: pi/2 + theta = 3pi/4.
3806 // Add img(-y,x)*k to the raysum of LOR (viewNr/2+view,bin)
3807 tmpptr[xn*imgDim + yp][++tmpptr[xn*imgDim + yp][0]] =
3808 (viewNr/2 + viewNr/4)*binNr + bin;
3809 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,binNr-bin)
3810 if(bin != center)
3811 tmpptr[xp*imgDim + yn][++tmpptr[xp*imgDim + yn][0]] =
3812 (viewNr/2 + viewNr/4)*binNr + binNr - 1 - bin;
3813 }
3814
3815 if(view != 0 && view != viewNr/4) {
3816
3817 // Add img(x,y)*k to the raysum of LOR (view,bin)
3818 tmpptr[yp*imgDim + xp][++tmpptr[yp*imgDim + xp][0]] =
3819 view*binNr + bin;
3820 if(bin != center)
3821 // Add img(-x,-y)*k to the raysum of LOR (view,binNr-bin)
3822 tmpptr[yn*imgDim + xn][++tmpptr[yn*imgDim + xn][0]] =
3823 view*binNr + binNr - 1 - bin;
3824
3825 // Mirror the LOR on line x=y, and on y-axis i.e x->y and y->-y.
3826 // Case: pi/2+theta
3827 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,bin)
3828 tmpptr[xn*imgDim + yp][++tmpptr[xn*imgDim + yp][0]] =
3829 (viewNr/2 + view)*binNr + bin;
3830 // Add img(y,-x)*k to the raysum of LOR (viewNr/2+view,binNr-bin)
3831 if(bin != center)
3832 tmpptr[xp*imgDim + yn][++tmpptr[xp*imgDim + yn][0]] =
3833 (viewNr/2 + view)*binNr + binNr - 1 - bin;
3834
3835 // Mirror the original LOR on y-axis, i.e. x->-x
3836 // Case: pi-theta.
3837 // Add img(-x,y)*k to the raysum of LOR (viewNr-view,bin)
3838 tmpptr[yp*imgDim + xn][++tmpptr[yp*imgDim + xn][0]] =
3839 (viewNr - view)*binNr + bin;
3840 // Add img(x,-y)*k to the raysum of LOR (viewNr-view,binNr-bin)
3841 if(bin != center)
3842 tmpptr[yn*imgDim + xp][++tmpptr[yn*imgDim + xp][0]] =
3843 (viewNr-view)*binNr + binNr - 1 - bin;
3844
3845 // Mirror the LOR on line x=y, i.e. x->y.
3846 // Case: pi/2-theta
3847 // Add img(-y,-x)*k to the raysum of LOR (viewNr/2-view,bin)
3848 tmpptr[xn*imgDim + yn][++tmpptr[xn*imgDim + yn][0]] =
3849 (viewNr/2 - view)*binNr + bin;
3850 // Add img(y,x)*k to the raysum of LOR (viewNr/2-view,binNr-bin)
3851 if(bin != center)
3852 tmpptr[xp*imgDim + yp][++tmpptr[xp*imgDim + yp][0]] =
3853 (viewNr/2 - view)*binNr + binNr - 1 - bin;
3854 }
3855 }
3856 }
3857 }
3858 }
3859
3860 pix = 0;
3861 // Get the number of pixels inside the FOV.
3862 for(row = 0; row < imgDim; row++){
3863 for(col = 0; col < imgDim; col++){
3864 if(ellipseIsInside(elli,row,col))
3865 pix++;
3866 }
3867 }
3868
3869 // Analyse the tmp data array.
3870 p = 0; // index of a pixel inside the FOV
3871 coords = (unsigned int*)calloc(pix,sizeof(int));
3872 iptr = coords;
3873 for(row = 0; row < imgDim; row++){
3874 for(col = 0; col < imgDim; col++){
3875 if(ellipseIsInside(elli,row,col)){
3876 // Put the number of coincidence lines hitting this pixel into the list.
3877 iptr[p] = tmpptr[row*imgDim + col][0];
3878 p++; // increase pixel counter
3879 }
3880 }
3881 }
3882
3883 // Allocate memory for the look-up table.
3884 ret = prmatAllocate(mat,0,pix,coords);
3885 if(ret){
3886 free((unsigned int**)tmpData);
3887 free((int*)coords);
3888 return(ret);
3889 }
3890
3891 /* Put pixel coordinates, number of lines and the coordinates of
3892 the coincidence lines in the structure. */
3893 p = 0;
3894 tmpptr = tmpData;
3895 iptr = coords;
3896 for(row = 0; row < imgDim; row++) {
3897 for(col = 0; col < imgDim; col++) {
3898 if(ellipseIsInside(elli,row,col)) {
3899 // Put pixel coordinates in the list.
3900 mat -> lines[p][0] = row*imgDim + col;
3901 // Put the number of lines hitting this pixel in the list.
3902 mat -> lines[p][1] = iptr[p];
3903 // Put the coordinates of the coincidence lines in the list.
3904 for(lors = 0; lors < iptr[p]; lors++)
3905 mat -> lines[p][lors + 2] = tmpptr[row*imgDim + col][lors+1];
3906
3907 p++; // increase pixel counter
3908 }
3909 }
3910 }
3911
3912 printf("\n");
3913 mat->status = PRMAT_STATUS_LU_OCCUPIED;
3914
3915 free((unsigned int**)tmpData);
3916 free((int*)coords);
3917
3918 return 0;
3919}// END OF SETTING LOOK-UP TABLE.

Referenced by radonSetLUT().

Variable Documentation

◆ RADON_TEST

int RADON_TEST

Drive in test mode if not 0.

Definition at line 12 of file radon.c.

◆ RADON_VERBOSE

int RADON_VERBOSE

Drive in verbose mode if not 0.

Definition at line 13 of file radon.c.

Referenced by radonBackTransformEA(), radonEmpty(), radonFwdTransform(), radonFwdTransformEA(), radonSet(), and radonSetBasesEA().