fconv2D.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include "mex.h"
  2. #include <math.h>
  3. #include <string.h>
  4. /*
  5. * This code is used for computing filter responses. It computes the
  6. * response of a set of filters with a feature map.
  7. *
  8. * Basic version, relatively slow but very compatible.
  9. */
  10. struct thread_data {
  11. double *A;
  12. double *B;
  13. double *C;
  14. mxArray *mxC;
  15. const mwSize *A_dims;
  16. const mwSize *B_dims;
  17. mwSize C_dims[2];
  18. };
  19. // convolve A and B
  20. void *process(void *thread_arg)
  21. {
  22. thread_data *args = (thread_data *)thread_arg;
  23. //input A - e.g., an image
  24. double *A = args->A;
  25. //input B - e.g., a filter
  26. double *B = args->B;
  27. //output C - the convolution response map
  28. double *C = args->C;
  29. const mwSize *A_dims = args->A_dims;
  30. const mwSize *B_dims = args->B_dims;
  31. const mwSize *C_dims = args->C_dims;
  32. //new pointers just for comparability with original fconv.cc
  33. double *dst = C;
  34. double *A_src = A;
  35. double *B_src = B;
  36. //run over possible locations on x dimension
  37. for (int x = 0; x < C_dims[1]; x++)
  38. {
  39. //run over possible locations on y dimension
  40. for (int y = 0; y < C_dims[0]; y++)
  41. {
  42. // compute convolution score for current position
  43. // loop over filter size
  44. double val = 0;
  45. for (int xp = 0; xp < B_dims[1]; xp++)
  46. {
  47. double *A_off = A_src + (x+xp)*A_dims[0] + y;
  48. double *B_off = B_src + xp*B_dims[0];
  49. //hope-to-be efficient version for up to 20 dimensions
  50. switch(B_dims[0])
  51. {
  52. case 20: val += A_off[19] * B_off[19];
  53. case 19: val += A_off[18] * B_off[18];
  54. case 18: val += A_off[17] * B_off[17];
  55. case 17: val += A_off[16] * B_off[16];
  56. case 16: val += A_off[15] * B_off[15];
  57. case 15: val += A_off[14] * B_off[14];
  58. case 14: val += A_off[13] * B_off[13];
  59. case 13: val += A_off[12] * B_off[12];
  60. case 12: val += A_off[11] * B_off[11];
  61. case 11: val += A_off[10] * B_off[10];
  62. case 10: val += A_off[9] * B_off[9];
  63. case 9: val += A_off[8] * B_off[8];
  64. case 8: val += A_off[7] * B_off[7];
  65. case 7: val += A_off[6] * B_off[6];
  66. case 6: val += A_off[5] * B_off[5];
  67. case 5: val += A_off[4] * B_off[4];
  68. case 4: val += A_off[3] * B_off[3];
  69. case 3: val += A_off[2] * B_off[2];
  70. case 2: val += A_off[1] * B_off[1];
  71. case 1: val += A_off[0] * B_off[0];
  72. break;
  73. // less efficient version with more than 20 dimensions
  74. default:
  75. for (int yp = 0; yp < B_dims[0]; yp++)
  76. {
  77. val += *(A_off++) * *(B_off++);
  78. }
  79. } // nasty switch-statement
  80. } //for-loop over filtersize
  81. //write value to current position in output data and increment output pointer
  82. *(dst++) += val;
  83. } // for-loop over y-positions
  84. } // for-loop over x-positions
  85. }
  86. // matlab entry point
  87. // C = fconv(A, cell of B, start, end);
  88. // for convolving a single filter with an image, call fconv2D( A, B, 1, 1)
  89. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
  90. if (nrhs != 4)
  91. mexErrMsgTxt("Wrong number of inputs");
  92. if (nlhs != 1)
  93. mexErrMsgTxt("Wrong number of outputs");
  94. // get input A, e.g., an image
  95. const mxArray *mxA = prhs[0];
  96. // safety check for input A
  97. if ( mxGetNumberOfDimensions(mxA) != 2 /* only single dimension feature matrices supported here*/ ||
  98. mxGetClassID(mxA) != mxDOUBLE_CLASS
  99. )
  100. {
  101. mexErrMsgTxt("Invalid input: A");
  102. }
  103. // get input B, e.g., a cell array of filters, and start/end indices for cells to use
  104. const mxArray *cellB = prhs[1];
  105. mwSize num_bs = mxGetNumberOfElements(cellB);
  106. // with which filter to start
  107. int start = (int)mxGetScalar(prhs[2]) - 1;
  108. // with which filter to end
  109. int end = (int)mxGetScalar(prhs[3]) - 1;
  110. // safety check for start and end wrt input cell array B
  111. if ( (start < 0) || (end >= num_bs) || (start > end) )
  112. {
  113. mexErrMsgTxt("Invalid input: start/end");
  114. }
  115. int i_numOfFilters = end-start+1;
  116. // output cell
  117. plhs[0] = mxCreateCellMatrix(1, i_numOfFilters);
  118. // do convolutions
  119. thread_data td;
  120. const mwSize *A_dims = mxGetDimensions(mxA);
  121. double *A = (double *)mxGetPr(mxA);
  122. for ( int i = 0; i < i_numOfFilters; i++ )
  123. {
  124. const mxArray *mxB = mxGetCell(cellB, i+start);
  125. td.A_dims = A_dims;
  126. td.A = A;
  127. td.B_dims = mxGetDimensions(mxB);
  128. td.B = (double *)mxGetPr(mxB);
  129. // safety check for input B
  130. if ( mxGetNumberOfDimensions(mxB) != 2 /* only single dimension feature matrices supported here*/ ||
  131. mxGetClassID(mxB) != mxDOUBLE_CLASS
  132. )
  133. {
  134. mexErrMsgTxt("Invalid input: B");
  135. }
  136. // compute size of output
  137. int height = td.A_dims[0] - td.B_dims[0] + 1;
  138. int width = td.A_dims[1] - td.B_dims[1] + 1;
  139. if ( (height < 1) || (width < 1) )
  140. mexErrMsgTxt("Invalid input: B should be smaller than A");
  141. td.C_dims[0] = height;
  142. td.C_dims[1] = width;
  143. td.mxC = mxCreateNumericArray(2, td.C_dims, mxDOUBLE_CLASS, mxREAL);
  144. td.C = (double *)mxGetPr(td.mxC);
  145. // call the main function doing the hacky convolution
  146. process( (void *)&td );
  147. mxSetCell(plhs[0], i, td.mxC);
  148. }
  149. }