@@ -65,126 +65,187 @@ namespace cv {
6565#endif
6666
6767/* *
68- * [linspace - Constructs linearly spaced vector of length n between start and end values ( both inclusive )]
69- * @param start [start value]
70- * @param end [end value]
71- * @param n [length of the vector]
72- * @return vec [linearly spaced vector]
68+ * Flags for range of angles
69+ * AR_x_y : theta lies in [x, y] ( both x and y inclusive )
7370 */
74- static inline std::vector<float > linspace (float start, float end, int n) {
75- /* *
76- * A utility function for generating a vector of linearly spaced integers.
77- */
7871
79- // Finding diff
80- float diff = (end - start)*1 .0f /(n-1 );
81- std::vector<float > vec (n);
82- float val = start;
72+ enum ARFlags { AR_1_45, AR_46_90, AR_91_135, AR_136_179, AR_180 };
8373
84- for (int i=0 ; i<n; ++i) {
85- vec[i] = val;
86- // Adding diff to val
87- val += diff;
88- }
74+ /* *
75+ * [trans Function for computing radon transform given a particular angle theta]
76+ * @param src [Source image]
77+ * @param dst [Destination image]
78+ * @param m [Half the columns in src]
79+ * @param n [Half the rows in src]
80+ * @param rhoMax [Maximum value of rho ( restricted due to finite dimension of the image )]
81+ * @param theta [Given value of theta]
82+ * @param angleRange [One of the angle ranges]
83+ * @param maxTheta [Maximum value of theta ( in degrees ), defaults to 180 degrees]
84+ */
85+
86+ void trans (Mat src, Mat& dst, int m, int n, int rhoMax, int theta, int angleRange, int maxTheta = 180 ) {
87+ int rc = rhoMax/2 ;
88+
89+ // Computing cos(theta) and sin(theta)
90+ float cosTh = static_cast <float >(std::cos (theta*CV_PI/180.0 ));
91+ float sinTh = static_cast <float >(std::sin (theta*CV_PI/180.0 ));
92+
93+ // Slope of the line = tan(90 - theta)
94+ float a = -cosTh/sinTh;
95+
96+ switch (angleRange) {
8997
90- // Returning the vector
91- return vec;
98+ // Range: [1, 45]
99+ case AR_1_45:
100+ for (int r = 1 ; r <= rhoMax; ++r) {
101+ float rho = r - rc;
102+ float b = rho/sinTh;
103+
104+ float yMax = std::min ((int )(-a*m + b), n-1 ),
105+ yMin = std::max ((int )(a*m + b), -n);
106+
107+ for (int y = yMin; y <= yMax; ++y) {
108+ float x = (y - b)/a;
109+ int xFloor = static_cast <int >(std::floor (x));
110+ float xUp = x - xFloor;
111+ float xLow = 1 .0f - xUp;
112+ x = xFloor;
113+ x = static_cast <float >(std::max ((int )(x), -m));
114+ x = static_cast <float >(std::min ((int )(x), m-2 ));
115+
116+ dst.at <float >(rhoMax - r, maxTheta - theta - 1 ) += xLow*src.at <float >(y + n, x + m)
117+ + xUp*src.at <float >(y + n, x + m + 1 );
118+ }
119+ }
120+ break ;
121+
122+ // Range: [46, 90]
123+ case AR_46_90:
124+ for (int r = 1 ; r <= rhoMax; ++r) {
125+ float rho = r - rc;
126+ float b = rho/sinTh;
127+
128+ float xMax = std::min ((int )((-n - b)/a), m-1 ),
129+ xMin = std::max ((int )((n - b)/a), -m);
130+
131+ for (int x = xMin; x <= xMax; ++x) {
132+ float y = a*x + b;
133+ int yFloor = static_cast <int >(std::floor (y));
134+ float yUp = y - yFloor;
135+ float yLow = 1 .0f - yUp;
136+ y = yFloor;
137+ y = static_cast <float >(std::max ((int )(y), -n));
138+ y = static_cast <float >(std::min ((int )(y), n-2 ));
139+
140+ dst.at <float >(rhoMax - r, maxTheta - theta - 1 ) += yLow*src.at <float >(y + n, x + m)
141+ + yUp*src.at <float >(y + n + 1 , x + m);
142+ }
143+ }
144+ break ;
145+
146+ // Range: [91, 135]
147+ case AR_91_135:
148+ for (int r = 1 ; r <= rhoMax; ++r) {
149+ float rho = r - rc;
150+ float b = rho/sinTh;
151+
152+ float xMax = std::min ((int )((n - b)/a), m-1 ),
153+ xMin = std::max ((int )((-n - b)/a), -m);
154+
155+ for (int x = xMin; x <= xMax; ++x) {
156+ float y = a*x + b;
157+ int yFloor = static_cast <int >(std::floor (y));
158+ float yUp = y - yFloor;
159+ float yLow = 1 .0f - yUp;
160+ y = yFloor;
161+ y = static_cast <float >(std::max ((int )(y), -n));
162+ y = static_cast <float >(std::min ((int )(y), n-2 ));
163+
164+ dst.at <float >(rhoMax - r, maxTheta - theta - 1 ) += yLow*src.at <float >(y + n, x + m)
165+ + yUp*src.at <float >(y + n + 1 , x + m);
166+ }
167+ }
168+ break ;
169+
170+ // Range: [136, 179]
171+ case AR_136_179:
172+ for (int r = 1 ; r <= rhoMax; ++r) {
173+ float rho = r - rc;
174+ float b = rho/sinTh;
175+
176+ float yMax = std::min ((int )(a*m + b), n-1 ),
177+ yMin = std::max ((int )(-a*m + b), -n);
178+
179+ for (int y = yMin; y <= yMax; ++y) {
180+ float x = (y - b)/a;
181+ int xFloor = static_cast <int >(std::floor (x));
182+ float xUp = x - xFloor;
183+ float xLow = 1 .0f - xUp;
184+ x = xFloor;
185+ x = static_cast <float >(std::max ((int )(x), -m));
186+ x = static_cast <float >(std::min ((int )(x), m-2 ));
187+
188+ dst.at <float >(rhoMax - r, maxTheta - theta - 1 ) += xLow*src.at <float >(y + n, x + m)
189+ + xUp*src.at <float >(y + n, x + m + 1 );
190+ }
191+ }
192+ break ;
193+
194+ // theta = 180 degrees | Integrating along a vertical line
195+ case AR_180:
196+ int rhoOffset = static_cast <int >((rhoMax - src.cols )/2 );
197+ for (int x = 1 ; x <= src.cols ; ++x) {
198+ int r = x + rhoOffset;
199+ r = rhoMax - r;
200+ for (int y = 0 ; y < src.rows ; ++y) {
201+ dst.at <float >(r, 179 ) += src.at <float >(y, x);
202+ }
203+ }
204+ break ;
205+ }
92206}
93207
94208/* *
95- * [meshgrid Returns a rectangular grid 2D space]
96- * @param matX [Repeating vector along X direction]
97- * @param matY [Repeating vector along Y direction]
98- * @param X [Final meshgrid matrix X]
99- * @param Y [Final meshgrid matrix Y]
209+ * [getAngleRange Returns flag AR_x_y for given angle theta]
210+ * @param theta [Given angle theta]
211+ * @return [flag AR_x_y]
100212 */
101- static inline void meshgrid (const Mat &matX, const Mat &matY, Mat &X, Mat &Y) {
102- /* *
103- * A utitlity function to compute the meshgrid matrices for given input vectors.
104- */
105- repeat (matX.reshape (1 ,1 ), static_cast <int >(matY.total ()), 1 , X);
106- repeat (matY.reshape (1 ,1 ).t (), 1 , static_cast <int >(matX.total ()), Y);
213+
214+ int getAngleRange (int theta) {
215+ if (theta >= 1 && theta <= 45 ) return AR_1_45;
216+ else if (theta >=46 && theta <=90 ) return AR_46_90;
217+ else if (theta >= 91 && theta <= 135 ) return AR_91_135;
218+ else if (theta >= 136 && theta <= 179 ) return AR_136_179;
219+ else return AR_180;
107220}
108221
109222/* *
110223 * [radonTransform Computes the Radon Transform of the given input array]
111224 * @param src [Input image]
112225 * @param dst [Output sinogram, referenced]
113- * @param accuracy [Minimum accuracy for angles ( IN DEGREES ), defaults to 1 degree]
114226 */
115- void radonTransform (InputArray src, OutputArray dst, float accuracy) {
227+
228+ void radonTransform (InputArray src, OutputArray& dst) {
229+
116230 /* *
117- * Implementation of the Radon Transform
118- *
119- * Example:
120- * ::
121- * cv::Mat img, imgRadTrans;
122- * :::: img holds some image ::::
123- *
124- * radonTransform(img, imgRadTrans, 0.5);
125- * :::: imgRadTrans contains the radon transform ::::
231+ * Computes the Radon Transform for the given source image.
126232 */
127- // Asserting accuracy to be positive
128- CV_Assert (accuracy > 0 );
129233
234+ CV_Assert (src.type () == CV_8UC1);
130235 Mat srcMat_ = src.getMat (), srcMat;
131- CV_Assert (srcMat_.type () == CV_8UC1);
132236
133237 srcMat_.convertTo (srcMat, CV_32F, 1.0 /255 );
134-
135238 int rows = srcMat.rows , cols = srcMat.cols ;
136- float diag = (float )std::sqrt (rows*rows + cols*cols);
137-
138- Mat srcMatPadded;
139- int padWidth = (int )((std::ceil (diag - cols) + 2 )/2 );
140- int padHeight = (int )((std::ceil (diag - rows) + 2 )/2 );
141- copyMakeBorder (srcMat, srcMatPadded, padWidth, padHeight, padWidth, padHeight, BORDER_CONSTANT, 0 );
239+ int m = cols/2 , n = rows/2 ;
142240
143- int n = (int )(180 /accuracy) + 1 ;
144- std::vector<float > vecTheta = linspace (0 , 180 , n);
145- int dstCols = static_cast <int >(vecTheta.size ()), dstRows = srcMatPadded.rows ;
241+ float rhoMax = static_cast <float >(std::ceil (std::sqrt (rows*rows + cols*cols)));
242+ int maxTheta = 180 ;
146243
147- dst.create (Size (dstCols, dstRows ), CV_32F);
244+ dst.create (Size (maxTheta, rhoMax + 1 ), CV_32F);
148245 Mat dstMat = dst.getMat ();
149246
150- int num = srcMatPadded.cols ;
151- std::vector<float > vecVal = linspace (-1 , 1 , num);
152-
153- Mat meshX, meshY, meshXX, meshYY;
154- meshgrid (Mat (vecVal), Mat (vecVal), meshX, meshY);
155-
156- for (int i = 0 ; i < dstCols; ++i) {
157- float theta = (90 - vecTheta[i])*static_cast <float >(CV_PI)/180 .0f ;
158- float cosTh = std::cos (theta), sinTh = std::sin (theta);
159-
160- Mat temp (srcMatPadded.size (), CV_32F);
161-
162- // Rotating meshgrid entries by an angle theta
163- meshXX = cosTh*meshX - sinTh*meshY;
164- meshYY = sinTh*meshX + cosTh*meshY;
165-
166- // Clamping values to [-1, 1]
167- for (int l = 0 ; l < meshXX.cols ; ++l) {
168- for (int m = 0 ; m < meshXX.rows ; ++m) {
169- if (meshXX.at <float >(m, l) < -1 ) meshXX.at <float >(m, l) = -1 ;
170- else if (meshXX.at <float >(m, l) > 1 ) meshXX.at <float >(m, l) = 1 ;
171-
172- if (meshYY.at <float >(m, l) < -1 ) meshYY.at <float >(m, l) = -1 ;
173- else if (meshYY.at <float >(m, l) > 1 ) meshYY.at <float >(m, l) = 1 ;
174- }
175- }
176-
177- // Normalizing meshXX and meshYY to proper indices in the image
178- normalize (meshXX, meshXX, 0 , srcMatPadded.cols - 1 , NORM_MINMAX, -1 );
179- normalize (meshYY, meshYY, 0 , srcMatPadded.cols - 1 , NORM_MINMAX, -1 );
180-
181- // Remapping, so as to interpolate for non-integer points
182- remap (srcMatPadded, temp, meshXX, meshYY, INTER_LINEAR, BORDER_CONSTANT, Scalar (0 ));
183-
184- // Computing columnwise sum and hence the a column of the sinogram
185- Mat dstColReduced;
186- reduce (temp, dstColReduced, 1 , REDUCE_SUM, -1 );
187- dstColReduced.copyTo (dstMat.col (i));
247+ for (int i = 1 ; i <= 180 ; ++i) {
248+ trans (srcMat, dstMat, m, n, rhoMax, i, getAngleRange (i), maxTheta);
188249 }
189250}
190251
0 commit comments