proffreda

poisson.cu

Nov 18th, 2016
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.75 KB | None | 0 0
  1.  
  2. #include "utils.h"
  3. #include <algorithm>
  4.  
  5. // get 2d position from block
  6. __device__
  7. int2 get2dPos() {
  8. return make_int2(
  9. blockIdx.x * blockDim.x + threadIdx.x,
  10. blockIdx.y * blockDim.y + threadIdx.y
  11. );
  12. }
  13.  
  14. // check whether a a value is within the image bounds
  15. __device__
  16. bool withinBounds(const int x, const int y, const size_t numRowsSource, const size_t numColsSource) {
  17. return ((x < numColsSource) && (y < numRowsSource));
  18. }
  19.  
  20. __device__
  21. bool masked(uchar4 val) {
  22. return (val.x != 255 || val.y != 255 || val.z != 255);
  23. }
  24.  
  25. __device__
  26. int getm(int x, int y, size_t numColsSource) {
  27. return y*numColsSource + x;
  28. }
  29.  
  30. __global__
  31. void maskPredicateKernel(
  32. const uchar4* const d_sourceImg,
  33. int* d_borderPredicate,
  34. int* d_interiorPredicate,
  35. const size_t numRowsSource,
  36. const size_t numColsSource) {
  37.  
  38. const int2 p = get2dPos();
  39. const int m = getm(p.x, p.y, numColsSource);
  40.  
  41. if(!withinBounds(p.x, p.y, numRowsSource, numColsSource))
  42. return;
  43.  
  44. // run through each pixel and determine if its
  45. // on the border, or if its on the interior border
  46.  
  47. if(masked(d_sourceImg[m])) {
  48. int inbounds = 0;
  49. int interior = 0;
  50.  
  51. // count how many of our neighbors are masked,
  52. // and how many neighbors we have
  53. if (withinBounds(p.x, p.y+1, numRowsSource, numColsSource)) {
  54. inbounds++;
  55. if(masked(d_sourceImg[getm(p.x, p.y+1, numColsSource)]))
  56. interior++;
  57.  
  58. }
  59. if (withinBounds(p.x, p.y-1, numRowsSource, numColsSource)) {
  60. inbounds++;
  61. if(masked(d_sourceImg[getm(p.x, p.y-1, numColsSource)]))
  62. interior++;
  63.  
  64. }
  65. if (withinBounds(p.x+1, p.y, numRowsSource, numColsSource)) {
  66. inbounds++;
  67. if(masked(d_sourceImg[getm(p.x+1, p.y, numColsSource)]))
  68. interior++;
  69. }
  70. if (withinBounds(p.x-1, p.y, numRowsSource, numColsSource)) {
  71. inbounds++;
  72. if(masked(d_sourceImg[getm(p.x-1, p.y, numColsSource)]))
  73. interior++;
  74. }
  75.  
  76. // clear out the values so we don't
  77. // have to memset this destination stuff
  78. d_interiorPredicate[m] = 0;
  79. d_borderPredicate[m] = 0;
  80.  
  81. // if all our neighbors are masked, then its interior
  82. if(inbounds == interior) {
  83. d_interiorPredicate[m] = 1;
  84. } else if (interior > 0) {
  85. d_borderPredicate[m] = 1;
  86. }
  87. }
  88. }
  89.  
  90. __global__
  91. void separateChannelsKernel(
  92. const uchar4* const inputImageRGBA,
  93. float* const redChannel,
  94. float* const greenChannel,
  95. float* const blueChannel,
  96. size_t numRows,
  97. size_t numCols)
  98. {
  99. const int2 p = get2dPos();
  100. const int m = getm(p.x, p.y, numCols);
  101.  
  102. if(!withinBounds(p.x, p.y, numRows, numCols))
  103. return;
  104.  
  105. redChannel[m] = (float)inputImageRGBA[m].x;
  106. greenChannel[m] = (float)inputImageRGBA[m].y;
  107. blueChannel[m] = (float)inputImageRGBA[m].z;
  108. }
  109.  
  110. __global__
  111. void recombineChannelsKernel(
  112. uchar4* outputImageRGBA,
  113. float* const redChannel,
  114. float* const greenChannel,
  115. float* const blueChannel,
  116. size_t numRows,
  117. size_t numCols)
  118. {
  119. const int2 p = get2dPos();
  120. const int m = getm(p.x, p.y, numCols);
  121.  
  122. if(!withinBounds(p.x, p.y, numRows, numCols))
  123. return;
  124.  
  125. outputImageRGBA[m].x = (char)redChannel[m];
  126. outputImageRGBA[m].y = (char)greenChannel[m];
  127. outputImageRGBA[m].z = (char)blueChannel[m];
  128. }
  129.  
  130. __global__
  131. void jacobiKernel(
  132. float* d_in,
  133. float* d_out,
  134. const int* d_borderPredicate,
  135. const int* d_interiorPredicate,
  136. float* d_source,
  137. float* d_dest,
  138. size_t numRows,
  139. size_t numCols)
  140. {
  141. const int2 p = get2dPos();
  142. const int m = getm(p.x, p.y, numCols);
  143.  
  144. if(!withinBounds(p.x, p.y, numRows, numCols))
  145. return;
  146.  
  147. // calculate these values as indicated in the videos
  148.  
  149. int lm;
  150. if(d_interiorPredicate[m]==1) {
  151. float a = 0.f, b=0.f, c=0.0f, d=0.f;
  152. float sourceVal = d_source[m];
  153.  
  154. if(withinBounds(p.x, p.y+1, numRows, numCols)) {
  155. d++;
  156. lm = getm(p.x, p.y+1, numCols);
  157. if(d_interiorPredicate[lm]==1) {
  158. a += d_in[lm];
  159. } else if(d_borderPredicate[lm]==1) {
  160. b += d_dest[lm];
  161. }
  162. c += (sourceVal-d_source[lm]);
  163. }
  164.  
  165. if(withinBounds(p.x, p.y-1, numRows, numCols)) {
  166. d++;
  167. lm = getm(p.x, p.y-1, numCols);
  168. if(d_interiorPredicate[lm]==1) {
  169. a += d_in[lm];
  170. } else if(d_borderPredicate[lm]==1) {
  171. b += d_dest[lm];
  172. }
  173. c += (sourceVal-d_source[lm]);
  174. }
  175.  
  176. if(withinBounds(p.x+1, p.y, numRows, numCols)) {
  177. d++;
  178. lm = getm(p.x+1, p.y, numCols);
  179. if(d_interiorPredicate[lm]==1) {
  180. a += d_in[lm];
  181. } else if(d_borderPredicate[lm]==1) {
  182. b += d_dest[lm];
  183. }
  184. c += (sourceVal-d_source[lm]);
  185. }
  186.  
  187. if(withinBounds(p.x-1, p.y, numRows, numCols)) {
  188. d++;
  189. lm = getm(p.x-1, p.y, numCols);
  190. if(d_interiorPredicate[lm]==1) {
  191. a += d_in[lm];
  192. } else if(d_borderPredicate[lm]==1) {
  193. b += d_dest[lm];
  194. }
  195. c += (sourceVal-d_source[lm]);
  196. }
  197.  
  198. d_out[m] = min(255.f, max(0.0, (a + b + c)/d));
  199. } else {
  200. d_out[m] = d_dest[m];
  201. }
  202.  
  203. }
  204.  
  205. void your_blend(const uchar4* const h_sourceImg, //IN
  206. const size_t numRowsSource, const size_t numColsSource,
  207. const uchar4* const h_destImg, //IN
  208. uchar4* const h_blendedImg) //OUT
  209. {
  210. // first push the dest and source onto the gpu
  211. size_t imageSize = numRowsSource*numColsSource*sizeof(uchar4);
  212.  
  213. uchar4* d_sourceImg;
  214. uchar4* d_destImg;
  215. uchar4* d_finalImg;
  216.  
  217. checkCudaErrors(cudaMalloc(&d_sourceImg, imageSize));
  218. checkCudaErrors(cudaMalloc(&d_destImg, imageSize));
  219. checkCudaErrors(cudaMalloc(&d_finalImg, imageSize));
  220.  
  221. checkCudaErrors(cudaMemcpy(d_sourceImg, h_sourceImg, imageSize, cudaMemcpyHostToDevice));
  222. checkCudaErrors(cudaMemcpy(d_destImg, h_destImg, imageSize, cudaMemcpyHostToDevice));
  223.  
  224. // allocate predicate stuff
  225. size_t predicateSize = numRowsSource*numColsSource*sizeof(int);
  226. int* d_borderPredicate;
  227. int* d_interiorPredicate;
  228.  
  229. checkCudaErrors(cudaMalloc(&d_borderPredicate, predicateSize));
  230. checkCudaErrors(cudaMalloc(&d_interiorPredicate, predicateSize));
  231.  
  232. // make reusable dims
  233. const dim3 blockSize(32, 32);
  234. const dim3 gridSize(numColsSource/blockSize.x + 1, numRowsSource/blockSize.y + 1);
  235.  
  236.  
  237. /**
  238. 1) Compute a mask of the pixels from the source image to be copied
  239. The pixels that shouldn't be copied are completely white, they
  240. have R=255, G=255, B=255. Any other pixels SHOULD be copied.
  241. **/
  242.  
  243. /**
  244. 2) Compute the interior and border regions of the mask. An interior
  245. pixel has all 4 neighbors also inside the mask. A border pixel is
  246. in the mask itself, but has at least one neighbor that isn't.
  247. **/
  248.  
  249. // generate the predicates
  250. maskPredicateKernel<<<gridSize, blockSize>>>(
  251. d_sourceImg,
  252. d_borderPredicate,
  253. d_interiorPredicate,
  254. numRowsSource,
  255. numColsSource
  256. );
  257.  
  258. cudaDeviceSynchronize(); checkCudaErrors(cudaGetLastError());
  259.  
  260. /**
  261. 3) Separate out the incoming image into three separate channels
  262. **/
  263. size_t floatSize = numRowsSource*numColsSource*sizeof(float);
  264. float *d_sourceImgR, *d_sourceImgG, *d_sourceImgB;
  265. float *d_destImgR, *d_destImgG, *d_destImgB;
  266.  
  267. checkCudaErrors(cudaMalloc(&d_sourceImgR, floatSize));
  268. checkCudaErrors(cudaMalloc(&d_sourceImgG, floatSize));
  269. checkCudaErrors(cudaMalloc(&d_sourceImgB, floatSize));
  270.  
  271. checkCudaErrors(cudaMalloc(&d_destImgR, floatSize));
  272. checkCudaErrors(cudaMalloc(&d_destImgG, floatSize));
  273. checkCudaErrors(cudaMalloc(&d_destImgB, floatSize));
  274.  
  275. separateChannelsKernel<<<gridSize, blockSize>>>(
  276. d_sourceImg,
  277. d_sourceImgR,
  278. d_sourceImgG,
  279. d_sourceImgB,
  280. numRowsSource,
  281. numColsSource);
  282.  
  283. cudaDeviceSynchronize(); checkCudaErrors(cudaGetLastError());
  284.  
  285. separateChannelsKernel<<<gridSize, blockSize>>>(
  286. d_destImg,
  287. d_destImgR,
  288. d_destImgG,
  289. d_destImgB,
  290. numRowsSource,
  291. numColsSource);
  292.  
  293. cudaDeviceSynchronize(); checkCudaErrors(cudaGetLastError());
  294.  
  295. /**
  296. 4) Create two float(!) buffers for each color channel that will
  297. act as our guesses. Initialize them to the respective color
  298. channel of the source image since that will act as our intial guess.
  299. **/
  300.  
  301. // allocate floats
  302. float *d_r0, *d_r1, *d_g0, *d_g1, *d_b0, *d_b1;
  303. checkCudaErrors(cudaMalloc(&d_r0, floatSize));
  304. checkCudaErrors(cudaMalloc(&d_r1, floatSize));
  305. checkCudaErrors(cudaMalloc(&d_b0, floatSize));
  306. checkCudaErrors(cudaMalloc(&d_b1, floatSize));
  307. checkCudaErrors(cudaMalloc(&d_g0, floatSize));
  308. checkCudaErrors(cudaMalloc(&d_g1, floatSize));
  309.  
  310.  
  311. checkCudaErrors(cudaMemcpy(d_r0, d_sourceImgR, floatSize, cudaMemcpyDeviceToDevice));
  312. checkCudaErrors(cudaMemcpy(d_g0, d_sourceImgG, floatSize, cudaMemcpyDeviceToDevice));
  313. checkCudaErrors(cudaMemcpy(d_b0, d_sourceImgB, floatSize, cudaMemcpyDeviceToDevice));
  314.  
  315. cudaDeviceSynchronize(); checkCudaErrors(cudaGetLastError());
  316.  
  317. /**
  318. 5) For each color channel perform the Jacobi iteration described
  319. above 800 times.
  320. **/
  321. for(int i = 0; i < 800; i++) {
  322. jacobiKernel<<<gridSize, blockSize>>>(
  323. d_r0,
  324. d_r1,
  325. d_borderPredicate,
  326. d_interiorPredicate,
  327. d_sourceImgR,
  328. d_destImgR,
  329. numRowsSource,
  330. numColsSource
  331. );
  332. std::swap(d_r0, d_r1);
  333.  
  334. jacobiKernel<<<gridSize, blockSize>>>(
  335. d_g0,
  336. d_g1,
  337. d_borderPredicate,
  338. d_interiorPredicate,
  339. d_sourceImgG,
  340. d_destImgG,
  341. numRowsSource,
  342. numColsSource
  343. );
  344. std::swap(d_g0, d_g1);
  345.  
  346. jacobiKernel<<<gridSize, blockSize>>>(
  347. d_b0,
  348. d_b1,
  349. d_borderPredicate,
  350. d_interiorPredicate,
  351. d_sourceImgB,
  352. d_destImgB,
  353. numRowsSource,
  354. numColsSource
  355. );
  356. std::swap(d_b0, d_b1);
  357. }
  358.  
  359. /**
  360. 6) Create the output image by replacing all the interior pixels
  361. in the destination image with the result of the Jacobi iterations.
  362. Just cast the floating point values to unsigned chars since we have
  363. already made sure to clamp them to the correct range.
  364. **/
  365.  
  366. // lets assume that d_r0, d_g0, d_b0 are the final pass
  367. recombineChannelsKernel<<<gridSize, blockSize>>>(
  368. d_finalImg,
  369. d_r0,
  370. d_g0,
  371. d_b0,
  372. numRowsSource,
  373. numColsSource);
  374.  
  375. cudaDeviceSynchronize(); checkCudaErrors(cudaGetLastError());
  376.  
  377. // copy device final image to host
  378. checkCudaErrors(cudaMemcpy(h_blendedImg, d_finalImg, imageSize, cudaMemcpyDeviceToHost));
  379.  
  380. // cleanup
  381. checkCudaErrors(cudaFree(d_sourceImg));
  382. checkCudaErrors(cudaFree(d_destImg));
  383. checkCudaErrors(cudaFree(d_finalImg));
  384.  
  385. checkCudaErrors(cudaFree(d_sourceImgR));
  386. checkCudaErrors(cudaFree(d_sourceImgG));
  387. checkCudaErrors(cudaFree(d_sourceImgB));
  388.  
  389. checkCudaErrors(cudaFree(d_destImgR));
  390. checkCudaErrors(cudaFree(d_destImgG));
  391. checkCudaErrors(cudaFree(d_destImgB));
  392.  
  393. checkCudaErrors(cudaFree(d_r0));
  394. checkCudaErrors(cudaFree(d_r1));
  395. checkCudaErrors(cudaFree(d_g0));
  396. checkCudaErrors(cudaFree(d_g1));
  397. checkCudaErrors(cudaFree(d_b0));
  398. checkCudaErrors(cudaFree(d_b1));
  399. }
Advertisement
Add Comment
Please, Sign In to add comment