当前位置:   article > 正文

双目视觉(五)立体匹配算法之动态规划全局匹配_全局匹配算法

全局匹配算法

系列文章:

  1. 双目视觉(一)双目视觉系统
  2. 双目视觉(二)双目匹配的困难和评判标准
  3. 双目视觉(三)立体匹配算法
  4. 双目视觉(四)匹配代价
  5. 双目视觉(五)立体匹配算法之动态规划全局匹配
  6. 双目视觉(六)U-V视差
  7. 【项目实战】利用U-V视差进行地面检测
  8. 【项目实践】U-V视差路面检测之动态规划      

代码:GitHub stereo matchhttps://github.com/Xke1718He/stereo-matchicon-default.png?t=N3I4https://github.com/Xke1718He/stereo-match

注:分享的代码中,双目匹配的代价只有一种,如果觉得不错,可以给予支持,谢谢^0^

全局匹配算法:

全局匹配主要是利用图像的全局约束信息,通过构建全局能量函数,然后通过优化方法最小化全局能量函数以求得致密视差图。目前优化方法主要有:动态规划(DP)、置信传播(BP)、模拟退火、图割法(GC)等。

动态规划

动态规划的思想就是把求解整个过程分解为若干子过程,逐个求解子过程。例如斐波那契数列,fib(6)分解为fib(5)和fib(4),而fib(5)分解为fib(4)和fib(3),fib(4)为一个重复子问题,而动态规划就是解决这类问题的方式之一。

这是我学习动态规划相关知识的链接:

动态规划 (第1讲)_哔哩哔哩_bilibili

【动态规划专题班】ACM总冠军、清华+斯坦福大神带你入门动态规划算法_哔哩哔哩_bilibili

在双目匹配中,动态规划立体匹配是基于极线约束,通过依次寻找每条极线上匹配点对的最小代价路径的动态寻优方法求解全局能量最小化,得到匹配视差图。

步骤大致如下:

  • step1.构建全局能量函数

其中,为数据项,一般表示为代价函数;为视差平滑约束项。

  • step2. 代价函数构建

代价函数构建这里采用的是块匹配,也就是以第一图像待匹配点为中心像素创建一个n*n的窗口,在第二幅图像中,沿着极线取出与基准点领域同样大小为n*n的领域,进行领域内的相似度函数的计算。

