/ocr/ocrservice/jni/imageutils/blur.cpp

http://eyes-free.googlecode.com/ · C++ · 358 lines · 244 code · 44 blank · 70 comment · 29 complexity · 85a6964ce67d33d9dc44c089c741f9b9 MD5 · raw file

  1. /*
  2. * Copyright 2011, Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. // Author: Xiaotao Duan
  17. //
  18. // This library contains image processing method to detect
  19. // image blurriness.
  20. //
  21. // This library is *not* thread safe because static memory is
  22. // used for performance.
  23. //
  24. // A method to detect whether a given image is blurred or not.
  25. // The algorithm is based on H. Tong, M. Li, H. Zhang, J. He,
  26. // and C. Zhang. "Blur detection for digital images using wavelet
  27. // transform".
  28. //
  29. // To achieve better performance on client side, the method
  30. // is running on four 128x128 portions which compose the 256x256
  31. // central area of the given image. On Nexus One, average time
  32. // to process a single image is ~5 milliseconds.
  33. #include <math.h>
  34. #include "blur.h"
  35. #include "utils.h"
  36. static const int kDecomposition = 3;
  37. static const int kThreshold = 35;
  38. static const float kMinZero = 0.05;
  39. static const int kMaximumWidth = 256;
  40. static const int kMaximumHeight = 256;
  41. static int32 _smatrix[kMaximumWidth * kMaximumHeight];
  42. static int32 _arow[kMaximumWidth > kMaximumHeight ?
  43. kMaximumWidth : kMaximumHeight];
  44. // Does Haar Wavelet Transformation in place on a given row of a matrix.
  45. // The matrix is in size of matrix_height * matrix_width and represented
  46. // in a linear array. Parameter offset_row indicates transformation is
  47. // performed on which row. offset_column and num_columns indicate column
  48. // range of the given row.
  49. inline void Haar1DX(int* matrix, int matrix_height, int matrix_width,
  50. int offset_row, int offset_column, int num_columns) {
  51. int32* ptr_a = _arow;
  52. int32* ptr_matrix = matrix + offset_row * matrix_width + offset_column;
  53. int half_num_columns = num_columns / 2;
  54. int32* a_tmp = ptr_a;
  55. int32* matrix_tmp = ptr_matrix;
  56. for (int j = 0; j < half_num_columns; ++j) {
  57. *a_tmp++ = (matrix_tmp[0] + matrix_tmp[1]) / 2;
  58. matrix_tmp += 2;
  59. }
  60. int32* average = ptr_a;
  61. a_tmp = ptr_a + half_num_columns;
  62. matrix_tmp = ptr_matrix;
  63. for (int j = 0; j < half_num_columns; ++j) {
  64. *a_tmp++ = *matrix_tmp - *average++;
  65. matrix_tmp += 2;
  66. }
  67. memcpy(ptr_matrix, ptr_a, sizeof(int32) * num_columns);
  68. }
  69. // Does Haar Wavelet Transformation in place on a given column of a matrix.
  70. inline void Haar1DY(int* matrix, int matrix_height, int matrix_width,
  71. int offset_column, int offset_row, int num_rows) {
  72. int32* ptr_a = _arow;
  73. int32* ptr_matrix = matrix + offset_row * matrix_width + offset_column;
  74. int half_num_rows = num_rows / 2;
  75. int two_line_width = matrix_width * 2;
  76. int32* a_tmp = ptr_a;
  77. int32* matrix_tmp = ptr_matrix;
  78. for (int j = 0; j < half_num_rows; ++j) {
  79. *a_tmp++ = (matrix_tmp[matrix_width] + matrix_tmp[0]) / 2;
  80. matrix_tmp += two_line_width;
  81. }
  82. int32* average = ptr_a;
  83. a_tmp = ptr_a + half_num_rows;
  84. matrix_tmp = ptr_matrix;
  85. for (int j = 0; j < num_rows; j += 2) {
  86. *a_tmp++ = *matrix_tmp - *average++;
  87. matrix_tmp += two_line_width;
  88. }
  89. for (int j = 0; j < num_rows; ++j) {
  90. *ptr_matrix = *ptr_a++;
  91. ptr_matrix += matrix_width;
  92. }
  93. }
  94. // Does Haar Wavelet Transformation in place for a specified area of
  95. // a matrix. The matrix size is specified by matrix_width and matrix_height.
  96. // The area on which the transformation is performed is specified by
  97. // offset_column, num_columns, offset_row and num_rows.
  98. void Haar2D(int* matrix, int matrix_height, int matrix_width,
  99. int offset_column, int num_columns, int offset_row, int num_rows) {
  100. for (int i = offset_row; i < offset_row + num_rows; ++i) {
  101. Haar1DX(matrix, matrix_height, matrix_width, i, offset_column, num_columns);
  102. }
  103. for (int i = offset_column; i < offset_column + num_columns; ++i){
  104. Haar1DY(matrix, matrix_height, matrix_width, i, offset_row, num_rows);
  105. }
  106. }
  107. // Reads in a given matrix, does first round HWT and outputs result
  108. // matrix into target array. This function is used for optimization by
  109. // avoiding a memory copy. The input matrix has height rows and width
  110. // columns. The transformation is performed on the given area specified
  111. // by offset_column, num_columns, offset_row, num_rows. After
  112. // transformation, the output matrix has num_columns columns and
  113. // num_rows rows.
  114. void HwtFirstRound(const uint8* const data, int height, int width,
  115. int offset_column, int num_columns,
  116. int offset_row, int num_rows, int32* matrix) {
  117. int32* ptr_a = _arow;
  118. const uint8* ptr_data = data + offset_row * width + offset_column;
  119. int half_num_columns = num_columns / 2;
  120. for (int i = 0; i < num_rows; ++i) {
  121. int32* a_tmp = ptr_a;
  122. const uint8* data_tmp = ptr_data;
  123. for (int j = 0; j < half_num_columns; ++j) {
  124. *a_tmp++ = (int32) ((data_tmp[0] + data_tmp[1]) / 2);
  125. data_tmp += 2;
  126. }
  127. int32* average = ptr_a;
  128. a_tmp = ptr_a + half_num_columns;
  129. data_tmp = ptr_data;
  130. for (int j = 0; j < half_num_columns; ++j) {
  131. *a_tmp++ = *data_tmp - *average++;
  132. data_tmp += 2;
  133. }
  134. int32* ptr_matrix = matrix + i * num_columns;
  135. a_tmp = ptr_a;
  136. for (int j = 0; j < num_columns; ++j) {
  137. *ptr_matrix++ = *a_tmp++;
  138. }
  139. ptr_data += width;
  140. }
  141. // Column transformation does not involve input data.
  142. for (int i = 0; i < num_columns; ++i) {
  143. Haar1DY(matrix, num_rows, num_columns, i, 0, num_rows);
  144. }
  145. }
  146. // Returns the weight of a given point in a certain scale of a matrix
  147. // after wavelet transformation.
  148. // The point is specified by k and l which are y and x coordinate
  149. // respectively. Parameter scale tells in which scale the weight is
  150. // computed, must be 1, 2 or 3 which stands respectively for 1/2, 1/4
  151. // and 1/8 of original size.
  152. int ComputeEdgePointWeight(int* matrix, int width, int height,
  153. int k, int l, int scale) {
  154. int r = k >> scale;
  155. int c = l >> scale;
  156. int window_row = height >> scale;
  157. int window_column = width >> scale;
  158. int v_top_right = square(matrix[r * width + c + window_column]);
  159. int v_bot_left = square(matrix[(r + window_row) * width + c]);
  160. int v_bot_right =
  161. square(matrix[(r + window_row) * width + c + window_column]);
  162. int v = sqrt(v_top_right + v_bot_left + v_bot_right);
  163. return v;
  164. }
  165. // Computes point with maximum weight for a given local window for a
  166. // given scale.
  167. // Parameter scaled_width and scaled_height define scaled image size
  168. // of a certain decomposition level. The window size is defined by
  169. // window_size. Output value k and l store row (y coordinate) and
  170. // column (x coordinate) respectively of the point with maximum weight.
  171. // The maximum weight is returned.
  172. int ComputeLocalMaximum(int* matrix, int width, int height,
  173. int scaled_width, int scaled_height,
  174. int top, int left, int window_size, int* k, int* l) {
  175. int max = -1;
  176. *k = top;
  177. *l = left;
  178. for (int i = 0; i < window_size; ++i) {
  179. for (int j = 0; j < window_size; ++j) {
  180. int r = top + i;
  181. int c = left + j;
  182. int v_top_right = abs(matrix[r * width + c + scaled_width]);
  183. int v_bot_left = abs(matrix[(r + scaled_height) * width + c]);
  184. int v_bot_right =
  185. abs(matrix[(r + scaled_height) * width + c + scaled_width]);
  186. int v = v_top_right + v_bot_left + v_bot_right;
  187. if (v > max) {
  188. max = v;
  189. *k = r;
  190. *l = c;
  191. }
  192. }
  193. }
  194. int r = *k;
  195. int c = *l;
  196. int v_top_right = square(matrix[r * width + c + scaled_width]);
  197. int v_bot_left = square(matrix[(r + scaled_height) * width + c]);
  198. int v_bot_right =
  199. square(matrix[(r + scaled_height) * width + c + scaled_width]);
  200. int v = sqrt(v_top_right + v_bot_left + v_bot_right);
  201. return v;
  202. }
  203. // Detects blurriness of a transformed matrix.
  204. // Blur confidence and extent will be returned through blur_conf
  205. // and blur_extent. 1 is returned while input matrix is blurred.
  206. int DetectBlur(int* matrix, int width, int height,
  207. float* blur_conf, float* blur_extent) {
  208. int nedge = 0;
  209. int nda = 0;
  210. int nrg = 0;
  211. int nbrg = 0;
  212. // For each scale
  213. for (int current_scale = kDecomposition; current_scale > 0; --current_scale) {
  214. int scaled_width = width >> current_scale;
  215. int scaled_height = height >> current_scale;
  216. int window_size = 16 >> current_scale; // 2, 4, 8
  217. // For each window
  218. for (int r = 0; r + window_size < scaled_height; r += window_size) {
  219. for (int c = 0; c + window_size < scaled_width; c += window_size) {
  220. int k, l;
  221. int emax = ComputeLocalMaximum(matrix, width, height,
  222. scaled_width, scaled_height, r, c, window_size, &k, &l);
  223. if (emax > kThreshold) {
  224. int emax1, emax2, emax3;
  225. switch (current_scale) {
  226. case 1:
  227. emax1 = emax;
  228. emax2 = ComputeEdgePointWeight(matrix, width, height,
  229. k << current_scale, l << current_scale, 2);
  230. emax3 = ComputeEdgePointWeight(matrix, width, height,
  231. k << current_scale, l << current_scale, 3);
  232. break;
  233. case 2:
  234. emax1 = ComputeEdgePointWeight(matrix, width, height,
  235. k << current_scale, l << current_scale, 1);
  236. emax2 = emax;
  237. emax3 = ComputeEdgePointWeight(matrix, width, height,
  238. k << current_scale, l << current_scale, 3);
  239. break;
  240. case 3:
  241. emax1 = ComputeEdgePointWeight(matrix, width, height,
  242. k << current_scale, l << current_scale, 1);
  243. emax2 = ComputeEdgePointWeight(matrix, width, height,
  244. k << current_scale, l << current_scale, 2);
  245. emax3 = emax;
  246. break;
  247. }
  248. nedge++;
  249. if (emax1 > emax2 && emax2 > emax3) {
  250. nda++;
  251. }
  252. if (emax1 < emax2 && emax2 < emax3) {
  253. nrg++;
  254. if (emax1 < kThreshold) {
  255. nbrg++;
  256. }
  257. }
  258. if (emax2 > emax1 && emax2 > emax3) {
  259. nrg++;
  260. if (emax1 < kThreshold) {
  261. nbrg++;
  262. }
  263. }
  264. }
  265. }
  266. }
  267. }
  268. // TODO(xiaotao): No edge point at all, blurred or not?
  269. float per = nedge == 0 ? 0 : (float)nda / nedge;
  270. *blur_conf = per;
  271. *blur_extent = (float)nbrg / nrg;
  272. return per < kMinZero;
  273. }
  274. // Detects blurriness of a given portion of a luminance matrix.
  275. int IsBlurredInner(const uint8* const luminance,
  276. const int width, const int height,
  277. const int left, const int top,
  278. const int width_wanted, const int height_wanted,
  279. float* const blur, float* const extent) {
  280. int32* matrix = _smatrix;
  281. HwtFirstRound(luminance, height, width,
  282. left, width_wanted, top, height_wanted, matrix);
  283. Haar2D(matrix, height_wanted, width_wanted,
  284. 0, width_wanted >> 1, 0, height_wanted >> 1);
  285. Haar2D(matrix, height_wanted, width_wanted,
  286. 0, width_wanted >> 2, 0, height_wanted >> 2);
  287. int blurred = DetectBlur(matrix, width_wanted, height_wanted, blur, extent);
  288. return blurred;
  289. }
  290. int IsBlurred(const uint8* const luminance,
  291. const int width, const int height, float* const blur, float* const extent) {
  292. int desired_width = min(kMaximumWidth, width);
  293. int desired_height = min(kMaximumHeight, height);
  294. int left = (width - desired_width) >> 1;
  295. int top = (height - desired_height) >> 1;
  296. float conf1, extent1;
  297. int blur1 = IsBlurredInner(luminance, width, height,
  298. left, top, desired_width >> 1, desired_height >> 1, &conf1, &extent1);
  299. float conf2, extent2;
  300. int blur2 = IsBlurredInner(luminance, width, height,
  301. left + (desired_width >> 1), top, desired_width >> 1, desired_height >> 1,
  302. &conf2, &extent2);
  303. float conf3, extent3;
  304. int blur3 = IsBlurredInner(luminance, width, height,
  305. left, top + (desired_height >> 1), desired_width >> 1,
  306. desired_height >> 1, &conf3, &extent3);
  307. float conf4, extent4;
  308. int blur4 = IsBlurredInner(luminance, width, height,
  309. left + (desired_width >> 1), top + (desired_height >> 1),
  310. desired_width >> 1, desired_height >> 1, &conf4, &extent4);
  311. *blur = (conf1 + conf2 + conf3 + conf4) / 4;
  312. *extent = (extent1 + extent2 + extent3 + extent4) / 4;
  313. return *blur < kMinZero;
  314. }