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 1429 of file radon.c.

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

◆ 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 1696 of file radon.c.

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

◆ 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 2503 of file radon.c.

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

◆ 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 2415 of file radon.c.

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

◆ 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

◆ 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

◆ 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 550 of file radon.c.

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

◆ 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 1328 of file radon.c.

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

◆ 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 1238 of file radon.c.

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

◆ 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(), 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(), 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(), 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(), 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(), 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(), 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(), 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(), 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}

◆ 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 2602 of file radon.c.

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

◆ 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 2984 of file radon.c.

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

◆ 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 3925 of file radon.c.

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

◆ 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 3719 of file radon.c.

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

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(), and radonSet().