说明:代价函数采用的是C++中的继承构建

  • imageType:判断左右图像的信息相似性。比如大小是否一样大呀。
  • aggregate:这也就是所谓的代价聚合函数,计算左右图像领域内的相似性度量的。
  1. class CostFunction {
  2. public:
  3. float lambda;
  4. cv::Mat left;//左图像
  5. cv::Mat right;//右图像
  6. int blocksize;//block大小
  7. int margin;//块的边界
  8. float normCost;
  9. float normWin;
  10. //构造函数
  11. CostFunction( cv::Mat left, cv::Mat right, float lambda)
  12. {
  13. lambda = 1.0;
  14. this->left = left;
  15. this->right = right;
  16. imageType(left, right);
  17. this->lambda = lambda;
  18. }
  19. //虚构函数
  20. virtual bool imageType(cv::Mat left, cv::Mat right) {
  21. assert(left.size() == right.size());
  22. return true;
  23. }
  24. //代价聚合
  25. virtual float aggregate(int x1, int x2, int y) = 0;
  26. float p(float cost) {
  27. return 1 - exp(-cost / lambda);
  28. }
  29. ~CostFunction() {}
  30. };
  31. class RGBCost : public CostFunction {
  32. public:
  33. RGBCost(cv::Mat left, cv::Mat right, float lambda) : CostFunction(left, right, lambda) {}
  34. bool imageType(cv::Mat left, cv::Mat right) {
  35. assert(left.type() == right.type() && "imgL imgR types not equal");
  36. assert(left.type() == CV_8UC3 && "img type not supported");
  37. return true;
  38. }
  39. // aggregate over a ROI of input images
  40. float aggregate(int x1, int x2, int y) {
  41. float sum = 0;
  42. for (int i = y - margin; i <= y + margin; ++i) {
  43. cv::Vec3b* lptr = left.ptr<cv::Vec3b>(i);
  44. cv::Vec3b* rptr = right.ptr<cv::Vec3b>(i);
  45. for ( int j = -margin; j <= margin; ++j) {
  46. sum += eukl(lptr[x1 + j], rptr[x2 + j]); // cost function
  47. }
  48. }
  49. return sum / sqrt(255*255 + 255*255+255*255); // normalize to winsize*1.0
  50. }
  51. float eukl(cv::Vec3b l, cv::Vec3b r) {
  52. float a = l[0] - r[0];
  53. float b = l[1] - r[1];
  54. float c = l[2] - r[2];
  55. return std::sqrt(a*a + b*b + c*c);
  56. }
  57. ~RGBCost() {}
  58. };
  59. class FloatCost : public CostFunction {
  60. public:
  61. FloatCost(cv::Mat left, cv::Mat right, float lambda) : CostFunction(left, right, lambda) {}
  62. bool imageType(cv::Mat left, cv::Mat right) {
  63. assert(left.type() == right.type() && "imgL imgR types not equal");
  64. assert(left.type() == CV_32F && "img type not supported");
  65. return true;
  66. }
  67. // aggregate over a ROI of input images
  68. float aggregate(int x1, int x2, int y) {
  69. float sum = 0;
  70. for (int i = y - margin; i <= y + margin; ++i) {
  71. float* lptr = left.ptr<float>(i);
  72. float* rptr = right.ptr<float>(i);
  73. for ( int j = -margin ; j <= margin; ++j) {
  74. sum += abs(lptr[x1 + j] - rptr[x2 + j]); // cost function
  75. }
  76. }
  77. return sum / (blocksize*blocksize*lambda);
  78. }
  79. };
  80. class CondHistCost : public CostFunction {
  81. public:
  82. cv::Mat nuLeft, nuRight;
  83. CondHistCost(cv::Mat left, cv::Mat right, float lambda) : CostFunction(left, right, lambda) {
  84. cv::Mat histl = condHist(left, 3);
  85. nuLeft = switchColors(left, histl);
  86. cv::Mat histr = condHist(right, 3);
  87. nuRight = switchColors(right, histr);
  88. }
  89. bool imageType(cv::Mat left, cv::Mat right) {
  90. assert(left.type() == right.type() && "imgL imgR types not equal");
  91. assert(left.type() == CV_32F && "img type not supported");
  92. return true;
  93. }
  94. // aggregate over a ROI of input images
  95. float aggregate(int x1, int x2, int y) {
  96. float sum = 0;
  97. for (int i = y - margin; i <= y + margin; ++i) {
  98. float* lptr = nuLeft.ptr<float>(i);
  99. float* rptr = nuRight.ptr<float>(i);
  100. for ( int j = -margin ; j <= margin; ++j) {
  101. sum += abs(lptr[x1 + j] - rptr[x2 + j]); // cost function
  102. }
  103. }
  104. return sum / (blocksize*blocksize*lambda);
  105. }
  106. };
  107. class GrayCost : public CostFunction {
  108. public:
  109. GrayCost(cv::Mat left, cv::Mat right, float lambda) : CostFunction(left, right, lambda) {}
  110. bool imageType(cv::Mat left, cv::Mat right) {
  111. assert(left.type() == right.type() && "imgL imgR types not equal");
  112. assert(left.type() == CV_8UC1 && "img type not supported");
  113. return true;
  114. }
  115. // aggregate over a ROI of input images
  116. float aggregate(int x1, int x2, int y) {
  117. float sum = 0;
  118. for (int i = y - margin; i <= y + margin; ++i) {
  119. uchar* lptr = left.ptr<uchar>(i);
  120. uchar* rptr = right.ptr<uchar>(i);
  121. for ( int j = -margin; j <= margin; ++j) {
  122. sum += abs(lptr[x1 + j] - rptr[x2 + j]); // cost function
  123. }
  124. }
  125. return sum / (blocksize*blocksize*255.0);
  126. }
  127. };
  128. class GradientCost : public CostFunction {
  129. public:
  130. cv::Mat l_grad; // 3 channel float
  131. cv::Mat r_grad; // 3 channel float
  132. GradientCost(const cv::Mat left, const cv::Mat right, float lambda) : CostFunction(left, right, lambda) {
  133. l_grad = getRGBGradientAngle(left);
  134. r_grad = getRGBGradientAngle(right);
  135. //displayGradientPic(l_grad);
  136. //displayGradientPic(r_grad);
  137. }
  138. bool imageType(cv::Mat left, cv::Mat right) {
  139. assert(left.type() == right.type() && "imgL imgR types not equal");
  140. assert(left.type() == CV_8UC3 && "img type not supported");
  141. return true;
  142. }
  143. // aggregate over a ROI of input images
  144. float aggregate(int x1, int x2, int y) {
  145. float sum = 0;
  146. for (int i = y - margin; i <= y + margin; ++i) {
  147. cv::Vec3f* lptr = l_grad.ptr<cv::Vec3f>(i);
  148. cv::Vec3f* rptr = r_grad.ptr<cv::Vec3f>(i);
  149. for ( int j = -margin; j <= margin; ++j) {
  150. sum += eukl(lptr[x1 + j], rptr[x2 + j]); // cost function
  151. }
  152. }
  153. return sum / sqrt(255*255 + 255*255 + 255*255); // normalize to winSize * 1.0
  154. }
  155. float eukl(cv::Vec3f l, cv::Vec3f r) {
  156. float a = l[0] - r[0];
  157. float b = l[1] - r[1];
  158. float c = l[2] - r[2];
  159. return std::sqrt(a*a + b*b + c*c);
  160. }
  161. ~GradientCost() {
  162. l_grad.release();
  163. r_grad.release();
  164. }
  165. };
  166. class CensusCost : public CostFunction {
  167. public:
  168. int censusWindow;
  169. int censusMargin;
  170. CensusCost(cv::Mat left, cv::Mat right, int censusWindow, float lambda) : CostFunction(left, right, lambda) {
  171. // census.... nimmt einen Block
  172. this->censusWindow = censusWindow;
  173. this->censusMargin = censusWindow / 2;
  174. this->normWin = censusWindow * censusWindow;
  175. // nimmt einen Block
  176. }
  177. bool imageType(cv::Mat left, cv::Mat right) {
  178. assert(left.type() == right.type() && "imgL imgR types not equal");
  179. assert(left.type() == CV_8UC1 && "img type not supported");
  180. return true;
  181. }
  182. unsigned int census(int x1, int x2, int y, uchar c1, uchar c2) {
  183. unsigned int diff = 0;
  184. for(int i = y - censusMargin; i <= y + censusMargin; ++i) {
  185. uchar* lptr = left.ptr<uchar>(i);
  186. uchar* rptr = right.ptr<uchar>(i);
  187. for(int j = -censusMargin; j <= censusMargin; ++j) {
  188. bool t1 = (c1 < lptr[x1 + j]);
  189. bool t2 = (c2 < rptr[x2 + j]);
  190. if(t1 != t2) diff++;
  191. }
  192. }
  193. return diff; /// (censusWindow*censusWindow);
  194. }
  195. float aggregate(int x1, int x2, int y) {
  196. float sum = 0;
  197. /*for(int i = y - margin; i <= y + margin; ++i) {
  198. uchar *lptr = left.ptr<uchar>(i);
  199. uchar *rptr = right.ptr<uchar>(i);
  200. for(int j = -margin; j <= margin; ++j)
  201. sum += census(x1 + j, x2 + j, i, lptr[x1 + j], rptr[x2 + j]);
  202. }*/
  203. uchar *lptr = left.ptr<uchar>(y);
  204. uchar *rptr = right.ptr<uchar>(y);
  205. sum = census(x1, x2, y, lptr[x1], rptr[x2]);
  206. return sum / normWin;
  207. }
  208. };
  209. class CensusFloatCost : public CostFunction {
  210. public:
  211. int censusWindow;
  212. int censusMargin;
  213. CensusFloatCost(cv::Mat left, cv::Mat right, int censusWindow, float lambda) : CostFunction(left, right, lambda) {
  214. // census.... nimmt einen Block
  215. this->censusWindow = censusWindow;
  216. this->censusMargin = censusWindow / 2;
  217. }
  218. bool imageType(cv::Mat left, cv::Mat right) {
  219. assert(left.type() == right.type() && "imgL imgR types not equal");
  220. assert(left.type() == CV_32F && "img type not supported");
  221. return true;
  222. }
  223. unsigned int census(int x1, int x2, int y, float c1, float c2) {
  224. unsigned int diff = 0;
  225. for(int i = y - censusMargin; i <= y + censusMargin; ++i) {
  226. float* lptr = left.ptr<float>(i);
  227. float* rptr = right.ptr<float>(i);
  228. for(int j = -censusMargin; j <= censusMargin; ++j) {
  229. bool t1 = (c1 < lptr[x1 + j]);
  230. bool t2 = (c2 < rptr[x2 + j]);
  231. if(t1 != t2) diff++;
  232. }
  233. }
  234. return diff;
  235. }
  236. float aggregate(int x1, int x2, int y) {
  237. float sum = 0;
  238. for(int i = y - margin; i <= y + margin; ++i) {
  239. float *lptr = left.ptr<float>(i);
  240. float *rptr = right.ptr<float>(i);
  241. for(int j = -margin; j <= margin; ++j)
  242. sum += census(x1 + j, x2 + j, i, lptr[x1 + j], rptr[x2 + j]);
  243. }
  244. float *lptr = left.ptr<float>(y);
  245. float *rptr = right.ptr<float>(y);
  246. //sum = census(x1, x2, y, lptr[x1], rptr[x2]);
  247. return sum / (censusWindow*censusWindow*lambda);
  248. }
  249. };
  250. class RGBCensusCost : public CostFunction {
  251. public:
  252. int censusWindow;
  253. int censusMargin;
  254. RGBCensusCost(cv::Mat left, cv::Mat right, int censusWindow, float lambda) : CostFunction(left, right, lambda) {
  255. // census.... nimmt einen Block
  256. this->censusWindow = censusWindow;
  257. this->censusMargin = censusWindow / 2;
  258. normCost = censusWindow*censusWindow*3;
  259. // nimmt einen Block
  260. }
  261. bool imageType(cv::Mat left, cv::Mat right) {
  262. assert(left.type() == right.type() && "imgL imgR types not equal");
  263. assert(left.type() == CV_8UC3 && "img type not supported");
  264. return true;
  265. }
  266. unsigned int census(int x1, int x2, int y, cv::Vec3b c1, cv::Vec3b c2) {
  267. unsigned int diff = 0;
  268. for(int i = y - censusMargin; i <= y + censusMargin; ++i) {
  269. cv::Vec3b* lptr = left.ptr<cv::Vec3b>(i);
  270. cv::Vec3b* rptr = right.ptr<cv::Vec3b>(i);
  271. for(int j = -censusMargin; j <= censusMargin; ++j) {
  272. cv::Vec3b cl = lptr[x1 + j];
  273. cv::Vec3b cr = rptr[x2 + j];
  274. for(int ch = 0; ch < 3; ++ch) {
  275. bool t1 = (c1[ch] < cl[ch]);
  276. bool t2 = (c2[ch] < cr[ch]);
  277. if(t1 != t2) diff++;
  278. }
  279. }
  280. }
  281. return diff;
  282. }
  283. float aggregate(int x1, int x2, int y) {
  284. float sum = 0;
  285. for(int i = y - margin; i <= y + margin; ++i) {
  286. cv::Vec3b *lptr = left.ptr<cv::Vec3b>(i);
  287. cv::Vec3b *rptr = right.ptr<cv::Vec3b>(i);
  288. for(int j = -margin; j <= margin; ++j)
  289. sum += census(x1 + j, x2 + j, i, lptr[x1 + j], rptr[x2 + j]);
  290. }
  291. //cv::Vec3b *lptr = left.ptr<cv::Vec3b>(y);
  292. //cv::Vec3b *rptr = right.ptr<cv::Vec3b>(y);
  293. return sum / normCost;
  294. }
  295. };
  296. class RGBGradCensusCost : public CostFunction {
  297. public:
  298. int censusWindow;
  299. int censusMargin;
  300. float normCost;
  301. float normWin;
  302. cv::Mat l_grad;
  303. cv::Mat r_grad;
  304. RGBGradCensusCost(cv::Mat left, cv::Mat right, int censusWindow, float lambda) : CostFunction(left, right, lambda) {
  305. // census.... nimmt einen Block
  306. this->censusWindow = censusWindow;
  307. this->censusMargin = censusWindow / 2;
  308. normWin = censusWindow*censusWindow*3;
  309. // nimmt einen Block
  310. l_grad = getRGBGradientAngle(left);
  311. r_grad = getRGBGradientAngle(right);
  312. }
  313. bool imageType(cv::Mat left, cv::Mat right) {
  314. assert(left.type() == right.type() && "imgL imgR types not equal");
  315. assert(left.type() == CV_8UC3 && "img type not supported");
  316. return true;
  317. }
  318. unsigned int census(int x1, int x2, int y, cv::Vec3f c1, cv::Vec3f c2) {
  319. unsigned int diff = 0;
  320. for(int i = y - censusMargin; i <= y + censusMargin; ++i) {
  321. cv::Vec3f* lptr = l_grad.ptr<cv::Vec3f>(i);
  322. cv::Vec3f* rptr = r_grad.ptr<cv::Vec3f>(i);
  323. for(int j = -censusMargin; j <= censusMargin; ++j) {
  324. cv::Vec3f cl = lptr[x1 + j];
  325. cv::Vec3f cr = rptr[x2 + j];
  326. for(int ch = 0; ch < 3; ++ch) {
  327. bool t1 = (c1[ch] < cl[ch]);
  328. bool t2 = (c2[ch] < cr[ch]);
  329. if(t1 != t2) diff++;
  330. }
  331. }
  332. }
  333. return diff;
  334. }
  335. float aggregate(int x1, int x2, int y) {
  336. float sum = 0;
  337. /*for(int i = y - margin; i <= y + margin; ++i) {
  338. cv::Vec3f *lptr = l_grad.ptr<cv::Vec3f>(i);
  339. cv::Vec3f *rptr = r_grad.ptr<cv::Vec3f>(i);
  340. for(int j = -margin; j <= margin; ++j)
  341. sum += census(x1 + j, x2 + j, i, lptr[x1 + j], rptr[x2 + j]);
  342. }*/
  343. cv::Vec3f *lptr = l_grad.ptr<cv::Vec3f>(y);
  344. cv::Vec3f *rptr = r_grad.ptr<cv::Vec3f>(y);
  345. sum = census(x1, x2, y, lptr[x1], rptr[x2]);
  346. return sum / normWin;
  347. }
  348. };

