h_measure.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. /****************************************************************************
  2. *
  3. * MODULE: r.texture
  4. * AUTHOR(S): Carmine Basco - basco@unisannio.it
  5. * with hints from:
  6. * prof. Giulio Antoniol - antoniol@ieee.org
  7. * prof. Michele Ceccarelli - ceccarelli@unisannio.it
  8. * Markus Metz (optimization and bug fixes)
  9. *
  10. * PURPOSE: Create map raster with textural features.
  11. *
  12. * COPYRIGHT: (C) 2003 by University of Sannio (BN) - Italy
  13. *
  14. * This program is free software under the GNU General Public
  15. * License (>=v2). Read the file COPYING that comes with GRASS
  16. * for details.
  17. *
  18. * Permission to use, copy, modify, and distribute this software and its
  19. * documentation for any purpose and without fee is hereby granted. This
  20. * software is provided "as is" without express or implied warranty.
  21. *
  22. *****************************************************************************/
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <math.h>
  26. #include <grass/gis.h>
  27. #include <grass/raster.h>
  28. #include <grass/glocale.h>
  29. #define BL "Direction "
  30. #define F1 "Angular Second Moment "
  31. #define F2 "Contrast "
  32. #define F3 "Correlation "
  33. #define F4 "Variance "
  34. #define F5 "Inverse Diff Moment "
  35. #define F6 "Sum Average "
  36. #define F7 "Sum Variance "
  37. #define F8 "Sum Entropy "
  38. #define F9 "Entropy "
  39. #define F10 "Difference Variance "
  40. #define F11 "Difference Entropy "
  41. #define F12 "Measure of Correlation-1 "
  42. #define F13 "Measure of Correlation-2 "
  43. #define PGM_MAXMAXVAL 255
  44. #define MAX_MATRIX_SIZE 512
  45. float **matrix(int nr, int nc);
  46. float *vector(int n);
  47. float f1_asm(void);
  48. float f2_contrast(void);
  49. float f3_corr(void);
  50. float f4_var(void);
  51. float f5_idm(void);
  52. float f6_savg(void);
  53. float f7_svar(void);
  54. float f8_sentropy(void);
  55. float f9_entropy(void);
  56. float f10_dvar(void);
  57. float f11_dentropy(void);
  58. float f12_icorr(void);
  59. float f13_icorr(void);
  60. static float **P_matrix = NULL;
  61. static float **P_matrix0 = NULL;
  62. static float **P_matrix45 = NULL;
  63. static float **P_matrix90 = NULL;
  64. static float **P_matrix135 = NULL;
  65. int tone[PGM_MAXMAXVAL + 1];
  66. static int Ng = 0;
  67. static float *px, *py;
  68. static float Pxpys[2 * PGM_MAXMAXVAL + 2];
  69. static float Pxpyd[2 * PGM_MAXMAXVAL + 2];
  70. void alloc_vars(int size)
  71. {
  72. int msize2;
  73. /* Allocate memory for gray-tone spatial dependence matrix */
  74. P_matrix0 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
  75. P_matrix45 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
  76. P_matrix90 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
  77. P_matrix135 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
  78. if (size * size < 256)
  79. msize2 = size * size;
  80. else
  81. msize2 = 256;
  82. px = vector(msize2 + 1);
  83. py = vector(msize2 + 1);
  84. }
  85. static int bsearch_gray(int *array, int n, int val)
  86. {
  87. int lo, hi, mid;
  88. lo = 0;
  89. hi = n - 1;
  90. while (lo <= hi) {
  91. mid = (lo + hi) >> 1;
  92. if (array[mid] == val)
  93. return mid;
  94. if (array[mid] > val)
  95. hi = mid - 1;
  96. else
  97. lo = mid + 1;
  98. }
  99. return -1;
  100. }
  101. int set_vars(int **grays, int curr_row, int curr_col,
  102. int size, int offset, int t_d, int with_nulls)
  103. {
  104. int R0, R45, R90, R135, x, y;
  105. int row, col, row2, col2, rows, cols;
  106. int rowmin, rowmax, colmin, colmax, wrows, wcols, rowd, cold;
  107. int itone, jtone;
  108. int cnt;
  109. rows = cols = size;
  110. wrows = Rast_window_rows();
  111. wcols = Rast_window_cols();
  112. /* Determine the number of different gray scales (not maxval) */
  113. for (row = 0; row <= PGM_MAXMAXVAL; row++)
  114. tone[row] = -1;
  115. cnt = 0;
  116. rowmin = curr_row - offset;
  117. if (rowmin < 0)
  118. rowmin = 0;
  119. rowmax = curr_row + offset;
  120. if (rowmax > wrows - 1)
  121. rowmax = wrows - 1;
  122. colmin = curr_col - offset;
  123. if (colmin < 0)
  124. colmin = 0;
  125. colmax = curr_col + offset;
  126. if (colmax > wcols - 1)
  127. colmax = wcols - 1;
  128. for (row = rowmin; row <= rowmax; row++) {
  129. for (col = colmin; col <= colmax; col++) {
  130. if (grays[row][col] < 0) { /* No data pixel found */
  131. continue;
  132. }
  133. if (grays[row][col] > PGM_MAXMAXVAL)
  134. G_fatal_error(_("Too many categories (found: %i, max: %i). "
  135. "Try to rescale or reclassify the map"),
  136. grays[row][col], PGM_MAXMAXVAL);
  137. tone[grays[row][col]] = grays[row][col];
  138. cnt++;
  139. }
  140. }
  141. /* what is the minimum number of pixels
  142. * to get reasonable texture measurements ?
  143. * at the very least, any of R0, R45, R90, R135 must be > 1 */
  144. if (cnt < size * size / 4 || (!with_nulls && cnt < size * size))
  145. return 0;
  146. /* Collapse array, taking out all zero values */
  147. Ng = 0;
  148. for (row = 0; row <= PGM_MAXMAXVAL; row++) {
  149. if (tone[row] != -1)
  150. tone[Ng++] = tone[row];
  151. }
  152. /* Now array contains only the gray levels present (in ascending order) */
  153. for (row = 0; row < Ng; row++)
  154. for (col = 0; col < Ng; col++) {
  155. P_matrix0[row][col] = P_matrix45[row][col] = 0;
  156. P_matrix90[row][col] = P_matrix135[row][col] = 0;
  157. }
  158. /* Find normalizing constants */
  159. /* not correct in case of NULL cells: */
  160. /*
  161. R0 = 2 * rows * (cols - t_d);
  162. R45 = 2 * (rows - t_d) * (cols - t_d);
  163. R90 = 2 * (rows - t_d) * cols;
  164. R135 = R45;
  165. */
  166. /* count actual cooccurrences for each angle */
  167. R0 = R45 = R90 = R135 = 0;
  168. /* Find gray-tone spatial dependence matrix */
  169. for (row = 0; row < rows; row++) {
  170. row2 = curr_row - offset + row;
  171. if (row2 < 0 || row2 >= wrows)
  172. continue;
  173. for (col = 0; col < cols; col++) {
  174. col2 = curr_col - offset + col;
  175. if (col2 < 0 || col2 >= wcols)
  176. continue;
  177. if (grays[row2][col2] < 0)
  178. continue;
  179. x = bsearch_gray(tone, Ng, grays[row2][col2]);
  180. rowd = row2;
  181. cold = col2 + t_d;
  182. if (col + t_d < cols && cold < wcols &&
  183. grays[rowd][cold] >= 0) {
  184. y = bsearch_gray(tone, Ng, grays[rowd][cold]);
  185. P_matrix0[x][y]++;
  186. P_matrix0[y][x]++;
  187. R0 += 2;
  188. }
  189. rowd = row2 + t_d;
  190. cold = col2;
  191. if (row + t_d < rows && rowd < wrows &&
  192. grays[rowd][cold] >= 0) {
  193. y = bsearch_gray(tone, Ng, grays[rowd][cold]);
  194. P_matrix90[x][y]++;
  195. P_matrix90[y][x]++;
  196. R90 += 2;
  197. }
  198. rowd = row2 + t_d;
  199. cold = col2 - t_d;
  200. if (row + t_d < rows && rowd < wrows &&
  201. col - t_d >= 0 && cold >= 0 &&
  202. grays[rowd][cold] >= 0) {
  203. y = bsearch_gray(tone, Ng, grays[rowd][cold]);
  204. P_matrix45[x][y]++;
  205. P_matrix45[y][x]++;
  206. R45 += 2;
  207. }
  208. rowd = row2 + t_d;
  209. cold = col2 + t_d;
  210. if (row + t_d < rows && rowd < wrows &&
  211. col + t_d < cols && cold < wcols &&
  212. grays[rowd][cold] >= 0) {
  213. y = bsearch_gray(tone, Ng, grays[rowd][cold]);
  214. P_matrix135[x][y]++;
  215. P_matrix135[y][x]++;
  216. R135 += 2;
  217. }
  218. }
  219. }
  220. /* Gray-tone spatial dependence matrices are complete */
  221. /* Normalize gray-tone spatial dependence matrix */
  222. for (itone = 0; itone < Ng; itone++) {
  223. for (jtone = 0; jtone < Ng; jtone++) {
  224. P_matrix0[itone][jtone] /= R0;
  225. P_matrix45[itone][jtone] /= R45;
  226. P_matrix90[itone][jtone] /= R90;
  227. P_matrix135[itone][jtone] /= R135;
  228. }
  229. }
  230. return 1;
  231. }
  232. int set_angle_vars(int angle, int have_px, int have_py,
  233. int have_pxpys, int have_pxpyd)
  234. {
  235. int i, j;
  236. float **P;
  237. switch (angle) {
  238. case 0:
  239. P_matrix = P_matrix0;
  240. break;
  241. case 1:
  242. P_matrix = P_matrix45;
  243. break;
  244. case 2:
  245. P_matrix = P_matrix90;
  246. break;
  247. case 3:
  248. P_matrix = P_matrix135;
  249. break;
  250. }
  251. P = P_matrix;
  252. /*
  253. * px[i] is the (i-1)th entry in the marginal probability matrix obtained
  254. * by summing the rows of p[i][j]
  255. */
  256. /* Pxpy sum and difference */
  257. /* reset variabless */
  258. if (have_px || have_py || have_pxpys || have_pxpyd) {
  259. for (i = 0; i < Ng; i++) {
  260. if (have_px || have_py) {
  261. px[i] = py[i] = 0;
  262. }
  263. if (have_pxpys || have_pxpyd) {
  264. Pxpys[i] = Pxpyd[i] = 0;
  265. }
  266. }
  267. if (have_pxpys) {
  268. for (j = Ng; j < 2 * Ng; j++) {
  269. Pxpys[j] = 0;
  270. }
  271. }
  272. }
  273. if (have_pxpys || have_pxpyd || have_px || have_py) {
  274. for (i = 0; i < Ng; i++) {
  275. for (j = 0; j < Ng; j++) {
  276. if (have_px || have_py) {
  277. px[i] += P[i][j];
  278. py[j] += P[i][j];
  279. }
  280. if (have_pxpys) {
  281. Pxpys[i + j] += P[i][j];
  282. }
  283. if (have_pxpyd) {
  284. Pxpyd[abs(i - j)] += P[i][j];
  285. }
  286. }
  287. }
  288. }
  289. return 1;
  290. }
  291. float h_measure(int t_m)
  292. {
  293. switch (t_m) {
  294. /* Angular Second Moment */
  295. case 1:
  296. return (f1_asm());
  297. break;
  298. /* Contrast */
  299. case 2:
  300. return (f2_contrast());
  301. break;
  302. /* Correlation */
  303. case 3:
  304. return (f3_corr());
  305. break;
  306. /* Variance */
  307. case 4:
  308. return (f4_var());
  309. break;
  310. /* Inverse Diff Moment */
  311. case 5:
  312. return (f5_idm());
  313. break;
  314. /* Sum Average */
  315. case 6:
  316. return (f6_savg());
  317. break;
  318. /* Sum Variance */
  319. case 7:
  320. return (f7_svar());
  321. break;
  322. /* Sum Entropy */
  323. case 8:
  324. return (f8_sentropy());
  325. break;
  326. /* Entropy */
  327. case 9:
  328. return (f9_entropy());
  329. break;
  330. /* Difference Variance */
  331. case 10:
  332. return (f10_dvar());
  333. break;
  334. /* Difference Entropy */
  335. case 11:
  336. return (f11_dentropy());
  337. break;
  338. /* Measure of Correlation-1 */
  339. case 12:
  340. return (f12_icorr());
  341. break;
  342. /* Measure of Correlation-2 */
  343. case 13:
  344. return (f13_icorr());
  345. break;
  346. }
  347. return 0;
  348. }
  349. void MatrixDealloc(float **A, int N)
  350. {
  351. /*A is NxN */
  352. int i;
  353. for (i = 0; i < N; i++)
  354. G_free(A[i]);
  355. G_free(A);
  356. }
  357. /* Angular Second Moment */
  358. /*
  359. * The angular second-moment feature (ASM) f1 is a measure of homogeneity
  360. * of the image. In a homogeneous image, there are very few dominant
  361. * gray-tone transitions. Hence the P matrix for such an image will have
  362. * fewer entries of large magnitude.
  363. */
  364. float f1_asm(void)
  365. {
  366. int i, j;
  367. float sum = 0;
  368. float **P = P_matrix;
  369. /*
  370. for (i = 0; i < Ng; i++)
  371. for (j = 0; j < Ng; j++)
  372. sum += P[i][j] * P[i][j];
  373. */
  374. for (i = 0; i < Ng; i++) {
  375. sum += P[i][i] * P[i][i];
  376. for (j = 0; j < i; j++)
  377. sum += 2 * P[i][j] * P[i][j];
  378. }
  379. return sum;
  380. }
  381. /* Contrast */
  382. /*
  383. * The contrast feature is a difference moment of the P matrix and is a
  384. * measure of the contrast or the amount of local variations present in an
  385. * image.
  386. */
  387. float f2_contrast(void)
  388. {
  389. int i, j /*, n */;
  390. float /* sum,*/ bigsum = 0;
  391. float **P = P_matrix;
  392. /* the three-loop version does not work
  393. * when gray tones that do not occur in the current window
  394. * have been removed in tone and P* */
  395. /*
  396. for (n = 0; n < Ng; n++) {
  397. sum = 0;
  398. for (i = 0; i < Ng; i++) {
  399. for (j = 0; j < Ng; j++) {
  400. if ((i - j) == n ||
  401. (j - i) == n) {
  402. sum += P[i][j];
  403. }
  404. }
  405. }
  406. bigsum += n * n * sum;
  407. }
  408. */
  409. /* two-loop version */
  410. for (i = 0; i < Ng; i++) {
  411. for (j = 0; j < i; j++) {
  412. bigsum += 2 * P[i][j] * (tone[i] - tone[j]) * (tone[i] - tone[j]);
  413. }
  414. }
  415. return bigsum;
  416. }
  417. /* Correlation */
  418. /*
  419. * This correlation feature is a measure of gray-tone linear-dependencies
  420. * in the image.
  421. */
  422. float f3_corr(void)
  423. {
  424. int i, j;
  425. float sum_sqr = 0, tmp = 0;
  426. float mean = 0, stddev;
  427. float **P = P_matrix;
  428. /* Now calculate the means and standard deviations of px and py */
  429. /*- fix supplied by J. Michael Christensen, 21 Jun 1991 */
  430. /*- further modified by James Darrell McCauley, 16 Aug 1991
  431. * after realizing that meanx=meany and stddevx=stddevy
  432. */
  433. for (i = 0; i < Ng; i++) {
  434. mean += px[i] * tone[i];
  435. sum_sqr += px[i] * tone[i] * tone[i];
  436. for (j = 0; j < Ng; j++)
  437. tmp += tone[i] * tone[j] * P[i][j];
  438. }
  439. stddev = sqrt(sum_sqr - (mean * mean));
  440. if (stddev == 0) /* stddev < GRASS_EPSILON or similar ? */
  441. return 0;
  442. return (tmp - mean * mean) / (stddev * stddev);
  443. }
  444. /* Sum of Squares: Variance */
  445. float f4_var(void)
  446. {
  447. int i, j;
  448. float mean = 0, var = 0;
  449. float **P = P_matrix;
  450. /*- Corrected by James Darrell McCauley, 16 Aug 1991
  451. * calculates the mean intensity level instead of the mean of
  452. * cooccurrence matrix elements
  453. */
  454. for (i = 0; i < Ng; i++)
  455. for (j = 0; j < Ng; j++)
  456. mean += tone[i] * P[i][j];
  457. for (i = 0; i < Ng; i++)
  458. for (j = 0; j < Ng; j++)
  459. var += (tone[i] - mean) * (tone[i] - mean) * P[i][j];
  460. return var;
  461. }
  462. /* Inverse Difference Moment */
  463. float f5_idm(void)
  464. {
  465. int i, j;
  466. float idm = 0;
  467. float **P = P_matrix;
  468. /*
  469. for (i = 0; i < Ng; i++)
  470. for (j = 0; j < Ng; j++)
  471. idm += P[i][j] / (1 + (tone[i] - tone[j]) * (tone[i] - tone[j]));
  472. */
  473. for (i = 0; i < Ng; i++) {
  474. idm += P[i][i];
  475. for (j = 0; j < i; j++)
  476. idm += 2 * P[i][j] / (1 + (tone[i] - tone[j]) * (tone[i] - tone[j]));
  477. }
  478. return idm;
  479. }
  480. /* Sum Average */
  481. float f6_savg(void)
  482. {
  483. int i, j, k;
  484. float savg = 0;
  485. float *P = Pxpys;
  486. /*
  487. for (i = 0; i < 2 * Ng - 1; i++)
  488. savg += (i + 2) * Pxpys[i];
  489. */
  490. for (i = 0; i < Ng; i++) {
  491. for (j = 0; j < Ng; j++) {
  492. k = i + j;
  493. savg += (tone[i] + tone[j]) * P[k];
  494. }
  495. }
  496. return savg;
  497. }
  498. /* Sum Variance */
  499. float f7_svar(void)
  500. {
  501. int i, j, k;
  502. float var = 0;
  503. float *P = Pxpys;
  504. float savg = f6_savg();
  505. float tmp;
  506. /*
  507. for (i = 0; i < 2 * Ng - 1; i++)
  508. var += (i + 2 - savg) * (i + 2 - savg) * Pxpys[i];
  509. */
  510. for (i = 0; i < Ng; i++) {
  511. for (j = 0; j < Ng; j++) {
  512. k = i + j;
  513. tmp = tone[i] + tone[j] - savg;
  514. var += tmp * tmp * P[k];
  515. }
  516. }
  517. return var;
  518. }
  519. /* Sum Entropy */
  520. float f8_sentropy(void)
  521. {
  522. int i;
  523. float sentr = 0;
  524. float *P = Pxpys;
  525. for (i = 0; i < 2 * Ng - 1; i++) {
  526. if (P[i] > 0)
  527. sentr -= P[i] * log2(P[i]);
  528. }
  529. return sentr;
  530. }
  531. /* Entropy */
  532. float f9_entropy(void)
  533. {
  534. int i, j;
  535. float entropy = 0;
  536. float **P = P_matrix;
  537. /*
  538. for (i = 0; i < Ng; i++) {
  539. for (j = 0; j < Ng; j++) {
  540. if (P[i][j] > 0)
  541. entropy += P[i][j] * log2(P[i][j]);
  542. }
  543. }
  544. */
  545. for (i = 0; i < Ng; i++) {
  546. if (P[i][i] > 0)
  547. entropy += P[i][i] * log2(P[i][i]);
  548. for (j = 0; j < i; j++) {
  549. if (P[i][j] > 0)
  550. entropy += 2 * P[i][j] * log2(P[i][j]);
  551. }
  552. }
  553. return -entropy;
  554. }
  555. /* Difference Variance */
  556. float f10_dvar(void)
  557. {
  558. int i, tmp;
  559. float sum = 0, sum_sqr = 0, var = 0;
  560. float *P = Pxpyd;
  561. /* Now calculate the variance of Pxpy (Px-y) */
  562. for (i = 0; i < Ng; i++) {
  563. sum += P[i];
  564. sum_sqr += P[i] * P[i];
  565. }
  566. /* tmp = Ng * Ng; */
  567. if (Ng > 1) {
  568. tmp = (tone[Ng - 1] - tone[0]) * (tone[Ng - 1] - tone[0]);
  569. var = ((tmp * sum_sqr) - (sum * sum)) / (tmp * tmp);
  570. }
  571. return var;
  572. }
  573. /* Difference Entropy */
  574. float f11_dentropy(void)
  575. {
  576. int i;
  577. float sum = 0;
  578. float *P = Pxpyd;
  579. for (i = 0; i < Ng; i++) {
  580. if (P[i] > 0)
  581. sum += P[i] * log2(P[i]);
  582. }
  583. return -sum;
  584. }
  585. /* Information Measures of Correlation */
  586. float f12_icorr(void)
  587. {
  588. int i, j;
  589. float hx = 0, hy = 0, hxy = 0, hxy1 = 0;
  590. float **P = P_matrix;
  591. for (i = 0; i < Ng; i++) {
  592. for (j = 0; j < Ng; j++) {
  593. if (px[i] * py[j] > 0)
  594. hxy1 -= P[i][j] * log2(px[i] * py[j]);
  595. if (P[i][j] > 0)
  596. hxy -= P[i][j] * log2(P[i][j]);
  597. }
  598. /* Calculate entropies of px and py - is this right? */
  599. if (px[i] > 0)
  600. hx -= px[i] * log2(px[i]);
  601. if (py[i] > 0)
  602. hy -= py[i] * log2(py[i]);
  603. }
  604. /* fprintf(stderr,"hxy1=%f\thxy=%f\thx=%f\thy=%f\n",hxy1,hxy,hx,hy); */
  605. if (hx == 0 && hy == 0)
  606. return 0;
  607. return ((hxy - hxy1) / (hx > hy ? hx : hy));
  608. }
  609. /* Information Measures of Correlation */
  610. float f13_icorr(void)
  611. {
  612. int i, j;
  613. float hxy = 0, hxy2 = 0;
  614. float **P = P_matrix;
  615. for (i = 0; i < Ng; i++) {
  616. for (j = 0; j < Ng; j++) {
  617. if (px[i] * py[j] > 0)
  618. hxy2 -= px[i] * py[j] * log2(px[i] * py[j]);
  619. if (P[i][j] > 0)
  620. hxy -= P[i][j] * log2(P[i][j]);
  621. }
  622. }
  623. /* fprintf(stderr,"hx=%f\thxy2=%f\n",hx,hxy2); */
  624. return (sqrt(fabs(1 - exp(-2.0 * (hxy2 - hxy)))));
  625. }
  626. float *vector(int n)
  627. {
  628. float *v;
  629. v = (float *)G_malloc(n * sizeof(float));
  630. if (!v)
  631. G_fatal_error(_("Unable to allocate memory")), exit(EXIT_FAILURE);
  632. return v;
  633. }
  634. /* Allocates a float matrix with range [nrl..nrh][ncl..nch] */
  635. float **matrix(int nr, int nc)
  636. {
  637. int i;
  638. float **m;
  639. /* allocate pointers to rows */
  640. m = (float **)G_malloc(nr * sizeof(float *));
  641. /* allocate rows */
  642. for (i = 0; i < nr; i++) {
  643. m[i] = (float *)G_malloc(nc * sizeof(float));
  644. }
  645. /* return pointer to array of pointers to rows */
  646. return m;
  647. }