经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++基于灰度图上色GrayToColorFromOther的实现
来源:jb51  时间:2021/7/19 13:31:11  对本文有异议

场景需求

       之前有提到给灰度图上色的需求,在此基础上,还有一种需求,就是基于另一张参考灰度图的色板来给当前的灰度图上色,比如参考灰度图的数值区间为-10到10,颜色从蓝到绿再到红,而当前的灰度图的数据区间为-1到1,若基于参考灰度图的色板确定数据对应的颜色,则当前灰度图的颜色应该在绿色左右波动。

       下方为具体实现函数和测试代码。

功能函数代码

  1. /**
  2. * @brief GrayToColorFromOther 灰度图上色,基于参考灰度图的色板
  3. * @param phase1 输入的灰色图像,通道为1,提供色板
  4. * @param phase2 输入的灰色图像,通道为1,基于phase1的色板绘色
  5. * @return 上色后的图像
  6. */
  7. cv::Mat GrayToColorFromOther(cv::Mat &phase1, cv::Mat &phase2)
  8. {
  9. CV_Assert(phase1.channels() == 1);
  10. CV_Assert(phase2.channels() == 1);
  11. if (phase1.empty() || phase2.empty())
  12. {
  13. cv::Mat result = cv::Mat::zeros(100, 100, CV_8UC3);
  14. return result;
  15. }
  16. cv::Mat temp, result, mask;
  17. double max1, min1;
  18. int row = phase2.rows;
  19. int col = phase2.cols;
  20. // 确定参考灰度图的数据范围
  21. cv::minMaxIdx(phase1, &min1, &max1, nullptr, nullptr, phase1 == phase1);
  22. // 将当前灰度图以参考灰度图的数据范围作标准,进行数据变换
  23. temp = phase2.clone();
  24. for (int i = 0; i < row; ++i)
  25. {
  26. float *t2 = temp.ptr<float>(i);
  27. for (int j = 0; j < col; ++j)
  28. {
  29. t2[j] = 255.0f*(phase2.at<float>(i, j) - min1) / (max1 - min1);
  30. }
  31. }
  32. temp.convertTo(temp, CV_8UC1);
  33. // 创建掩膜,目的是为了隔离nan值的干扰
  34. mask = cv::Mat::zeros(phase2.size(), CV_8UC1);
  35. mask.setTo(255, phase2 == phase2);
  36. // 初始化三通道颜色图
  37. cv::Mat color1, color2, color3;
  38. color1 = cv::Mat::zeros(temp.size(), temp.type());
  39. color2 = cv::Mat::zeros(temp.size(), temp.type());
  40. color3 = cv::Mat::zeros(temp.size(), temp.type());
  41. // 基于灰度图的灰度层级,给其上色,最底的灰度值0为蓝色(255,0,0),最高的灰度值255为红色(0,0,255),中间的灰度值127为绿色(0,255,0)
  42. for (int i = 0; i < row; ++i)
  43. {
  44. uchar *c1 = color1.ptr<uchar>(i);
  45. uchar *c2 = color2.ptr<uchar>(i);
  46. uchar *c3 = color3.ptr<uchar>(i);
  47. uchar *r = temp.ptr<uchar>(i);
  48. uchar *m = mask.ptr<uchar>(i);
  49. for (int j = 0; j < col; ++j)
  50. {
  51. if (m[j] == 255)
  52. {
  53. if (r[j] > (3 * 255 / 4) && r[j] <= 255)
  54. {
  55. c1[j] = 255;
  56. c2[j] = 4 * (255 - r[j]);
  57. c3[j] = 0;
  58. }
  59. else if (r[j] <= (3 * 255 / 4) && r[j] > (255 / 2))
  60. {
  61. c1[j] = 255 - 4 * (3 * 255 / 4 - r[j]);
  62. c2[j] = 255;
  63. c3[j] = 0;
  64. }
  65. else if (r[j] <= (255 / 2) && r[j] > (255 / 4))
  66. {
  67. c1[j] = 0;
  68. c2[j] = 255;
  69. c3[j] = 4 * (255 / 2 - r[j]);
  70. }
  71. else if (r[j] <= (255 / 4) && r[j] >= 0)
  72. {
  73. c1[j] = 0;
  74. c2[j] = 255 - 4 * (255 / 4 - r[j]);
  75. c3[j] = 255;
  76. }
  77. else {
  78. c1[j] = 0;
  79. c2[j] = 0;
  80. c3[j] = 0;
  81. }
  82. }
  83. }
  84. }
  85. // 三通道合并,得到颜色图
  86. vector<cv::Mat> images;
  87. images.push_back(color3);
  88. images.push_back(color2);
  89. images.push_back(color1);
  90. cv::merge(images, result);
  91. return result;
  92. }