step3.视差空间的构建

DSI(Disparity Space Image)视差空间图像为一个三维矩阵,主要由横轴x,纵轴y,视差搜索范围d构成,传统的DP方法一般就是为了在某固定的Y(也就是某极线上)寻找一条从最左段到最右段的最小代价路径,每条路径的代价为

  • 视差空间的构建

输入参数:

  • imageSize:图像的大小
  • blocksize:块的大小
  • y:某条极线

输出参数:

  • map:某极线上左右图像两两领域相互的代价值
  • 左范围:[margin,imageSize.width - margin]
  • 右范围:[margin,imageSize.width - margin]
  1. cv::Mat BlockMatching::disparitySpace(Size imageSize, int blocksize, int y)
  2. {
  3. int margin = blocksize / 2;
  4. int start = margin;
  5. int stopW = imageSize.width - margin;
  6. int workSpace = stopW - start;
  7. // leave out the borders
  8. //Mat map = Mat(workSpace, workSpace, CV_32F); // not preinitialized.. // numeric_limits<float>::max());
  9. Mat map = Mat(workSpace, workSpace, CV_32F, numeric_limits<float>::max());
  10. //int dmax = 101;
  11. for(int x1 = start; x1 < stopW; x1++) {
  12. float* ptr = map.ptr<float>(x1 - margin); // [x1 - margin, x2 - margin]
  13. //ptr[max(x1 - 1, start) - margin] = numeric_limits<float>::max(); // fast borders
  14. //ptr[min(x1 + dmax, stopW - 1) - margin] = numeric_limits<float>::max();
  15. //for(int x2 = x1; x2 < min(x1 + dmax, stopW); x2++) {
  16. for(int x2 = start; x2 < stopW; x2++) {
  17. // combine costs
  18. float cost = 0;
  19. for(size_t i = 0; i < functions.size(); ++i) {
  20. float val = functions[i]->aggregate(x1, x2, y);
  21. mins[i] = min(mins[i], val); // debug
  22. maxs[i] = max(maxs[i], val); // debug
  23. cost += val;
  24. }
  25. // x1, x2. Das heißt x1 sind die Zeilen. Wir gehen jedes Mal die Zeilen runter.
  26. // geht nur von 0 - workspace, deshalb margin abziehen
  27. //map.at<float>(x1 - margin, x2 - margin) = greySad(leftRoi, rightRoi);
  28. ptr[x2 - margin] = cost;
  29. }
  30. }
  31. return map;
  32. }

