123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- /*------------------------------------------------------------------------------
- -- --
- -- This software is confidential and proprietary and may be used --
- -- only as expressly authorized by a licensing agreement from --
- -- --
- -- Hantro Products Oy. --
- -- --
- -- (C) COPYRIGHT 2006 HANTRO PRODUCTS OY --
- -- ALL RIGHTS RESERVED --
- -- --
- -- The entire notice above must be reproduced --
- -- on all copies and should not be removed. --
- -- --
- --------------------------------------------------------------------------------
- -
- - Description : Video stabilization algorithms. Quarter pixel ME, Motion filter
- -
- ------------------------------------------------------------------------------*/
- #include "basetype.h"
- #include "vidstabcommon.h"
- #ifdef TEST_DATA
- #include <stdio.h>
- #endif
- #define ABS(x) ((x) < (0) ? -(x) : (x))
- #define MAX(a, b) ((a) > (b) ? (a) : (b))
- #define MIN(a, b) ((a) < (b) ? (a) : (b))
- static void QuarterPixelMotion(SwStbData * data, i32 minX, i32 minY);
- static void InterpolateMotion(i32(*data)[5], i32 * half_hor, i32 * half_ver);
- static void FilterMotion(SwStbData * data, i32 * minX, i32 * minY);
- #ifdef TEST_DATA
- /*------------------------------------------------------------------------------
- Function name : PrintTraceFile
- Description :
- Return type : void
- Argument : x
- Argument : y
- ------------------------------------------------------------------------------*/
- void PrintTraceFile(i32 x, i32 y)
- {
- static FILE *fTrc = NULL;
- if (fTrc == NULL)
- {
- fTrc = fopen("video_stab_result.trc", "w");
- if (fTrc)
- fprintf(fTrc, "offX, offY\n");
- }
- if (fTrc)
- fprintf(fTrc, "%4d, %4d\n", x, y);
- }
- #endif
- /*------------------------------------------------------------------------------
- Function name : FilterMotion
- Description :
- Return type : void
- Argument : SwStbData * data
- Argument : i32 * minX
- Argument : i32 * minY
- ------------------------------------------------------------------------------*/
- void FilterMotion(SwStbData * data, i32 * minX, i32 * minY)
- {
- i32 meanX, meanY;
- i32 edgeX, edgeY;
- edgeX = (data->inputWidth - data->stabilizedWidth) / 2;
- edgeY = (data->inputHeight - data->stabilizedHeight) / 2;
- data->filterX += *minX;
- data->filterY += *minY;
- data->filterX += data->filterErrorX;
- data->filterY += data->filterErrorY;
- data->filterX -= data->filterErrorXp;
- data->filterY -= data->filterErrorYp;
- meanX = data->filterX / data->filterLengthX;
- meanY = data->filterY / data->filterLengthY;
- data->filterErrorXp = data->filterErrorX;
- data->filterErrorYp = data->filterErrorY;
- data->filterErrorX = data->filterX - meanX * data->filterLengthX;
- data->filterErrorY = data->filterY - meanY * data->filterLengthY;
- data->filterX -= meanX;
- data->filterY -= meanY;
- data->filterSumStabX += meanX;
- data->filterSumStabY += meanY;
- data->filterSumMotX += *minX;
- data->filterSumMotY += *minY;
- /* Compensate motion with filter */
- *minX -= meanX;
- *minY -= meanY;
- /* Adjust the filter length */
- if((ABS(data->filterSumMotX - data->filterSumStabX) >= 3 * edgeX / 4) &&
- data->filterLengthX > 4)
- data->filterLengthX -= 2;
- if((ABS(data->filterSumMotX - data->filterSumStabX) <= edgeX / 4) &&
- data->filterLengthX < 40)
- data->filterLengthX += 2;
- if((ABS(data->filterSumMotY - data->filterSumStabY) >= 3 * edgeY / 4) &&
- data->filterLengthY > 4)
- data->filterLengthY -= 2;
- if((ABS(data->filterSumMotY - data->filterSumStabY) <= edgeY / 4) &&
- data->filterLengthY < 40)
- data->filterLengthY += 2;
- }
- /*------------------------------------------------------------------------------
- Function name : InterpolateMotion
- Description :
- Return type : void
- Argument : i32 ** data
- Argument : i32 * hor
- Argument : i32 * ver
- ------------------------------------------------------------------------------*/
- void InterpolateMotion(i32(*data)[5], i32 * hor, i32 * ver)
- {
- i32 i, j, tmp;
- i32 min = 0;
- for(i = 0; i < 5; i += 2)
- {
- for(j = 1; j < 5; j += 2)
- {
- data[i][j] = (data[i][j - 1] + data[i][j + 1] + 1) / 2;
- }
- }
- for(i = 1; i < 5; i += 2)
- {
- for(j = 0; j < 5; j++)
- {
- data[i][j] = (data[i - 1][j] + data[i + 1][j] + 1) / 2;
- }
- }
- /* Find minimum */
- for(i = 1; i < 4; i++)
- {
- for(j = 1; j < 4; j++)
- {
- tmp = data[i - 1][j - 1]
- + data[i - 1][j]
- + data[i - 1][j + 1]
- + data[i][j - 1]
- + data[i][j]
- + data[i][j + 1]
- + data[i + 1][j - 1] + data[i + 1][j] + data[i + 1][j + 1];
- if((i == 1) && (j == 1))
- {
- min = tmp;
- *ver = i - 2;
- *hor = j - 2;
- }
- if(tmp < min)
- {
- min = tmp;
- *ver = i - 2;
- *hor = j - 2;
- }
- }
- }
- }
- /*------------------------------------------------------------------------------
- Function name : QuarterPixelMotion
- Description :
- Return type : void
- Argument : SwStbData * data
- Argument : i32 minX
- Argument : i32 minY
- ------------------------------------------------------------------------------*/
- void QuarterPixelMotion(SwStbData * data, i32 minX, i32 minY)
- {
- const u32 *motion = data->motion;
- i32(*half)[5] = data->half;
- i32(*quarter)[5] = data->quarter;
- i32 ver = 0;
- i32 hor = 0;
- i32 i, j;
- /* 1/4 pixel is not calculated for +-16 pixel GMV */
- if((ABS(minX - 16) < 16) && (ABS(minY - 16) < 16))
- {
- /* Get full pixel samples around minimum */
- for(i = 0; i < 3; i++)
- {
- for(j = 0; j < 3; j++)
- {
- half[2 * i][2 * j] = motion[i * 3 + j];
- }
- }
- /* Interpolate to half pixel */
- InterpolateMotion(half, &hor, &ver);
- data->qpMotionX += 2 * hor;
- data->qpMotionY += 2 * ver;
- /* Get half pixel samples around minimum */
- for(i = 0; i < 3; i++)
- {
- for(j = 0; j < 3; j++)
- {
- quarter[2 * i][2 * j] = half[1 + ver + i][1 + hor + j];
- }
- }
- /* Interpolate to quarter pixel */
- InterpolateMotion(quarter, &hor, &ver);
- data->qpMotionX += hor;
- data->qpMotionY += ver;
- }
- }
- /*------------------------------------------------------------------------------
- Function name : VSAlgStabilize
- Description :
- Return type : u32
- Argument : SwStbData * data
- Argument : const HWStabData * hwStabData
- ------------------------------------------------------------------------------*/
- u32 VSAlgStabilize(SwStbData * data, const HWStabData * hwStabData)
- {
- i32 minX, minY;
- i32 edgeX, edgeY;
- u32 min, mean;
- /* inputImage = whole frame from the camera
- * stabilizedImage = area to be encoded */
- /* Quarter pixel motion in [-2, 2] */
- if((data->qpMotionX < -2) || (data->qpMotionX > 2))
- data->qpMotionX = 0;
- if((data->qpMotionY < -2) || (data->qpMotionY > 2))
- data->qpMotionY = 0;
- edgeX = (data->inputWidth - data->stabilizedWidth) / 2;
- edgeY = (data->inputHeight - data->stabilizedHeight) / 2;
- mean = hwStabData->rMotionSum / 1089;
- min = hwStabData->rMotionMin;
- minX = hwStabData->rGmvX + 16; /* alg is using [0, 32] range */
- minY = hwStabData->rGmvY + 16; /* alg is using [0, 32] range */
- data->motion = hwStabData->rMatrixVal;
- /* scene change detection */
- if((min > (3*data->prevMin/2)) && (mean > (3*data->prevMean/2)))
- {
- /* Scene change works like a start of sequence
- * The internal variables will be zeroed for the next frame */
- data->prevMin = min;
- data->prevMean = mean;
- data->sceneChange = 1; /* signal scene change */
- #ifdef TRACE_VIDEOSTAB_INTERNAL
- DEBUG_PRINT(("VS: Scene change detected\n"));
- #endif
- #ifdef TEST_DATA
- PrintTraceFile((data->inputWidth - data->stabilizedWidth) / 2,
- (data->inputHeight - data->stabilizedHeight) / 2);
- #endif
- return 1; /* reset stab also */
- }
- else
- {
- data->sceneChange = 0; /* no scene change */
- data->prevMin = min;
- data->prevMean = mean;
- }
- /* Threshold for not finding significant overall motion */
- if((mean == 0) || ((85 * mean / 100) < min))
- {
- /* The internal variables will be zeroed for the next frame */
- #ifdef TRACE_VIDEOSTAB_INTERNAL
- DEBUG_PRINT(("VS: No motion detected\n"));
- #endif
- #ifdef TEST_DATA
- PrintTraceFile((data->inputWidth - data->stabilizedWidth) / 2,
- (data->inputHeight - data->stabilizedHeight) / 2);
- #endif
- return 1;
- }
- /* Half-pixel and quarter-pixel motion */
- QuarterPixelMotion(data, minX, minY);
- /* Add half pixel motion */
- if(data->qpMotionX > 2)
- {
- minX += 1;
- data->qpMotionX -= 4;
- }
- if(data->qpMotionX < -2)
- {
- minX -= 1;
- data->qpMotionX += 4;
- }
- if(data->qpMotionY > 2)
- {
- minY += 1;
- data->qpMotionY -= 4;
- }
- if(data->qpMotionY < -2)
- {
- minY -= 1;
- data->qpMotionY += 4;
- }
- /* Compensated motion */
- minX = 16 - minX;
- minY = 16 - minY;
- FilterMotion(data, &minX, &minY);
- /* Calculate the new stabilized picture offset */
- data->filterPosX = data->filterPosX + minX;
- data->filterPosY = data->filterPosY + minY;
- /* Saturate the stabilized window into input picture */
- data->stabOffsetX = MIN(MAX(data->filterPosX, 0), 2 * edgeX);
- data->stabOffsetY = MIN(MAX(data->filterPosY, 0), 2 * edgeY);
- #ifdef TRACE_VIDEOSTAB_INTERNAL
- DEBUG_PRINT(("VS: New Result %d, %d\n", data->stabOffsetX,
- data->stabOffsetY));
- #endif
- #ifdef TEST_DATA
- PrintTraceFile(data->stabOffsetX, data->stabOffsetY);
- #endif
- return 0;
- }
- /*------------------------------------------------------------------------------
- Function name : VSAlgInit
- Description :
- Return type : void
- Argument : SwStbData * data
- Argument : u32 srcWidth
- Argument : u32 srcHeight
- Argument : u32 width
- Argument : u32 height
- ------------------------------------------------------------------------------*/
- void VSAlgInit(SwStbData * data, u32 srcWidth, u32 srcHeight, u32 width,
- u32 height)
- {
- data->inputWidth = srcWidth;
- data->inputHeight = srcHeight;
- data->stabilizedWidth = width;
- data->stabilizedHeight = height;
- data->prevMean = ~0;
- data->prevMin = ~0;
- data->sceneChange = 0;
- VSAlgReset(data);
- }
- /*------------------------------------------------------------------------------
- Function name : VSAlgGetResult
- Description :
- Return type : void
- Argument : const SwStbData * data
- Argument : u32 * xOff
- Argument : u32 * yOff
- ------------------------------------------------------------------------------*/
- void VSAlgGetResult(const SwStbData * data, u32 * xOff, u32 * yOff)
- {
- *xOff = data->stabOffsetX;
- *yOff = data->stabOffsetY;
- #ifdef TRACE_VIDEOSTAB_INTERNAL
- DEBUG_PRINT(("VS: Get Result %d, %d\n", data->stabOffsetX,
- data->stabOffsetY));
- #endif
- }
- /*------------------------------------------------------------------------------
- Function name : VSAlgReset
- Description :
- Return type : void
- Argument : SwStbData * data
- ------------------------------------------------------------------------------*/
- void VSAlgReset(SwStbData * data)
- {
- i32 edgeX, edgeY;
- edgeX = (data->inputWidth - data->stabilizedWidth) / 2;
- edgeY = (data->inputHeight - data->stabilizedHeight) / 2;
- data->qpMotionX = 0;
- data->qpMotionY = 0;
- data->stabOffsetX = edgeX;
- data->stabOffsetY = edgeY;
- data->filterPosX = edgeX;
- data->filterPosY = edgeY;
- data->filterX = 0;
- data->filterY = 0;
- data->filterErrorX = 0;
- data->filterErrorY = 0;
- data->filterErrorXp = 0;
- data->filterErrorYp = 0;
- data->filterSumMotX = 0;
- data->filterSumMotY = 0;
- data->filterSumStabX = 0;
- data->filterSumStabY = 0;
- data->filterLengthX = 16;
- data->filterLengthY = 16;
- }
|