vidstabalg.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*------------------------------------------------------------------------------
  2. -- --
  3. -- This software is confidential and proprietary and may be used --
  4. -- only as expressly authorized by a licensing agreement from --
  5. -- --
  6. -- Hantro Products Oy. --
  7. -- --
  8. -- (C) COPYRIGHT 2006 HANTRO PRODUCTS OY --
  9. -- ALL RIGHTS RESERVED --
  10. -- --
  11. -- The entire notice above must be reproduced --
  12. -- on all copies and should not be removed. --
  13. -- --
  14. --------------------------------------------------------------------------------
  15. -
  16. - Description : Video stabilization algorithms. Quarter pixel ME, Motion filter
  17. -
  18. ------------------------------------------------------------------------------*/
  19. #include "basetype.h"
  20. #include "vidstabcommon.h"
  21. #ifdef TEST_DATA
  22. #include <stdio.h>
  23. #endif
  24. #define ABS(x) ((x) < (0) ? -(x) : (x))
  25. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  26. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  27. static void QuarterPixelMotion(SwStbData * data, i32 minX, i32 minY);
  28. static void InterpolateMotion(i32(*data)[5], i32 * half_hor, i32 * half_ver);
  29. static void FilterMotion(SwStbData * data, i32 * minX, i32 * minY);
  30. #ifdef TEST_DATA
  31. /*------------------------------------------------------------------------------
  32. Function name : PrintTraceFile
  33. Description :
  34. Return type : void
  35. Argument : x
  36. Argument : y
  37. ------------------------------------------------------------------------------*/
  38. void PrintTraceFile(i32 x, i32 y)
  39. {
  40. static FILE *fTrc = NULL;
  41. if (fTrc == NULL)
  42. {
  43. fTrc = fopen("video_stab_result.trc", "w");
  44. if (fTrc)
  45. fprintf(fTrc, "offX, offY\n");
  46. }
  47. if (fTrc)
  48. fprintf(fTrc, "%4d, %4d\n", x, y);
  49. }
  50. #endif
  51. /*------------------------------------------------------------------------------
  52. Function name : FilterMotion
  53. Description :
  54. Return type : void
  55. Argument : SwStbData * data
  56. Argument : i32 * minX
  57. Argument : i32 * minY
  58. ------------------------------------------------------------------------------*/
  59. void FilterMotion(SwStbData * data, i32 * minX, i32 * minY)
  60. {
  61. i32 meanX, meanY;
  62. i32 edgeX, edgeY;
  63. edgeX = (data->inputWidth - data->stabilizedWidth) / 2;
  64. edgeY = (data->inputHeight - data->stabilizedHeight) / 2;
  65. data->filterX += *minX;
  66. data->filterY += *minY;
  67. data->filterX += data->filterErrorX;
  68. data->filterY += data->filterErrorY;
  69. data->filterX -= data->filterErrorXp;
  70. data->filterY -= data->filterErrorYp;
  71. meanX = data->filterX / data->filterLengthX;
  72. meanY = data->filterY / data->filterLengthY;
  73. data->filterErrorXp = data->filterErrorX;
  74. data->filterErrorYp = data->filterErrorY;
  75. data->filterErrorX = data->filterX - meanX * data->filterLengthX;
  76. data->filterErrorY = data->filterY - meanY * data->filterLengthY;
  77. data->filterX -= meanX;
  78. data->filterY -= meanY;
  79. data->filterSumStabX += meanX;
  80. data->filterSumStabY += meanY;
  81. data->filterSumMotX += *minX;
  82. data->filterSumMotY += *minY;
  83. /* Compensate motion with filter */
  84. *minX -= meanX;
  85. *minY -= meanY;
  86. /* Adjust the filter length */
  87. if((ABS(data->filterSumMotX - data->filterSumStabX) >= 3 * edgeX / 4) &&
  88. data->filterLengthX > 4)
  89. data->filterLengthX -= 2;
  90. if((ABS(data->filterSumMotX - data->filterSumStabX) <= edgeX / 4) &&
  91. data->filterLengthX < 40)
  92. data->filterLengthX += 2;
  93. if((ABS(data->filterSumMotY - data->filterSumStabY) >= 3 * edgeY / 4) &&
  94. data->filterLengthY > 4)
  95. data->filterLengthY -= 2;
  96. if((ABS(data->filterSumMotY - data->filterSumStabY) <= edgeY / 4) &&
  97. data->filterLengthY < 40)
  98. data->filterLengthY += 2;
  99. }
  100. /*------------------------------------------------------------------------------
  101. Function name : InterpolateMotion
  102. Description :
  103. Return type : void
  104. Argument : i32 ** data
  105. Argument : i32 * hor
  106. Argument : i32 * ver
  107. ------------------------------------------------------------------------------*/
  108. void InterpolateMotion(i32(*data)[5], i32 * hor, i32 * ver)
  109. {
  110. i32 i, j, tmp;
  111. i32 min = 0;
  112. for(i = 0; i < 5; i += 2)
  113. {
  114. for(j = 1; j < 5; j += 2)
  115. {
  116. data[i][j] = (data[i][j - 1] + data[i][j + 1] + 1) / 2;
  117. }
  118. }
  119. for(i = 1; i < 5; i += 2)
  120. {
  121. for(j = 0; j < 5; j++)
  122. {
  123. data[i][j] = (data[i - 1][j] + data[i + 1][j] + 1) / 2;
  124. }
  125. }
  126. /* Find minimum */
  127. for(i = 1; i < 4; i++)
  128. {
  129. for(j = 1; j < 4; j++)
  130. {
  131. tmp = data[i - 1][j - 1]
  132. + data[i - 1][j]
  133. + data[i - 1][j + 1]
  134. + data[i][j - 1]
  135. + data[i][j]
  136. + data[i][j + 1]
  137. + data[i + 1][j - 1] + data[i + 1][j] + data[i + 1][j + 1];
  138. if((i == 1) && (j == 1))
  139. {
  140. min = tmp;
  141. *ver = i - 2;
  142. *hor = j - 2;
  143. }
  144. if(tmp < min)
  145. {
  146. min = tmp;
  147. *ver = i - 2;
  148. *hor = j - 2;
  149. }
  150. }
  151. }
  152. }
  153. /*------------------------------------------------------------------------------
  154. Function name : QuarterPixelMotion
  155. Description :
  156. Return type : void
  157. Argument : SwStbData * data
  158. Argument : i32 minX
  159. Argument : i32 minY
  160. ------------------------------------------------------------------------------*/
  161. void QuarterPixelMotion(SwStbData * data, i32 minX, i32 minY)
  162. {
  163. const u32 *motion = data->motion;
  164. i32(*half)[5] = data->half;
  165. i32(*quarter)[5] = data->quarter;
  166. i32 ver = 0;
  167. i32 hor = 0;
  168. i32 i, j;
  169. /* 1/4 pixel is not calculated for +-16 pixel GMV */
  170. if((ABS(minX - 16) < 16) && (ABS(minY - 16) < 16))
  171. {
  172. /* Get full pixel samples around minimum */
  173. for(i = 0; i < 3; i++)
  174. {
  175. for(j = 0; j < 3; j++)
  176. {
  177. half[2 * i][2 * j] = motion[i * 3 + j];
  178. }
  179. }
  180. /* Interpolate to half pixel */
  181. InterpolateMotion(half, &hor, &ver);
  182. data->qpMotionX += 2 * hor;
  183. data->qpMotionY += 2 * ver;
  184. /* Get half pixel samples around minimum */
  185. for(i = 0; i < 3; i++)
  186. {
  187. for(j = 0; j < 3; j++)
  188. {
  189. quarter[2 * i][2 * j] = half[1 + ver + i][1 + hor + j];
  190. }
  191. }
  192. /* Interpolate to quarter pixel */
  193. InterpolateMotion(quarter, &hor, &ver);
  194. data->qpMotionX += hor;
  195. data->qpMotionY += ver;
  196. }
  197. }
  198. /*------------------------------------------------------------------------------
  199. Function name : VSAlgStabilize
  200. Description :
  201. Return type : u32
  202. Argument : SwStbData * data
  203. Argument : const HWStabData * hwStabData
  204. ------------------------------------------------------------------------------*/
  205. u32 VSAlgStabilize(SwStbData * data, const HWStabData * hwStabData)
  206. {
  207. i32 minX, minY;
  208. i32 edgeX, edgeY;
  209. u32 min, mean;
  210. /* inputImage = whole frame from the camera
  211. * stabilizedImage = area to be encoded */
  212. /* Quarter pixel motion in [-2, 2] */
  213. if((data->qpMotionX < -2) || (data->qpMotionX > 2))
  214. data->qpMotionX = 0;
  215. if((data->qpMotionY < -2) || (data->qpMotionY > 2))
  216. data->qpMotionY = 0;
  217. edgeX = (data->inputWidth - data->stabilizedWidth) / 2;
  218. edgeY = (data->inputHeight - data->stabilizedHeight) / 2;
  219. mean = hwStabData->rMotionSum / 1089;
  220. min = hwStabData->rMotionMin;
  221. minX = hwStabData->rGmvX + 16; /* alg is using [0, 32] range */
  222. minY = hwStabData->rGmvY + 16; /* alg is using [0, 32] range */
  223. data->motion = hwStabData->rMatrixVal;
  224. /* scene change detection */
  225. if((min > (3*data->prevMin/2)) && (mean > (3*data->prevMean/2)))
  226. {
  227. /* Scene change works like a start of sequence
  228. * The internal variables will be zeroed for the next frame */
  229. data->prevMin = min;
  230. data->prevMean = mean;
  231. data->sceneChange = 1; /* signal scene change */
  232. #ifdef TRACE_VIDEOSTAB_INTERNAL
  233. DEBUG_PRINT(("VS: Scene change detected\n"));
  234. #endif
  235. #ifdef TEST_DATA
  236. PrintTraceFile((data->inputWidth - data->stabilizedWidth) / 2,
  237. (data->inputHeight - data->stabilizedHeight) / 2);
  238. #endif
  239. return 1; /* reset stab also */
  240. }
  241. else
  242. {
  243. data->sceneChange = 0; /* no scene change */
  244. data->prevMin = min;
  245. data->prevMean = mean;
  246. }
  247. /* Threshold for not finding significant overall motion */
  248. if((mean == 0) || ((85 * mean / 100) < min))
  249. {
  250. /* The internal variables will be zeroed for the next frame */
  251. #ifdef TRACE_VIDEOSTAB_INTERNAL
  252. DEBUG_PRINT(("VS: No motion detected\n"));
  253. #endif
  254. #ifdef TEST_DATA
  255. PrintTraceFile((data->inputWidth - data->stabilizedWidth) / 2,
  256. (data->inputHeight - data->stabilizedHeight) / 2);
  257. #endif
  258. return 1;
  259. }
  260. /* Half-pixel and quarter-pixel motion */
  261. QuarterPixelMotion(data, minX, minY);
  262. /* Add half pixel motion */
  263. if(data->qpMotionX > 2)
  264. {
  265. minX += 1;
  266. data->qpMotionX -= 4;
  267. }
  268. if(data->qpMotionX < -2)
  269. {
  270. minX -= 1;
  271. data->qpMotionX += 4;
  272. }
  273. if(data->qpMotionY > 2)
  274. {
  275. minY += 1;
  276. data->qpMotionY -= 4;
  277. }
  278. if(data->qpMotionY < -2)
  279. {
  280. minY -= 1;
  281. data->qpMotionY += 4;
  282. }
  283. /* Compensated motion */
  284. minX = 16 - minX;
  285. minY = 16 - minY;
  286. FilterMotion(data, &minX, &minY);
  287. /* Calculate the new stabilized picture offset */
  288. data->filterPosX = data->filterPosX + minX;
  289. data->filterPosY = data->filterPosY + minY;
  290. /* Saturate the stabilized window into input picture */
  291. data->stabOffsetX = MIN(MAX(data->filterPosX, 0), 2 * edgeX);
  292. data->stabOffsetY = MIN(MAX(data->filterPosY, 0), 2 * edgeY);
  293. #ifdef TRACE_VIDEOSTAB_INTERNAL
  294. DEBUG_PRINT(("VS: New Result %d, %d\n", data->stabOffsetX,
  295. data->stabOffsetY));
  296. #endif
  297. #ifdef TEST_DATA
  298. PrintTraceFile(data->stabOffsetX, data->stabOffsetY);
  299. #endif
  300. return 0;
  301. }
  302. /*------------------------------------------------------------------------------
  303. Function name : VSAlgInit
  304. Description :
  305. Return type : void
  306. Argument : SwStbData * data
  307. Argument : u32 srcWidth
  308. Argument : u32 srcHeight
  309. Argument : u32 width
  310. Argument : u32 height
  311. ------------------------------------------------------------------------------*/
  312. void VSAlgInit(SwStbData * data, u32 srcWidth, u32 srcHeight, u32 width,
  313. u32 height)
  314. {
  315. data->inputWidth = srcWidth;
  316. data->inputHeight = srcHeight;
  317. data->stabilizedWidth = width;
  318. data->stabilizedHeight = height;
  319. data->prevMean = ~0;
  320. data->prevMin = ~0;
  321. data->sceneChange = 0;
  322. VSAlgReset(data);
  323. }
  324. /*------------------------------------------------------------------------------
  325. Function name : VSAlgGetResult
  326. Description :
  327. Return type : void
  328. Argument : const SwStbData * data
  329. Argument : u32 * xOff
  330. Argument : u32 * yOff
  331. ------------------------------------------------------------------------------*/
  332. void VSAlgGetResult(const SwStbData * data, u32 * xOff, u32 * yOff)
  333. {
  334. *xOff = data->stabOffsetX;
  335. *yOff = data->stabOffsetY;
  336. #ifdef TRACE_VIDEOSTAB_INTERNAL
  337. DEBUG_PRINT(("VS: Get Result %d, %d\n", data->stabOffsetX,
  338. data->stabOffsetY));
  339. #endif
  340. }
  341. /*------------------------------------------------------------------------------
  342. Function name : VSAlgReset
  343. Description :
  344. Return type : void
  345. Argument : SwStbData * data
  346. ------------------------------------------------------------------------------*/
  347. void VSAlgReset(SwStbData * data)
  348. {
  349. i32 edgeX, edgeY;
  350. edgeX = (data->inputWidth - data->stabilizedWidth) / 2;
  351. edgeY = (data->inputHeight - data->stabilizedHeight) / 2;
  352. data->qpMotionX = 0;
  353. data->qpMotionY = 0;
  354. data->stabOffsetX = edgeX;
  355. data->stabOffsetY = edgeY;
  356. data->filterPosX = edgeX;
  357. data->filterPosY = edgeY;
  358. data->filterX = 0;
  359. data->filterY = 0;
  360. data->filterErrorX = 0;
  361. data->filterErrorY = 0;
  362. data->filterErrorXp = 0;
  363. data->filterErrorYp = 0;
  364. data->filterSumMotX = 0;
  365. data->filterSumMotY = 0;
  366. data->filterSumStabX = 0;
  367. data->filterSumStabY = 0;
  368. data->filterLengthX = 16;
  369. data->filterLengthY = 16;
  370. }