step4:动态规划

主要分为四步:

  1. 设置初始位置的值(已知的值,这里设置的最后一行,最后一列的点为初始值)
  2. 计算边界上的代价(最后一行、最后一列)
  3. 从三个方向(向上、向左、斜向上)计算代价
  4. 记录每一步的方向
  5. 第一行的最小值即为视差点

 这里不容易理解,其实它和Leetcode的最短路径的题是相似的

题目:给定一个矩阵,从左上角开始每次只能向右或者向下移动,最后到达右下角的位置,路径上的所有的数字累加起来作为这条路径的路劲和。要求返回所有路径和中的最小路径和

131
151
421

路径1,3,1,1,1,1是所有路径中路径和最小的,所以返回其和7。

  • 第一步:起始点1
  • 第二步:如果一直向下或者向右:
145
251
621
  • 第三步:计算第二行第二列的值,比较第一行第二列和第二行第一列的数谁小就选谁,依次类推。
145
27
6
145
276
68
145
276
687
  •   最小路径和的代码

  1. int minPathSum1(int matrix[][col], int dp[][col], int path[][col])
  2. {
  3. if(matrix == NULL)
  4. {
  5. return 0;
  6. }
  7. dp[0][0] = matrix[0][0];
  8. //计算第一列的值
  9. for(int i = 1; i < row; i ++)
  10. {
  11. dp[i][0] = dp[i - 1][0] + matrix[i][0];
  12. path[i][0] = 0;
  13. }
  14. //计算第一行的值
  15. for(int j = 1; j < col; j++)
  16. {
  17. dp[0][j] = dp[0][j- 1] + matrix[0][j];
  18. path[0][j] = 1;
  19. }
  20. //计算其它的值
  21. for(int i = 1; i < row; i++)
  22. {
  23. for(int j = 1; j < col; j++)
  24. {
  25. int direction = dp[i][j-1] < dp[i-1][j] ? 1 : 0;
  26. dp[i][j] = (direction ? dp[i][j-1] : dp[i-1][j]) + matrix[i][j];
  27. path[i][j] = direction;
  28. }
  29. }//for
  30. return dp[row - 1][col - 1];
  31. }

  •  dp视差空间代码
  1. // (1) set last entry sink in matrix (last value)
  2. // (2-3) Initializ Edges
  3. // (2) initialize travelpath for last col (only south direction)
  4. // (3) initialize travelpath for last row (only east direction)
  5. // (4) calculate paths till last sink (last entry) till xLast - 1, yLast - 1
  6. // (-) save all (chosen) directions along the way
  7. void DPmat::preCalc(Mat &matrix, Mat &sum, Mat &dirs) {
  8. float occlusion_south = 1.0f;
  9. float occlusion_east = 1.0f;
  10. sum = Mat::zeros(matrix.rows, matrix.cols, matrix.type()); // not initialized with zero, should not be a problem,
  11. dirs = Mat::zeros(matrix.rows, matrix.cols, CV_16U); // because traversion is pre initialized with borders
  12. // dirs = (1, south), (2, south-east), (3, east)
  13. int rowLast = matrix.rows - 1; // last index inclusive
  14. int colLast = matrix.cols - 1; // last index inclusive
  15. // (1) initialize sink (last Entry/ terminal point/ matrix exit value)
  16. sum.at<float>(rowLast, colLast) = matrix.at<float>(rowLast, colLast);
  17. // (2-3) Initialize Edges
  18. // (2) calculate all last row entries down to exit value | only downward directions (so upward pre calculation)
  19. for(int y = rowLast - 1; y >= 0; --y) {
  20. // sum[y,x] = M[y,x] * occlusion_south + sum[y+1,x]
  21. sum.at<float>(y, colLast) = matrix.at<float>(y, colLast) * occlusion_south + sum.at<float>(y + 1, colLast); // add current value + successor min(value)
  22. dirs.at<ushort>(y, colLast) = 1; // south
  23. }
  24. // (3) initialize last
  25. for(int x = colLast - 1; x >= 0; --x) {
  26. // sum[y,x] = M[y,x] * occlusion_east + sum[y+1,x]
  27. sum.at<float>(rowLast, x) = matrix.at<float>(rowLast, x) * occlusion_east + sum.at<float>(rowLast, x + 1); // add current value + successor min(value)
  28. dirs.at<ushort>(rowLast, x) = 3; // east
  29. }
  30. // (4) Main calculation (3 way [south(s), east(e), south-east(se)])
  31. for(int y = rowLast - 1; y >= 0; --y) {
  32. float* sum_ptr = sum.ptr<float>(y);
  33. float* sum_south_ptr = sum.ptr<float>(y+1);
  34. float* mat_ptr = matrix.ptr<float>(y);
  35. ushort* dirs_ptr = dirs.ptr<ushort>(y);
  36. for(int x = colLast - 1; x >= 0; --x) {
  37. // dirs
  38. //float s = sum.at<float>(y + 1, x);
  39. //float se = sum.at<float>(y + 1, x + 1);
  40. //float e = sum.at<float>(y, x + 1);
  41. float s = sum_south_ptr[x] * occlusion_south; // (y+1,x) occlusion dir
  42. float se = sum_south_ptr[x + 1]; // (y+1,x+1)
  43. float e = sum_ptr[x + 1] * occlusion_east; // (y, x+1) occlusion dir
  44. // lowest cost till current point
  45. float p = min(s, min(se, e));
  46. //sum.at<float>(y, x) = p + matrix.at<float>(y, x); // sum till current (cost + lowest path)
  47. sum_ptr[x] = p + mat_ptr[x]; // sum[y,x] = p + mat[y, x]
  48. // selection for traversion direction
  49. //if(p == s) dirs.at<ushort>(y, x) = 1; // occlusion
  50. //if(p == se) dirs.at<ushort>(y, x) = 2; // math
  51. //if(p == e) dirs.at<ushort>(y, x) = 3; // occlusion
  52. if(p == s) dirs_ptr[x] = 1; // occlusion
  53. if(p == se) dirs_ptr[x] = 2; // math
  54. if(p == e) dirs_ptr[x] = 3; // occlusion
  55. }
  56. }
  57. }
  1. void DPmat::disparityFromDirs(Mat &sum, Mat &dirs, Mat &disp, int line, int offset) {
  2. assert(dirs.type() == CV_16U);
  3. // wir bekommen jetzt einen index x, y
  4. int rowLast = dirs.rows - 1;
  5. int colLast = dirs.cols - 1;
  6. int lastval = -1;
  7. int x1 = 0;
  8. int x2 = 0;
  9. float minVal = numeric_limits<float>::max();
  10. int minIndex = 0;
  11. // seek top entry
  12. for(x2 = 0; x2 < sum.cols; ++x2) {
  13. float val = sum.at<float>(x1, x2);
  14. if(val > minVal) {
  15. minIndex = x2;
  16. minVal = val;
  17. }
  18. }
  19. x2 = minIndex;
  20. // safe x1, x2 as disparity match
  21. ushort disparity = abs(x2 - x1);
  22. ushort* disp_ptr = disp.ptr<ushort>(line);
  23. disp_ptr[x1 + offset] = disparity;
  24. while(x1 < rowLast && x2 < colLast) {
  25. ushort d = dirs.at<ushort>(x1, x2);
  26. if(d == 1) { // 1 = down, skipping left index, left got occloded (occlusion from right)
  27. x1++;
  28. if(lastval >= 0) disp_ptr[x1 + offset] = lastval; // dips[line, x1 + offset] = lastval
  29. //disp_ptr[x1 + offset] = 0;
  30. }
  31. if(d == 2) { // match
  32. // next entry will be match
  33. x1++;
  34. x2++;
  35. disparity = abs(x2 - x1);
  36. disp_ptr[x1 + offset] = disparity;
  37. lastval = disparity;
  38. }
  39. if(d == 3) { // 2 = right, skipping right index, occlusion don't care..
  40. x2++;
  41. if(lastval >= 0) disp_ptr[x1 + offset] = lastval; // dips[line, x1 + offset] = lastval
  42. //disp_ptr[x1 + offset]= 0;
  43. }
  44. }
  45. }

原图像:

视差图像:


结论:

这种只考虑了图像左右相邻像素的视差约束,而忽略了上下领域像素之间的视差约束,这种方法得到的解因此也称为扫描线最优解,不能称为严格意义上的最优解,视差图像也出现了明显的横向条纹瑕疵。而且其计算时间也比较慢

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号