C++测试代码

  1. #include<iostream>
  2. #include<opencv2/opencv.hpp>
  3. #include<ctime>
  4. using namespace std;
  5. using namespace cv;
  6. void UnitPolar(int squaresize, cv::Mat& mag,cv::Mat& ang);
  7. void UnitCart(int squaresize, cv::Mat& x, cv::Mat& y);
  8. cv::Mat GrayToColor(cv::Mat &phase);
  9. cv::Mat GrayToColorFromOther(cv::Mat &phase1, cv::Mat &phase2);
  10. int main(void)
  11. {
  12. cv::Mat mag, ang,result,result2;
  13. UnitPolar(2001, mag, ang);
  14. mag.at<float>(10, 10) = nan("");
  15. cv::Mat mag2 = mag / 2;
  16. result = GrayToColor(mag);
  17. result2= GrayToColorFromOther(mag,mag2);
  18. system("pause");
  19. return 0;
  20. }
  21. void UnitPolar(int squaresize, cv::Mat& mag,cv::Mat& ang) {
  22. cv::Mat x;
  23. cv::Mat y;
  24. UnitCart(squaresize, x, y); //产生指定范围内的指定数量点数,相邻数据跨度相同
  25. // OpenCV自带的转换有精度限制,导致结果有一定差异性
  26. //cv::cartToPolar(x, y, mag, ang, false); //坐标转换
  27. mag = cv::Mat(x.size(), x.type());
  28. ang = cv::Mat(x.size(), x.type());
  29. int row = mag.rows;
  30. int col = mag.cols;
  31. float *m, *a, *xx, *yy;
  32. for (int i = 0; i < row; ++i)
  33. {
  34. m = mag.ptr<float>(i);
  35. a = ang.ptr<float>(i);
  36. xx = x.ptr<float>(i);
  37. yy = y.ptr<float>(i);
  38. for (int j = 0; j < col; ++j)
  39. {
  40. m[j] = sqrt(xx[j] * xx[j] + yy[j] * yy[j]);
  41. a[j] = atan2(yy[j], xx[j]);
  42. }
  43. }
  44. }
  45. void UnitCart(int squaresize, cv::Mat& x, cv::Mat& y) {
  46. CV_Assert(squaresize % 2 == 1);
  47. x.create(squaresize, squaresize, CV_32FC1);
  48. y.create(squaresize, squaresize, CV_32FC1);
  49. //设置边界
  50. x.col(0).setTo(-1.0);
  51. x.col(squaresize - 1).setTo(1.0f);
  52. y.row(0).setTo(1.0);
  53. y.row(squaresize - 1).setTo(-1.0f);
  54. float delta = 2.0f / (squaresize - 1.0f); //两个元素的间隔
  55. //计算其他位置的值
  56. for (int i = 1; i < squaresize - 1; ++i) {
  57. x.col(i) = -1.0f + i * delta;
  58. y.row(i) = 1.0f - i * delta;
  59. }
  60. }
  61. /**
  62. * @brief GrayToColor 灰度图上色
  63. * @param phase 输入的灰色图像,通道为1
  64. * @return 上色后的图像
  65. */
  66. cv::Mat GrayToColor(cv::Mat &phase)
  67. {
  68. CV_Assert(phase.channels() == 1);
  69. cv::Mat temp, result, mask;
  70. // 将灰度图重新归一化至0-255
  71. cv::normalize(phase, temp, 255, 0, cv::NORM_MINMAX);
  72. temp.convertTo(temp, CV_8UC1);
  73. // 创建掩膜,目的是为了隔离nan值的干扰
  74. mask = cv::Mat::zeros(phase.size(), CV_8UC1);
  75. mask.setTo(255, phase == phase);
  76. // 初始化三通道颜色图
  77. cv::Mat color1, color2, color3;
  78. color1 = cv::Mat::zeros(temp.size(), temp.type());
  79. color2 = cv::Mat::zeros(temp.size(), temp.type());
  80. color3 = cv::Mat::zeros(temp.size(), temp.type());
  81. int row = phase.rows;
  82. int col = phase.cols;
  83. // 基于灰度图的灰度层级,给其上色,最底的灰度值0为蓝色(255,0,0),最高的灰度值255为红色(0,0,255),中间的灰度值127为绿色(0,255,0)
  84. // 不要惊讶蓝色为什么是(255,0,0),因为OpenCV中是BGR而不是RGB
  85. for (int i = 0; i < row; ++i)
  86. {
  87. uchar *c1 = color1.ptr<uchar>(i);
  88. uchar *c2 = color2.ptr<uchar>(i);
  89. uchar *c3 = color3.ptr<uchar>(i);
  90. uchar *r = temp.ptr<uchar>(i);
  91. uchar *m = mask.ptr<uchar>(i);
  92. for (int j = 0; j < col; ++j)
  93. {
  94. if (m[j] == 255)
  95. {
  96. if (r[j] > (3 * 255 / 4) && r[j] <= 255)
  97. {
  98. c1[j] = 255;
  99. c2[j] = 4 * (255 - r[j]);
  100. c3[j] = 0;
  101. }
  102. else if (r[j] <= (3 * 255 / 4) && r[j] > (255 / 2))
  103. {
  104. c1[j] = 255 - 4 * (3 * 255 / 4 - r[j]);
  105. c2[j] = 255;
  106. c3[j] = 0;
  107. }
  108. else if (r[j] <= (255 / 2) && r[j] > (255 / 4))
  109. {
  110. c1[j] = 0;
  111. c2[j] = 255;
  112. c3[j] = 4 * (255 / 2 - r[j]);
  113. }
  114. else if (r[j] <= (255 / 4) && r[j] >= 0)
  115. {
  116. c1[j] = 0;
  117. c2[j] = 255 - 4 * (255 / 4 - r[j]);
  118. c3[j] = 255;
  119. }
  120. else {
  121. c1[j] = 0;
  122. c2[j] = 0;
  123. c3[j] = 0;
  124. }
  125. }
  126. }
  127. }
  128. // 三通道合并,得到颜色图
  129. vector<cv::Mat> images;
  130. images.push_back(color3);
  131. images.push_back(color2);
  132. images.push_back(color1);
  133. cv::merge(images, result);
  134. return result;
  135. }
  136. /**
  137. * @brief GrayToColorFromOther 灰度图上色,基于参考灰度图的色板
  138. * @param phase1 输入的灰色图像,通道为1,提供色板
  139. * @param phase2 输入的灰色图像,通道为1,基于phase1的色板绘色
  140. * @return 上色后的图像
  141. */
  142. cv::Mat GrayToColorFromOther(cv::Mat &phase1, cv::Mat &phase2)
  143. {
  144. CV_Assert(phase1.channels() == 1);
  145. CV_Assert(phase2.channels() == 1);
  146. if (phase1.empty() || phase2.empty())
  147. {
  148. cv::Mat result = cv::Mat::zeros(100, 100, CV_8UC3);
  149. return result;
  150. }
  151. cv::Mat temp, result, mask;
  152. double max1, min1;
  153. int row = phase2.rows;
  154. int col = phase2.cols;
  155. // 确定参考灰度图的数据范围
  156. cv::minMaxIdx(phase1, &min1, &max1, nullptr, nullptr, phase1 == phase1);
  157. // 将当前灰度图以参考灰度图的数据范围作标准,进行数据变换
  158. temp = phase2.clone();
  159. for (int i = 0; i < row; ++i)
  160. {
  161. float *t2 = temp.ptr<float>(i);
  162. for (int j = 0; j < col; ++j)
  163. {
  164. t2[j] = 255.0f*(phase2.at<float>(i, j) - min1) / (max1 - min1);
  165. }
  166. }
  167. temp.convertTo(temp, CV_8UC1);
  168. // 创建掩膜,目的是为了隔离nan值的干扰
  169. mask = cv::Mat::zeros(phase2.size(), CV_8UC1);
  170. mask.setTo(255, phase2 == phase2);
  171. // 初始化三通道颜色图
  172. cv::Mat color1, color2, color3;
  173. color1 = cv::Mat::zeros(temp.size(), temp.type());
  174. color2 = cv::Mat::zeros(temp.size(), temp.type());
  175. color3 = cv::Mat::zeros(temp.size(), temp.type());
  176. // 基于灰度图的灰度层级,给其上色,最底的灰度值0为蓝色(255,0,0),最高的灰度值255为红色(0,0,255),中间的灰度值127为绿色(0,255,0)
  177. for (int i = 0; i < row; ++i)
  178. {
  179. uchar *c1 = color1.ptr<uchar>(i);
  180. uchar *c2 = color2.ptr<uchar>(i);
  181. uchar *c3 = color3.ptr<uchar>(i);
  182. uchar *r = temp.ptr<uchar>(i);
  183. uchar *m = mask.ptr<uchar>(i);
  184. for (int j = 0; j < col; ++j)
  185. {
  186. if (m[j] == 255)
  187. {
  188. if (r[j] > (3 * 255 / 4) && r[j] <= 255)
  189. {
  190. c1[j] = 255;
  191. c2[j] = 4 * (255 - r[j]);
  192. c3[j] = 0;
  193. }
  194. else if (r[j] <= (3 * 255 / 4) && r[j] > (255 / 2))
  195. {
  196. c1[j] = 255 - 4 * (3 * 255 / 4 - r[j]);
  197. c2[j] = 255;
  198. c3[j] = 0;
  199. }
  200. else if (r[j] <= (255 / 2) && r[j] > (255 / 4))
  201. {
  202. c1[j] = 0;
  203. c2[j] = 255;
  204. c3[j] = 4 * (255 / 2 - r[j]);
  205. }
  206. else if (r[j] <= (255 / 4) && r[j] >= 0)
  207. {
  208. c1[j] = 0;
  209. c2[j] = 255 - 4 * (255 / 4 - r[j]);
  210. c3[j] = 255;
  211. }
  212. else {
  213. c1[j] = 0;
  214. c2[j] = 0;
  215. c3[j] = 0;
  216. }
  217. }
  218. }
  219. }
  220. // 三通道合并,得到颜色图
  221. vector<cv::Mat> images;
  222. images.push_back(color3);
  223. images.push_back(color2);
  224. images.push_back(color1);
  225. cv::merge(images, result);
  226. return result;
  227. }

测试效果

 

图1 参考灰度图上色效果

 

图2 基于参考灰度图色板的上色效果

       如上图所示,为了方便,我生成了一个2001*2001的图像矩阵,并设置了另一个对比图像,该图像为原图像的1/2,那么原图像就是参考灰度图,而对比图像就是需要基于参考灰度图色板上色的灰度图。图1为参考灰度图的上色效果,图2是基于参考灰度图色板给对比图像上色的效果图。原图像的数据从0-1.3左右,其颜色变化从蓝到绿再到红,而对比图像的数据从0-1.3/2左右,则颜色变化为蓝到绿,满足了前面提到的需求。

到此这篇关于C++基于灰度图上色GrayToColorFromOther的实现的文章就介绍到这了,更多相关C++ 灰度图上色GrayToColorFromOther内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号