• OpenCV自动色阶算法(可用于去雾)


    1. #include <iostream>
    2. #include<opencv2/opencv.hpp>
    3. #include<opencv2/highgui/highgui.hpp>
    4. #include<opencv2/imgproc/imgproc.hpp>
    5. #include<iostream>
    6. #include<vector>
    7. #include <algorithm>
    8. #include <sys/time.h>
    9. //
    10. #include <omp.h>
    11. using namespace cv;
    12. #define OMP_ON
    13. //自动色阶调整:用于图像去雾
    14. void AutoLevelsAdjust(cv::Mat& src, cv::Mat& dst)
    15. {
    16. timeval begin_time;
    17. timeval end_time;
    18. CV_Assert(!src.empty() && src.channels() == 3);
    19. //统计灰度直方图
    20. gettimeofday(&begin_time, NULL);
    21. int BHist[256] = { 0 }; //B分量
    22. int GHist[256] = { 0 }; //G分量
    23. int RHist[256] = { 0 }; //R分量
    24. //
    25. #ifdef OMP_ON
    26. int omp_thread_nums = omp_get_num_procs() * 2;
    27. omp_set_num_threads(omp_thread_nums);
    28. #pragma omp parallel for
    29. #endif
    30. for(unsigned char* pixel = src.data; pixel < src.dataend; pixel += 3)
    31. {
    32. BHist[*pixel]++;
    33. }
    34. #ifdef OMP_ON
    35. #pragma omp parallel for
    36. #endif
    37. for(unsigned char* pixel = src.data + 1; pixel < src.dataend; pixel += 3)
    38. {
    39. GHist[*pixel]++;
    40. }
    41. #ifdef OMP_ON
    42. #pragma omp parallel for
    43. #endif
    44. for(unsigned char* pixel = src.data + 2; pixel < src.dataend; pixel += 3)
    45. {
    46. RHist[*pixel]++;
    47. }
    48. gettimeofday(&end_time, NULL);
    49. printf("Hist Time: %f ms\n", (end_time.tv_sec*1000000 - begin_time.tv_sec*1000000 + end_time.tv_usec - begin_time.tv_usec) / 1000.0);
    50. gettimeofday(&begin_time, NULL);
    51. //设置LowCut和HighCut
    52. float LowCut = 0.5;
    53. float HighCut = 0.5;
    54. //根据LowCut和HighCut查找每个通道最大值最小值
    55. int BMax = 0, BMin = 0;
    56. int GMax = 0, GMin = 0;
    57. int RMax = 0, RMin = 0;
    58. int TotalPixels = src.cols * src.rows;
    59. float LowTh = LowCut * 0.01 * TotalPixels;
    60. float HighTh = HighCut * 0.01 * TotalPixels;
    61. //B通道查找最小最大值
    62. int sumTempB = 0;
    63. for (int i = 0; i < 256; i++)
    64. {
    65. sumTempB += BHist[i];
    66. if (sumTempB >= LowTh)
    67. {
    68. BMin = i;
    69. break;
    70. }
    71. }
    72. //
    73. sumTempB = 0;
    74. for (int i = 255; i >= 0; i--)
    75. {
    76. sumTempB += BHist[i];
    77. if (sumTempB >= HighTh)
    78. {
    79. BMax = i;
    80. break;
    81. }
    82. }
    83. //G通道查找最小最大值
    84. int sumTempG = 0;
    85. for (int i = 0; i < 256; i++)
    86. {
    87. sumTempG += GHist[i];
    88. if (sumTempG >= LowTh)
    89. {
    90. GMin = i;
    91. break;
    92. }
    93. }
    94. //
    95. sumTempG = 0;
    96. for (int i = 255; i >= 0; i--)
    97. {
    98. sumTempG += GHist[i];
    99. if (sumTempG >= HighTh)
    100. {
    101. GMax = i;
    102. break;
    103. }
    104. }
    105. //R通道查找最小最大值
    106. int sumTempR = 0;
    107. for (int i = 0; i < 256; i++)
    108. {
    109. sumTempR += RHist[i];
    110. if (sumTempR >= LowTh)
    111. {
    112. RMin = i;
    113. break;
    114. }
    115. }
    116. //
    117. sumTempR = 0;
    118. for (int i = 255; i >= 0; i--)
    119. {
    120. sumTempR += RHist[i];
    121. if (sumTempR >= HighTh)
    122. {
    123. RMax = i;
    124. break;
    125. }
    126. }
    127. gettimeofday(&end_time, NULL);
    128. printf("Get Max Min Time: %f ms\n", (end_time.tv_sec*1000000 - begin_time.tv_sec*1000000 + end_time.tv_usec - begin_time.tv_usec) / 1000.0);
    129. gettimeofday(&begin_time, NULL);
    130. //对每个通道建立分段线性查找表
    131. //B分量查找表
    132. int BTable[256] = { 0 };
    133. #ifdef OMP_ON
    134. omp_set_num_threads(omp_thread_nums);
    135. #pragma omp parallel for
    136. #endif
    137. for (int i = 0; i < 256; i++)
    138. {
    139. if (i <= BMin)
    140. BTable[i] = 0;
    141. else if (i > BMin && i < BMax)
    142. BTable[i] = cvRound((float)(i - BMin) / (BMax - BMin) * 255);
    143. else
    144. BTable[i] = 255;
    145. }
    146. //G分量查找表
    147. int GTable[256] = { 0 };
    148. #ifdef OMP_ON
    149. omp_set_num_threads(omp_thread_nums);
    150. #pragma omp parallel for
    151. #endif
    152. for (int i = 0; i < 256; i++)
    153. {
    154. if (i <= GMin)
    155. GTable[i] = 0;
    156. else if (i > GMin && i < GMax)
    157. GTable[i] = cvRound((float)(i - GMin) / (GMax - GMin) * 255);
    158. else
    159. GTable[i] = 255;
    160. }
    161. //R分量查找表
    162. int RTable[256] = { 0 };
    163. #ifdef OMP_ON
    164. omp_set_num_threads(omp_thread_nums);
    165. #pragma omp parallel for
    166. #endif
    167. for (int i = 0; i < 256; i++)
    168. {
    169. if (i <= RMin)
    170. RTable[i] = 0;
    171. else if (i > RMin && i < RMax)
    172. RTable[i] = cvRound((float)(i - RMin) / (RMax - RMin) * 255);
    173. else
    174. RTable[i] = 255;
    175. }
    176. gettimeofday(&end_time, NULL);
    177. printf("Create Color Table Time: %f ms\n", (end_time.tv_sec*1000000 - begin_time.tv_sec*1000000 + end_time.tv_usec - begin_time.tv_usec) / 1000.0);
    178. gettimeofday(&begin_time, NULL);
    179. //对每个通道用相应的查找表进行分段线性拉伸
    180. cv::Mat dst_ = src.clone();
    181. #ifdef OMP_ON
    182. omp_set_num_threads(omp_thread_nums);
    183. #pragma omp parallel for
    184. #endif
    185. for(unsigned char* pixel = dst_.data; pixel <= dst_.dataend; pixel += 3)
    186. {
    187. *pixel = BTable[*pixel];
    188. }
    189. #ifdef OMP_ON
    190. #pragma omp parallel for
    191. #endif
    192. for(unsigned char* pixel = dst_.data + 1; pixel <= dst_.dataend; pixel += 3)
    193. {
    194. *(pixel) = GTable[*pixel];
    195. }
    196. #ifdef OMP_ON
    197. #pragma omp parallel for
    198. #endif
    199. for(unsigned char* pixel = dst_.data + 2; pixel <= dst_.dataend; pixel += 3)
    200. {
    201. *(pixel) = RTable[*pixel];
    202. }
    203. gettimeofday(&end_time, NULL);
    204. printf("Mapping Time: %f ms\n", (end_time.tv_sec*1000000 - begin_time.tv_sec*1000000 + end_time.tv_usec - begin_time.tv_usec) / 1000.0);
    205. dst = dst_;
    206. }
    207. int main()
    208. {
    209. Mat image = imread("test.jpg");
    210. cv::resize(image, image, cv::Size(1920, 1080));
    211. Mat dst = Mat::zeros(image.rows, image.cols, CV_8UC1);
    212. timeval begin_time;
    213. timeval end_time;
    214. gettimeofday(&begin_time, NULL);
    215. AutoLevelsAdjust(image, dst);
    216. gettimeofday(&end_time, NULL);
    217. printf("Auto Level Adjust Time: %f ms\n", (end_time.tv_sec*1000000 - begin_time.tv_sec*1000000 + end_time.tv_usec - begin_time.tv_usec) / 1000.0);
    218. //
    219. imshow("src", image);
    220. imshow("dst", dst);
    221. while (char(waitKey(1)) != 'q') {}
    222. imwrite("dst.jpg", dst);
    223. }

    第一步,分别统计各通道(红/绿/蓝)的直方图

    第二步,分别计算各通道按照给定的参数所确定的上下限值。比如对于蓝色通道,我们从色阶0开始向上累加统计直方图,当累加值大于LowCut所有像素数时,以此时的色阶值计为BMin。然后从色阶255开始向下累计直方图,如果累加值大于HighCut所有像素时,以此时的色阶值计为BMax。

    第三步,按照计算出的MinBlue/MaxBlue构建一个映射表,映射表的规则是,对于小于MinBlue的值,则映射为0(实际上这句话也不对,映射为多少是和那个自动颜色校正选项对话框中的阴影所设定的颜色有关,默认情况下是黑色,对应的RGB分量都为0,所以我们这里就映射为0,有兴趣你们也可以指定为其他的参数),对于大于MaxBlue的值,则映射为255(同理,这个值和高光的颜色设置有关),对于介于MinBlue和MaxBlue之间的值,则进行线性映射,默认是映射为0到255之间(当然实际是和我们的暗调和高光的设置有关,并且这里其实也不是线性映射,是有一个Gamma校正,为了简便,用线性替代效果也没太大的问题)。

    最后一步,对各通道图像数据进行映射。

    引用自https://www.cnblogs.com/ybqjymy/p/13807586.html

    对代码进行运行效率优化。优化前,1920x1080分辨率处理时间150ms左右;优化后,1920x1080分辨率处理时间22ms左右。

  • 相关阅读:
    在uni-app中,input组件的auto-focus和focus属性用于控制输入框的自动聚焦行为,它们之间的区别
    MFC中LIST控件的问题
    机器人过程自动化(RPA)入门 9. 管理和维护代码
    搞定“项目八怪”,你就是管理高手!
    基于matab GUI的图形处理火焰检测系统
    [附源码]计算机毕业设计springboot-大学生健康档案管理
    164页5万字轨道交通BIM方案建议书
    C. Peaceful Rooks(并查集找环)
    万字长文浅析配置对MySQL服务器的影响
    草稿草稿草稿,python 和VBA的差别对比汇总 收集ing
  • 原文地址:https://blog.csdn.net/Zhangchen9091/article/details/136339173