ImageColorBalance.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. #include "ImageColorBalance.h"
  2. ImageColorBalance::ImageColorBalance()
  3. {
  4. //set the refresh frequency
  5. m_nCurrentRefreshFrequency = 0;
  6. }
  7. void ImageColorBalance::Init(unsigned char* pImage, int nPanoWidth, int nPanoHeight, int nPanoPitch, int nCameraWidth, int nCameraHeight, int nCameraPitch,int nRefreshFrequency)
  8. {
  9. m_pPanoImageBuffer = pImage;
  10. m_nPanoWidth = nPanoWidth;
  11. m_nPanoHeight = nPanoHeight;
  12. m_nPanoPitch = nPanoPitch;
  13. m_nCameraWidth = nCameraWidth;
  14. m_nCameraHeight = nCameraHeight;
  15. m_nCameraPitch = nCameraPitch;
  16. m_nRefreshFrequency = nRefreshFrequency;
  17. }
  18. void ImageColorBalance::FusionImageByBorderColor(unsigned char* pPano, cv::Rect InferRc, unsigned char* pCvTarget, cv::Rect TargetOverlapRc)
  19. {
  20. if (TargetOverlapRc.width < 2)
  21. return;
  22. std::vector<bool> bAddOrSub;
  23. //according to pano image pointer to build a cv mat to store the pano image
  24. cv::Mat PanoImage = cv::Mat(this->m_nPanoHeight, this->m_nPanoWidth, CV_8UC3, pPano);
  25. //get the fusion part in pano image
  26. cv::Mat CvInferMat = PanoImage(InferRc);
  27. if(TargetOverlapRc.width==0 || TargetOverlapRc.height==0)
  28. return;
  29. //get the target image to cv mat
  30. cv::Mat CvTargetMat = cv::Mat(this->m_nCameraHeight, this->m_nCameraWidth, CV_8UC3, pCvTarget)(TargetOverlapRc);
  31. std::vector<cv::Mat> Mask;
  32. //GetGradientMask(CvInferMat, CvTargetMat, Mask, bAddOrSub);
  33. if (m_nCurrentRefreshFrequency == 0)
  34. {
  35. m_nCurrentRefreshFrequency = m_nRefreshFrequency;
  36. }
  37. else
  38. {
  39. m_nCurrentRefreshFrequency--;
  40. }
  41. std::vector<cv::Mat> InferChannels;
  42. cv::split(CvInferMat, InferChannels);
  43. for (int i = 0; i < 3; i++)
  44. {
  45. if (bAddOrSub[i])
  46. InferChannels[i] = InferChannels[i] + Mask[i];
  47. else
  48. InferChannels[i] = InferChannels[i] - Mask[i];
  49. }
  50. cv::merge(InferChannels, CvInferMat);
  51. }
  52. void ImageColorBalance::GetGradientMask(cv::Rect Infer, cv::Rect Target, cv::Mat& MaskTarget, cv::Mat& MaskInfer, std::vector<bool>& bAddOrSub)
  53. {
  54. bAddOrSub.resize(3);
  55. //according to intersect rect rgb avg val to get the light base in this image
  56. cv::Mat WeigthMapTarget = cv::Mat(cv::Size(Infer.width, Infer.height), CV_8U, cv::Scalar(255));
  57. cv::Mat WeightMapInfer = cv::Mat(cv::Size(Infer.width, Infer.height), CV_8U, cv::Scalar(255));
  58. cv::Mat DistanceMaskTarget, DistanceMaskInfer;
  59. //set a column 0 in Mask
  60. WeigthMapTarget(cv::Rect(Infer.width - 1, 0, 1, Infer.height)).setTo(cv::Scalar(0));
  61. WeightMapInfer(cv::Rect(0, 0, 1, Infer.height)).setTo(cv::Scalar(0));
  62. DistanceMaskTarget.create(WeigthMapTarget.size(), WeigthMapTarget.type());
  63. DistanceMaskInfer.create(WeightMapInfer.size(), WeightMapInfer.type());
  64. //calculate a Weightmap in DistanceMask
  65. distanceATS_L1_8u(WeigthMapTarget.data, DistanceMaskTarget.cols, DistanceMaskTarget.rows, DistanceMaskTarget.step, DistanceMaskTarget.data);
  66. distanceATS_L1_8u(WeightMapInfer.data, DistanceMaskInfer.cols, DistanceMaskInfer.rows, DistanceMaskInfer.step, DistanceMaskInfer.data);
  67. std::shared_ptr<float> pfLightBaseDif(new float[3] {0});
  68. cv::Mat vTargetChannels, vInferChannels;
  69. DistanceMaskTarget.convertTo(DistanceMaskTarget, CV_32F);
  70. DistanceMaskInfer.convertTo(DistanceMaskInfer, CV_32F);
  71. //step is according to inferRc`s width
  72. float fStep = abs(1.f / Infer.width);
  73. vTargetChannels = DistanceMaskTarget * fStep;
  74. vInferChannels = DistanceMaskInfer * fStep;
  75. MaskTarget = (vTargetChannels);
  76. MaskInfer = (vInferChannels);
  77. }
  78. void ImageColorBalance::GetColorBalanceImage(unsigned char* pFusionImage, int& nWidth, int& nHeight, int& nPitch)
  79. {
  80. pFusionImage = this->m_pPanoImageBuffer;
  81. nWidth = this->m_nPanoWidth;
  82. nHeight = this->m_nPanoHeight;
  83. nPitch = this->m_nPanoPitch;
  84. }
  85. int& ImageColorBalance::GetRefreshFrequency()
  86. {
  87. return this->m_nCurrentRefreshFrequency;
  88. }
  89. const int ImageColorBalance::GetStdRefreshFrequency()
  90. {
  91. return this->m_nRefreshFrequency;
  92. }
  93. int ImageColorBalance::FusionImageByAutoLightBalance(unsigned char* pPano, cv::Rect InferRc, unsigned char* pCvTarget, cv::Rect TargetOverlapRc)
  94. {
  95. //将pPano全景数据转为mat
  96. cv::Mat PanoImage = cv::Mat(this->m_nPanoHeight, this->m_nPanoWidth, CV_8UC3, pPano);
  97. //从全景图像中获取需要色彩融合的部分
  98. cv::Mat ColorBalanceROI = PanoImage(InferRc);
  99. //if (m_InferWeightMask.empty())
  100. // GetGradientMask();
  101. return 0;
  102. }
  103. cv::Mat ImageColorBalance::stretchImage(cv::Mat src)
  104. {
  105. //stretch image to 0~1
  106. int row = src.rows;
  107. int col = src.cols;
  108. cv::Mat dst(row, col, CV_64FC1);
  109. double MaxValue = 0;
  110. double MinValue = 256.0;
  111. //find maxvalue and minvalue in image
  112. for (int i = 0; i < row; i++) {
  113. for (int j = 0; j < col; j++) {
  114. MaxValue = std::max(MaxValue, src.at<double>(i, j));
  115. MinValue = std::min(MinValue, src.at<double>(i, j));
  116. }
  117. }
  118. //stretch image
  119. for (int i = 0; i < row; i++) {
  120. for (int j = 0; j < col; j++) {
  121. dst.at<double>(i, j) = (1.0 * src.at<double>(i, j) - MinValue) / (MaxValue - MinValue);
  122. //protect
  123. if (dst.at<double>(i, j) > 1.0) {
  124. dst.at<double>(i, j) = 1.0;
  125. }
  126. else if (dst.at<double>(i, j) < 0) {
  127. dst.at<double>(i, j) = 0;
  128. }
  129. }
  130. }
  131. return dst;
  132. }
  133. cv::Mat ImageColorBalance::getPara(int radius)
  134. {
  135. int size = radius * 2 + 1;
  136. cv::Mat dst(size, size, CV_64FC1);
  137. for (int i = -radius; i <= radius; i++) {
  138. for (int j = -radius; j <= radius; j++) {
  139. //center point is 0
  140. if (i == 0 && j == 0) {
  141. dst.at<double>(i + radius, j + radius) = 0;
  142. }
  143. else {
  144. //distance to center point
  145. dst.at<double>(i + radius, j + radius) = 1.0 / sqrt(i * i + j * j);
  146. }
  147. }
  148. }
  149. //get the sum of all value
  150. double sum = 0;
  151. for (int i = 0; i < size; i++) {
  152. for (int j = 0; j < size; j++) {
  153. sum += dst.at<double>(i, j);
  154. }
  155. }
  156. //normalize
  157. for (int i = 0; i < size; i++) {
  158. for (int j = 0; j < size; j++) {
  159. dst.at<double>(i, j) = dst.at<double>(i, j) / sum;
  160. }
  161. }
  162. return dst;
  163. }
  164. cv::Mat ImageColorBalance::NormalACE(cv::Mat src, int ratio, int radius)
  165. {
  166. cv::Mat para = getPara(radius);
  167. int row = src.rows;
  168. int col = src.cols;
  169. int size = 2 * radius + 1;
  170. cv::Mat Z(row + 2 * radius, col + 2 * radius, CV_64FC1);
  171. //padding
  172. for (int i = 0; i < Z.rows; i++) {
  173. for (int j = 0; j < Z.cols; j++) {
  174. if ((i - radius >= 0) && (i - radius < row) && (j - radius >= 0) && (j - radius < col)) {
  175. //in the range of src,copy the src in z
  176. Z.at<double>(i, j) = src.at<double>(i - radius, j - radius);
  177. }
  178. else {
  179. Z.at<double>(i, j) = 0;
  180. }
  181. }
  182. }
  183. //init the dst
  184. cv::Mat dst(row, col, CV_64FC1);
  185. for (int i = 0; i < row; i++) {
  186. for (int j = 0; j < col; j++) {
  187. dst.at<double>(i, j) = 0.f;
  188. }
  189. }
  190. //convolution
  191. for (int i = 0; i < size; i++) {
  192. for (int j = 0; j < size; j++) {
  193. if (para.at<double>(i, j) == 0) continue;
  194. for (int x = 0; x < row; x++) {
  195. for (int y = 0; y < col; y++) {
  196. double sub = src.at<double>(x, y) - Z.at<double>(x + i, y + j);
  197. double tmp = sub * ratio;
  198. if (tmp > 1.0) tmp = 1.0;
  199. if (tmp < -1.0) tmp = -1.0;
  200. dst.at<double>(x, y) += tmp * para.at<double>(i, j);
  201. }
  202. }
  203. }
  204. }
  205. return dst;
  206. }
  207. cv::Mat ImageColorBalance::FastACE(cv::Mat src, int ratio, int radius)
  208. {
  209. int row = src.rows;
  210. int col = src.cols;
  211. //if the image is too small,just return 0.5
  212. if (std::min(row, col) <= 2) {
  213. cv::Mat dst(row, col, CV_64FC1);
  214. for (int i = 0; i < row; i++) {
  215. for (int j = 0; j < col; j++) {
  216. dst.at<double>(i, j) = 0.5;
  217. }
  218. }
  219. return dst;
  220. }
  221. //resize the image to half
  222. cv::Mat Rs((row + 1) / 2, (col + 1) / 2, CV_64FC1);
  223. cv::resize(src, Rs, cv::Size((col + 1) / 2, (row + 1) / 2));
  224. //recursive
  225. //convolution and resize
  226. cv::Mat Rf = FastACE(Rs, ratio, radius);
  227. cv::resize(Rf, Rf, cv::Size(col, row));
  228. cv::resize(Rs, Rs, cv::Size(col, row));
  229. cv::Mat dst(row, col, CV_64FC1);
  230. cv::Mat dst1 = NormalACE(src, ratio, radius);
  231. cv::Mat dst2 = NormalACE(Rs, ratio, radius);
  232. for (int i = 0; i < row; i++) {
  233. for (int j = 0; j < col; j++) {
  234. dst.at<double>(i, j) = Rf.at<double>(i, j) + dst1.at<double>(i, j) - dst2.at<double>(i, j);
  235. }
  236. }
  237. return dst;
  238. }
  239. cv::Mat ImageColorBalance::getACE(cv::Mat src, int ratio, int radius)
  240. {
  241. int row = src.rows;
  242. int col = src.cols;
  243. std::vector <cv::Mat> v;
  244. split(src, v);
  245. v[0].convertTo(v[0], CV_64FC1);
  246. v[1].convertTo(v[1], CV_64FC1);
  247. v[2].convertTo(v[2], CV_64FC1);
  248. cv::Mat src1(row, col, CV_64FC1);
  249. cv::Mat src2(row, col, CV_64FC1);
  250. cv::Mat src3(row, col, CV_64FC1);
  251. for (int i = 0; i < row; i++) {
  252. for (int j = 0; j < col; j++) {
  253. src1.at<double>(i, j) = 1.0 * src.at<cv::Vec3b>(i, j)[0] / 255.0;
  254. src2.at<double>(i, j) = 1.0 * src.at<cv::Vec3b>(i, j)[1] / 255.0;
  255. src3.at<double>(i, j) = 1.0 * src.at<cv::Vec3b>(i, j)[2] / 255.0;
  256. }
  257. }
  258. src1 = stretchImage(FastACE(src1, ratio, radius));
  259. src2 = stretchImage(FastACE(src2, ratio, radius));
  260. src3 = stretchImage(FastACE(src3, ratio, radius));
  261. //
  262. cv::Mat dst1(row, col, CV_8UC1);
  263. cv::Mat dst2(row, col, CV_8UC1);
  264. cv::Mat dst3(row, col, CV_8UC1);
  265. for (int i = 0; i < row; i++) {
  266. for (int j = 0; j < col; j++) {
  267. dst1.at<uchar>(i, j) = (int)(src1.at<double>(i, j) * 255);
  268. if (dst1.at<uchar>(i, j) > 255) dst1.at<uchar>(i, j) = 255;
  269. else if (dst1.at<uchar>(i, j) < 0) dst1.at<uchar>(i, j) = 0;
  270. dst2.at<uchar>(i, j) = (int)(src2.at<double>(i, j) * 255);
  271. if (dst2.at<uchar>(i, j) > 255) dst2.at<uchar>(i, j) = 255;
  272. else if (dst2.at<uchar>(i, j) < 0) dst2.at<uchar>(i, j) = 0;
  273. dst3.at<uchar>(i, j) = (int)(src3.at<double>(i, j) * 255);
  274. if (dst3.at<uchar>(i, j) > 255) dst3.at<uchar>(i, j) = 255;
  275. else if (dst3.at<uchar>(i, j) < 0) dst3.at<uchar>(i, j) = 0;
  276. }
  277. }
  278. std::vector <cv::Mat> out;
  279. out.push_back(dst1);
  280. out.push_back(dst2);
  281. out.push_back(dst3);
  282. cv::Mat dst;
  283. merge(out, dst);
  284. return dst;
  285. }
  286. void ImageColorBalance::InterectRectDiff(cv::Mat& Infer, cv::Mat& Target, float& fInferToTarget_mul, float& fInferToTarget_sub)
  287. {
  288. cv::Scalar MeanInfer;
  289. cv::Scalar StdInfer;
  290. //获取infer图像的均值
  291. cv::meanStdDev(Infer, MeanInfer, StdInfer);
  292. cv::Scalar MeanTarget;
  293. cv::Scalar StdTarget;
  294. //获取target图像的均值
  295. cv::meanStdDev(Target, MeanTarget, StdTarget);
  296. float fMeanInfer = MeanInfer.val[0] + MeanInfer.val[1] + MeanInfer.val[2];
  297. fMeanInfer = fMeanInfer / 3.0f;
  298. float fMeanTarget = MeanTarget.val[0] + MeanTarget.val[1] + MeanTarget.val[2];
  299. fMeanTarget = fMeanTarget / 3.0f;
  300. fInferToTarget_sub = fMeanInfer;
  301. fInferToTarget_mul = fMeanTarget / fMeanInfer;
  302. }
  303. void ImageColorBalance::FlatParamInChain(std::vector<float>& vInParams, std::vector<float>& vOutParams)
  304. {
  305. //获取均值
  306. float Mean = 0.0f;
  307. for (int i = 0; i < int(vInParams.size()); i++)
  308. {
  309. Mean += vInParams[i];
  310. }
  311. Mean = Mean / int(vInParams.size());
  312. }
  313. void ImageColorBalance::IntersectRectChange(cv::Mat& InferImg, cv::Mat& TargetImg, cv::Rect InferRc, cv::Rect TargetRc, float fInferToTarget_mul)
  314. {
  315. InferImg = InferImg * fInferToTarget_mul;
  316. }