Hình 43: So sánh kết quả PSNR giữa phương pháp Forward-Backward Bi-Directional ME [2, 8] và MCI tham chiếu, nội suy tuyến tính
(để kết quả PSNR có ý nghĩa hơn với phương pháp MCI tham chiếu, khi giá trị mặc định của các vùng lỗ trống có ảnh hưởng nhiều đến kết quả PSNR, các vùng lỗ trống sẽ được thay thế bằng các giá trị pixel trung bình của frame hiện tại và liền trước) (trục hoành là thứ tự các frame nội suy đánh từ 1÷100, nghĩa là frame nội suy thứ 2, 4, 6, …, 200)
Hình 44: So sánh kết quả PSNR khi ước lượng vector chuyển động của block frame nội suy dựa vào ước lượng chuyển động tiến [2], và kết hợp cả ước lượng chuyển động
Từ kết quả PSNR, ta thấy rõ phương pháp MCI sử dụng ước lượng vector chuyển động 2 chiều cho chất lượng cao hơn phương pháp MCI tham chiếu và nội suy tuyến tính. Trong đó, nếu bước ước lượng chuyển động sử dụng cả ước lượng chuyển động tiến và lùi thì kết quả sẽ cao hơn là chỉ sử dụng ước lượng chuyển động tiến.
KẾT LUẬN
Luận văn đã giới thiệu được nhu cầu cần thiết của việc tăng tốc độ khung hình FRUC cũng như các thuật toán cơ bản đang được sử dụng: nhóm các thuật toán không dựa vào chuyển động: thuật toán lặp lại khung hình, thuật toán nội suy tuyến tính, nhóm các thuật toán dựa vào chuyển động: thuật toán nội suy bù chuyển động tham chiếu. Cùng các vấn đề còn tồn tại: vùng chồng lấn và lỗ trống, hiệu ứng khối.
Luận văn đã trình bày phương pháp tăng tốc độ khung hình mới sử dụng ước lượng chuyển động hai chiều kết hợp cả tiến và lùi, tham khảo từ [2] và [8], cải tiến so với phương pháp MCI tham chiếu. Kết quả thực thi của thuật toán bằng ngôn ngữ C, có sử dụng thư viện Opencv để xử lý video cho thấy thuật toán đạt chất lượng cao hơn so với thuật toán MCI tham chiếu, cũng như khắc phục được các vùng chồng lấn và lỗ trống, cũng như hiệu ứng khối hiệu quả.
Tương lai, thuật toán có thể được tiếp tục nghiên cứu tiếp theo hướng nâng cao việc nội suy vector chuyển động từ 2 chiều tuyến tính lên thành việc nội suy từ quỹ đạo phi tuyến từ nhiều frame liên tiếp (được tạo ra bởi hàm đa thức).
TÀI LIỆU THAM KHẢO
Tiếng Việt
[1] Hoàng Đình Chiến (2009), “Ứng dụng thuật toán chỉnh sửa và tăng độ phân giải vector chuyển động trong kỹ thuật tăng số khung hình cho video”, Tạp chí phát triển KH&CN, TẬP 12, SỐ 08 – 2009.
Tiếng Anh
[2] B.-T. Choi, S.-H. Lee, and S.-J. Ko, “New Frame Rate Up-Conversion Using Bi- directional Motion Estimation”, IEEE Transactions on Consumer Electronics, Vol. 46, Issue 3, August 2000, pp. 603-609.
[3] Abhishek Girotra, Motion Estimation – An Overview
http://sitemaker.umich.edu/agirotra/files/SANPre.ppt
[4] Lee, S.-H., Kwon, O. and Park, R.-H., “Weighted-adaptive motion-compensated frame rate up-conversion”, IEEE Trans. Consumer Electron. v49 i3. 485-492
[5] Saranta Ponla, Frame rate up conversion by block based affine transform, Computer science master thesis, Mahidol University, 2009.
[6] R. Thoma and M. Bierling, "Motion compensating interpolation considering covered and uncovered background", Signal Processing Image Compression, vol.1, pp. 192-212, 1989.
[7] Deepak Turaga, Mohamed Alkanhal, Search Algorithms for Block-Matching in Motion Estimation, Mid-Term project, 18-899, Spring, 1998.
http://www.ece.cmu.edu/~ee899/project/deepak_mid.htm
[8] Truong Quang Vinh, Young-Chul Kim, Sung-Hoon Hong, “Frame Rate Up- Conversion Using Forward-Backward Jointing Motion Estimation And Spatio- Temporal Motion Vector Smoothing”, International Conference on Computer Engineering & Systems, 2009. ICCES 2009, pp. 605 – 609.
PHỤ LỤC Các hàm thực thi Source code File fruc.h #include "../../opencv_dll/cv.h" #include "../../opencv_dll/highgui.h" #include "common.h" #ifndef _fruc_h_ #define _fruc_h_ //#define debug
#define NO_FRAME 300 /*for test, not load all frames*/
#define FRAME_NO_IN 1 #define FRAME_NO_OUT 2 #define FRAME_WIDTH 352 #define FRAME_HEIGHT 288 #define BLOCK_WIDTH 8 #define BLOCK_HEIGHT 8 #define SEARCH_RANGE_WIDTH 8 #define SEARCH_RANGE_HEIGHT 8 #define OVERLAPPED_BLOCK_WIDTH 2 #define OVERLAPPED_BLOCK_HEIGHT 2 #define DISPLACEMENT 2 #define NO_BLOCK 1584 /* 352x288 / (8x8) = 1584 */ #define IMAGE_MV_NCHANNEL 3
ER MotionVector(IplImage* pIFrame_curr, IplImage* pIFrame_prev, CvSize SBlock_size, CvSize SSearch_range, IplImage** ppIFrame_curr_mv, float* pfMAD_mean);
//Linear Interpolation
ER LinearInterpolation(IplImage* pISrc1, CvPoint PPst1, IplImage* pISrc2, CvPoint PPst2, IplImage* pIDst, CvPoint PPst, CvSize SBlockSize);
//Conventional
ER MCI_Conventional_forward(IplImage* pIFrame_curr, IplImage* pIFrame_prev, CvSize SBlock_size, CvSize SSearch_range, int iFrame_no_in, int
iFrame_no_out,IplImage** ppIFrame_intp);
ER Interpolation_Conventional(IplImage* pIFrame_prev, IplImage* pIFrame_prev_mv, CvSize SBlock_size,
int iFrame_no_in, int iFrame_no_out, IplImage** ppIFrame_intp);
ER MCI_BiDirectional(IplImage* pIFrame_curr, IplImage* pIFrame_prev, CvSize SBlock_size, CvSize SSearch_range, CvSize SOverlapBlock_size, int
iFrame_no_in, int iFrame_no_out, IplImage** ppIFrame_intp);
#endif /*_fruc_h_*/ File common.h #include "../../opencv_dll/cv.h" #include "../../opencv_dll/highgui.h" #ifndef _common_h_ #define _common_h_ enum ER { E_OK = 0, E_INVALID = 1, E_UNRESOLVED = 2 };
ER ReadYUVFile(char* pcFilename, int iW, int iH, IplImage*** pppIFrame_ls,
int* piFrame_no);
ER FullSearchBlockAlgorithm(IplImage* pIFrame_curr, CvRect RBlock, IplImage* pIFrame_prev, CvRect RSearch_area, CvPoint* pPPst, int* piMAD_min, float* pfMAD_mean);
ER MAD(IplImage* pIFrame1, CvPoint PPst1, IplImage* pIFrame2, CvPoint PPst2, CvSize SBlock_size, int* piResult);
ER CopyImage(IplImage* pISrc, CvRect RArea, IplImage* pIDst, CvPoint PPst2);
void show(char* name, int x, int y, IplImage* image, int resize=0);
double calcPSNR(const CvArr *a, const CvArr *b);
#endif /*_common_h_*/ File common.cpp #include <conio.h> #include <stdio.h> #include "common.h" #include "fruc.h" #include <string> #include <iostream> #include <fstream> #include <iterator> /***
*ER ReadYUVFile(char* pcFilename, int iW, int iH, IplImage*** pppIFrame_ls, int* piFrame_no)
*
*Purpose: *Entry:
* char* [in] pcFilename
* int [in] iW
* IplImage*** [out] pppIFrame_ls - memory is allocated by the function
* int* [out] piFrame_no
*Return:
* E_OK
* E_INVALID
* E_UNRESOLVED
**************************************************************************/
ER ReadYUVFile(char* pcFilename, int iW, int iH, IplImage*** pppIFrame_ls,
int* piFrame_no) { FILE* pF; IplImage** ppIFrame_ls; long lF_size; int iFrame_no; int iFrame_id;
int iReadByte; //for checking number of byte read from the
file
IplImage* pIm; //for storing image each time reading file
char* pcTemp; //for storing u-v component
ER EReturn = E_OK;
//open yuv file for reading
fopen_s(&pF, pcFilename, "rb");
if(pF == NULL) {
printf("\n %s File can't be open!", pcFilename);
return E_INVALID;
}
// obtain file size:
fseek (pF , 0 , SEEK_END); lF_size = ftell (pF);
rewind (pF); //Set position indicator to the beginning //number of frame in the video sequence
iFrame_no = lF_size / (3 * iW * iH / 2);
/*******************************/
ppIFrame_ls = (IplImage**) malloc (sizeof(IplImage*) * iFrame_no);
if (ppIFrame_ls == NULL) {
fputs ("Memory error",stderr);
return E_UNRESOLVED;
}
*pppIFrame_ls = ppIFrame_ls;
// allocate temparory memory for storing u-v component
pcTemp = (char*) malloc(sizeof(char) * int(iW * iH / 2)); //4:2:0 video
char cName[10]; iFrame_id = 0;
while(iFrame_id < NO_FRAME) //test for NO_FRAME, not load all (take
long time)
{
pIm = cvCreateImage(cvSize(iW, iH), IPL_DEPTH_8U, 1);//gray scale image if (!pIm) { EReturn = E_UNRESOLVED; break; } // reading image // y component
iReadByte = fread(pIm->imageData, 1, pIm->imageSize, pF);
if (iReadByte < pIm->imageSize) { EReturn = E_UNRESOLVED; break; } //u v component //4:2:0
//read to pcTemp, --> no store
iReadByte = fread(pcTemp, 1, (pIm->imageSize / 2), pF);
if (iReadByte < (pIm->imageSize / 2)) { EReturn = E_UNRESOLVED; break; } ppIFrame_ls[iFrame_id] = pIm; iFrame_id++; }
*piFrame_no = iFrame_id; //from 0 - (iFrame_id - 1)
fclose(pF); free(pcTemp);
return EReturn;
}
/*
pIFrame_curr: Frame that is finding motion vector for each block pIFrame_prev: Frame for search area
RBlock: (.x, .y) --> block position (.width, .height) --> block size
RSearch_areaa: (.x, .y) --> searched position
(.width, .height) --> searched size pPPst: output position: where MAD is min
piMAD_min: output, min MAD value pfMAD_mean: output, mean MAD value */
ER FullSearchBlockAlgorithm(IplImage* pIFrame_curr, CvRect RBlock,
IplImage* pIFrame_prev, CvRect RSearch_areaa, CvPoint* pPPst,
int* piMAD_min, float* pfMAD_mean) {
int w, h;
int mad;
int no_blk = 0, sum = 0; ER Err;
*piMAD_min = 65537; no_blk = 0;
sum = 0;
for (h = RSearch_areaa.y; h < RSearch_areaa.y + RSearch_areaa.height - RBlock.height; h++)
{
for (w = RSearch_areaa.x; w <= RSearch_areaa.x + RSearch_areaa.width - RBlock.width; w++)
{
Err = MAD(pIFrame_curr, cvPoint(RBlock.x,RBlock.y),
pIFrame_prev, cvPoint(w, h), cvSize(RBlock.width, RBlock.height), &mad);
if (Err != E_OK) return Err;
/* add mad value*/
sum += mad; no_blk ++;
/* calculate the min value of mad and save the position*/
if (*piMAD_min > mad) { *piMAD_min = mad; pPPst->x = w; pPPst->y = h; } } } if ((pPPst->x > 400) || (pPPst->y > 400)) {
printf("\nout of range in search result\nPress any key to
continue");
_getch(); }
*pfMAD_mean = float (sum) / (float)no_blk;//no_blk = 252
return E_OK;
}
/*
Mean of Absolute Different Input image is GRAY image
PPst1: left-top position of block of image 1 */
ER MAD(IplImage* pIFrame1, CvPoint PPst1, IplImage* pIFrame2, CvPoint PPst2, CvSize SBlock_size, int* piResult)
{
int p1 = 0, p2 = 0; /* pixel position in 1D array */
int h = 0, w = 0;
if ((!pIFrame1)||(!pIFrame2)) {
printf("MAD: 2 input images have different size");
return E_INVALID;
}
if ((pIFrame1->nChannels > 1) || (pIFrame2->nChannels > 1)) {
printf("MAD: input image is not GRAY image");
return E_INVALID;
}
if ((PPst1.x > pIFrame1->width) || (PPst1.y > pIFrame1->height)) return
E_INVALID;
if ((PPst2.x > pIFrame2->width) || (PPst2.y > pIFrame2->height)) return
E_INVALID;
if ((SBlock_size.width < 1) || (SBlock_size.height < 1)) return
E_INVALID;
int n = 0;
for(h = 0; h < SBlock_size.height; h ++) {
for(w = 0; w < SBlock_size.width; w++) {
p1 = (PPst1.y + h) * pIFrame1->widthStep + PPst1.x + w; //for GRAY image only
p2 = (PPst2.y + h) * pIFrame2->widthStep + PPst2.x + w;
if ((p1>0) && (p1 < pIFrame1->imageSize) && (p2>0) && (p2<pIFrame2->imageSize))
{
*piResult += abs(pIFrame1->imageData[p1] - pIFrame2- >imageData[p2]); n++; } } } if (n>0) *piResult /= n;
else return E_INVALID;
return E_OK;
}
ER CopyImage(IplImage* pISrc, CvRect RArea, IplImage* pIDst, CvPoint PPst2) { int h, w, p1, p2, i; for (h = 0; h < RArea.height; h++) { for (w = 0; w < RArea.width; w++) {
for (i = 0; i < pISrc->nChannels; i++) {
p1 = (h + RArea.y) * pISrc->widthStep + (w + RArea.x) * pISrc->nChannels + i;
p2 = (h + PPst2.y) * pIDst->widthStep + (w + PPst2.x) * pIDst->nChannels + i;
if ((p2 < pIDst->imageSize) && (p1 < pISrc->imageSize)) pIDst->imageData[p2] = pISrc->imageData[p1]; } } } return E_OK; }
void show(char* name, int x, int y, IplImage* image, int resize) { if (image != NULL) { if (resize==1) { cvNamedWindow(name,0); cvResizeWindow(name, 320,240); } else cvNamedWindow(name,1); cvMoveWindow(name, x, y); cvShowImage(name, image);cvWaitKey(1); } }
double calcPSNR(const CvArr *a, const CvArr *b) { CvMat *x; CvMat *y; CvMat *z; double MSE; double PSNR; CvSize size; size = cvGetSize(a); x = cvCreateMat(size.height, size.width, CV_64F); y = cvCreateMat(size.height, size.width, CV_64F); z = cvCreateMat(size.height, size.width, CV_64F); cvScale(a, x); cvScale(b, y); cvSub(x, y, z); cvPow(z, z, 2.0);
MSE = cvSum(z).val[0] / double(size.width * size.height); PSNR = 10.0 * log10(255.0 * 255.0 / MSE); cvReleaseMat(&x); cvReleaseMat(&y); cvReleaseMat(&z); return PSNR; } File mci_conventional.cpp #include <stdio.h> #include <conio.h> #include "fruc.h" #include "common.h"
ER MCI_Conventional_forward(IplImage* pIFrame_curr, IplImage* pIFrame_prev, CvSize SBlock_size, CvSize SSearch_range, int iFrame_no_in, int
iFrame_no_out, IplImage** ppIFrame_intp) { float fMAD_mean; ER err; IplImage* pIFrame_curr_mv;
err = MotionVector(pIFrame_curr, pIFrame_prev, SBlock_size, SSearch_range,
&pIFrame_curr_mv, &fMAD_mean);
err = Interpolation_Conventional(pIFrame_prev, pIFrame_curr_mv, SBlock_size,
iFrame_no_in, iFrame_no_out, ppIFrame_intp);
return err;
}
ER Interpolation_Conventional(IplImage* pIFrame_prev, IplImage* pIFrame_prev_mv, CvSize SBlock_size,
IplImage** ppIFrame_intp) {
int h, w, mv_id;
*ppIFrame_intp = cvCreateImage(cvSize(pIFrame_prev->width,
pIFrame_prev->height), pIFrame_prev->depth, pIFrame_prev->nChannels); mv_id = 0; int p = 0; int delta_x = 0; int delta_y = 0; int prev_pst_x = 0; int prev_pst_y = 0; int intp_pst_x = 0; int intp_pst_y = 0;
/* block based processing */
for (h = 0; h <= (pIFrame_prev_mv)->height - SBlock_size.height; h += SBlock_size.height)
{
for (w = 0; w <= (pIFrame_prev_mv)->width - SBlock_size.width; w += SBlock_size.width)
{
p = h * pIFrame_prev_mv->widthStep + w * pIFrame_prev_mv- >nChannels;
delta_x = ((unsigned char*)pIFrame_prev_mv->imageData)[p] - 128;
delta_y = ((unsigned char*)pIFrame_prev_mv->imageData)[p+1] - 128;
prev_pst_x = w - delta_x; prev_pst_y = h - delta_y;
intp_pst_x = w - delta_x*iFrame_no_in/iFrame_no_out; intp_pst_y = h - delta_y*iFrame_no_in/iFrame_no_out; CopyImage(pIFrame_prev, cvRect(prev_pst_x, prev_pst_y, SBlock_size.width, SBlock_size.height),
(*ppIFrame_intp), cvPoint(intp_pst_x, intp_pst_y)); }
}
return E_OK;
}
/*
caculate the motion vectors of current image's block, consider previous image as reference
SSearch_range: search range SBlock_size: block size
--> search area is 2 * sr.height + bs.height
2 * sr.width + bs.width output is IplImage* pIFrame_curr_mv
*/
ER MotionVector(IplImage* pIFrame_curr, IplImage* pIFrame_prev, CvSize SBlock_size, CvSize SSearch_range,
IplImage** ppIFrame_curr_mv, float* pfMAD_mean) {
ER err;
CvPoint PPst; //position
int iMAD_min; // for calculating threshold for MAD
float sum_MAD = 0;
int no_blk = 0; CvRect RSearch_area;
//temp
IplImage* pIFrame_curr_mv = cvCreateImage(cvSize(pIFrame_curr->width, pIFrame_curr->height), IPL_DEPTH_8U, IMAGE_MV_NCHANNEL);
int i;
//checking input condition
if ((!pIFrame_prev) || (!pIFrame_curr)) return E_INVALID;
if (pIFrame_prev->imageSize != pIFrame_curr->imageSize) return
E_INVALID;
int p = 0;//pixel position //initialize pIFrame_curr_mv
for (h = 0; h < pIFrame_curr_mv->height; h++) {
for (w = 0; w < pIFrame_curr_mv->width; w ++) {
for (i = 0; i < pIFrame_curr_mv->nChannels; i++) {
p = h * pIFrame_curr_mv->widthStep + w * pIFrame_curr_mv- >nChannels;
pIFrame_curr_mv->imageData[p + i] = (unsigned char) 128;
//offset + 128 due to imageData type is unsigned char
} } }
/* Block based processing in current image */
for (h = 0; h <= pIFrame_curr->height - SBlock_size.height; h += SBlock_size.height)
{
for (w = 0; w <= pIFrame_curr->width - SBlock_size.width; w += SBlock_size.width)
{
/*calculate the position for input value of searching function*/ RSearch_area.x = w - SSearch_range.width; RSearch_area.y = h - SSearch_range.height; RSearch_area.width = 2*SSearch_range.width + SBlock_size.width; RSearch_area.height = 2*SSearch_range.height + SBlock_size.height; if (RSearch_area.x < 0) { RSearch_area.width = 2*SSearch_range.width + SBlock_size.width + RSearch_area.x; RSearch_area.x = 0; } if (RSearch_area.y < 0) { RSearch_area.height = 2*SSearch_range.height + SBlock_size.height + RSearch_area.y; RSearch_area.y = 0;
}
if ((RSearch_area.x + RSearch_area.width) > pIFrame_prev- >width)
RSearch_area.width = pIFrame_prev->width - RSearch_area.x;
if ((RSearch_area.y + RSearch_area.height) > pIFrame_prev- >height) RSearch_area.height = pIFrame_prev->height - RSearch_area.y; /* searching algorithm */ err = FullSearchBlockAlgorithm(pIFrame_curr, cvRect(w,h,SBlock_size.width, SBlock_size.height), pIFrame_prev, RSearch_area, &PPst, &iMAD_min, pfMAD_mean);
if (err != E_OK) return err; sum_MAD += *pfMAD_mean; no_blk ++; p = h * pIFrame_curr_mv->widthStep + w * pIFrame_curr_mv- >nChannels; pIFrame_curr_mv->imageData[p + 2] = iMAD_min; pIFrame_curr_mv->imageData[p] = 128 + w - PPst.x; //offset + 128 due to imageData type is unsigned char
pIFrame_curr_mv->imageData[p + 1] = 128 + h - PPst.y; } } #ifdef debug show("mv_MotionVector_debug", 0, 400, pIFrame_curr_mv); #endif *ppIFrame_curr_mv = pIFrame_curr_mv; #ifdef debug show("mv_MotionVector2_debug", 400, 400, *ppIFrame_curr_mv); #endif
*pfMAD_mean = sum_MAD / no_blk; printf("\n"); return E_OK; } File mci_bidirectional.cpp #include <stdio.h> #include <conio.h> #include "fruc.h" #include "common.h"
ER addR(IplImage* B, IplImage* dst, CvRect region, int factor);
ER Interpolation_bidirectional_OBMC(IplImage* pIFrame_curr, IplImage* pIFrame_prev,
IplImage* pIFrame_intp_mv, CvSize SBlock_size, CvSize SOverlapBlock_size,
int iFrame_no_in, int iFrame_no_out, IplImage** ppIFrame_intp);
ER Interpolation_bidirectional(IplImage* pIFrame_curr, IplImage* pIFrame_prev,
IplImage* pIFrame_intp_mv, CvSize SBlock_size,
IplImage** ppIFrame_intp);
ER LinearInterpolation(IplImage* pISrc1, CvPoint PPst1, IplImage* pISrc2, CvPoint PPst2, IplImage* pIDst, CvPoint PPst, CvSize SBlockSize);
ER refineMV(IplImage* pIFrame_curr, IplImage* pIFrame_prev, IplImage* mv, CvSize SBlock_size);
ER refineMV_block(IplImage* im1, CvRect area1, IplImage* im2, CvRect area2, CvSize block,
CvPoint* pPPst,
int* piMAD_min, float* pfMAD_mean);
ER displaceMV(IplImage* pIFrame_curr, IplImage* pIFrame_prev, IplImage* mv, CvSize SBlock_size, int iFrame_no_in, int iFrame_no_out);
ER MCI_BiDirectional(IplImage* pIFrame_curr, IplImage* pIFrame_prev, CvSize SBlock_size, CvSize SSearch_range, CvSize SOverlapBlock_size, int iFrame_no_in, int iFrame_no_out, IplImage** ppIFrame_intp)
{
float fMAD_mean;
ER err;
IplImage* pIFrame_curr_mv;
err = MotionVector(pIFrame_curr, pIFrame_prev, SBlock_size, SSearch_range,
&pIFrame_curr_mv, &fMAD_mean);
// refineMV(pIFrame_curr, pIFrame_prev, pIFrame_curr_mv, SBlock_size);
displaceMV(pIFrame_curr, pIFrame_prev, pIFrame_curr_mv, SBlock_size, iFrame_no_in, iFrame_no_out);
//for internal result (no OBMC)
//err = Interpolation_bidirectional(pIFrame_curr, pIFrame_prev, pIFrame_curr_mv,
// SBlock_size, iFrame_no_in, iFrame_no_out, ppIFrame_intp);
err = Interpolation_bidirectional_OBMC(pIFrame_curr, pIFrame_prev, pIFrame_curr_mv,
SBlock_size, SOverlapBlock_size, iFrame_no_in, iFrame_no_out, ppIFrame_intp);
return err;
}
ER Interpolation_bidirectional_OBMC(IplImage* pIFrame_curr, IplImage* pIFrame_prev, IplImage* pIFrame_intp_mv, CvSize SBlock_size, CvSize SOverlapBlock_size,int iFrame_no_in, int iFrame_no_out, IplImage** ppIFrame_intp)
{
int h, w, mv_id, i, p; mv_id = 0;
int delta_x = 0, delta_y = 0;
int curr_pst_x = 0, curr_pst_y = 0;
int prev_pst_x = 0, prev_pst_y = 0;
int h1, w1;
CvSize block_size;
*ppIFrame_intp = cvCreateImage(cvSize(pIFrame_prev->width,
pIFrame_prev->height), pIFrame_prev->depth, pIFrame_prev->nChannels);
for (h = 0; h < (*ppIFrame_intp)->height; h++) {
for (w = 0; w < (*ppIFrame_intp)->width; w ++) {
for (i = 0; i < (*ppIFrame_intp)->nChannels; i++) {
p = h * (*ppIFrame_intp)->widthStep + w * (*ppIFrame_intp)->nChannels;
(*ppIFrame_intp)->imageData[p + i] = (unsigned char) 0; }
} }
IplImage* B = cvCreateImage(cvSize(pIFrame_prev->width, pIFrame_prev- >height), pIFrame_prev->depth, pIFrame_prev->nChannels);
/* block based processing */
for (h = 0; h <= (*ppIFrame_intp)->height - SBlock_size.height; h += SBlock_size.height)
{
for (w = 0; w <= (*ppIFrame_intp)->width - SBlock_size.width; w += SBlock_size.width)
{
p = h * pIFrame_intp_mv->widthStep + w * pIFrame_intp_mv- >nChannels;
delta_x = ((unsigned char*)pIFrame_intp_mv->imageData)[p] - 128;
delta_y = ((unsigned char*)pIFrame_intp_mv->imageData)[p+1] - 128; curr_pst_x = w + delta_x*iFrame_no_in/iFrame_no_out; curr_pst_y = h + delta_y*iFrame_no_in/iFrame_no_out; prev_pst_x = w - delta_x*iFrame_no_in/iFrame_no_out; prev_pst_y = h - delta_y*iFrame_no_in/iFrame_no_out; //OBMC curr_pst_x -= SOverlapBlock_size.width; curr_pst_y -= SOverlapBlock_size.height; prev_pst_x -= SOverlapBlock_size.width; prev_pst_y -= SOverlapBlock_size.height; w1 = w - SOverlapBlock_size.width; h1 = h - SOverlapBlock_size.height; block_size.width = SBlock_size.width + 2*SOverlapBlock_size.width; block_size.height = SBlock_size.height + 2*SOverlapBlock_size.height; LinearInterpolation(pIFrame_curr, cvPoint(curr_pst_x,
curr_pst_y), pIFrame_prev, cvPoint(prev_pst_x, prev_pst_y), B, cvPoint(w1, h1), block_size);
//R1 region
CvRect R1;
R1.x = w + SOverlapBlock_size.width; R1.y = h + SOverlapBlock_size.height;
R1.width = SBlock_size.width - 2* SOverlapBlock_size.width; R1.height = SBlock_size.height - 2*SOverlapBlock_size.height; CopyImage(B,R1,*ppIFrame_intp,cvPoint(R1.x, R1.y));
//R2 regions
CvRect R2;
R2.x = w + SOverlapBlock_size.width; R2.y = h - SOverlapBlock_size.height;
R2.width = SBlock_size.width - 2*SOverlapBlock_size.width; R2.height = 2*SOverlapBlock_size.height;
addR(B, *ppIFrame_intp, R2, 2); R2.x = w - SOverlapBlock_size.width; R2.y = h + SOverlapBlock_size.height; R2.width = 2*SOverlapBlock_size.width;
R2.height = SBlock_size.height - 2*SOverlapBlock_size.height; addR(B, *ppIFrame_intp, R2, 2);
R2.x = w + SBlock_size.width - SOverlapBlock_size.width; R2.y = h + SOverlapBlock_size.height;
R2.width = 2*SOverlapBlock_size.width;
R2.height = SBlock_size.height - 2*SOverlapBlock_size.height; addR(B, *ppIFrame_intp, R2, 2);
R2.x = w + SOverlapBlock_size.width;
R2.y = h + SBlock_size.height - SOverlapBlock_size.height; R2.width = SBlock_size.width - 2*SOverlapBlock_size.width; R2.height = 2*SOverlapBlock_size.height; addR(B, *ppIFrame_intp, R2, 2); //R3 regions CvRect R3; R3.x = w - SOverlapBlock_size.width; R3.y = h - SOverlapBlock_size.height; R3.width = 2*SOverlapBlock_size.width; R3.height = 2*SOverlapBlock_size.height; addR(B, *ppIFrame_intp, R3, 4); R3.x = w + SBlock_size.width - SOverlapBlock_size.width; R3.y = h - SOverlapBlock_size.height; addR(B, *ppIFrame_intp, R3, 4); R3.x = w - SOverlapBlock_size.width;
R3.y = h + SBlock_size.height - SOverlapBlock_size.height; addR(B, *ppIFrame_intp, R3, 4);
R3.x = w + SBlock_size.width - SOverlapBlock_size.width; R3.y = h + SBlock_size.height - SOverlapBlock_size.height; addR(B, *ppIFrame_intp, R3, 4);
} }
return E_OK;
}
ER addR(IplImage* B, IplImage* dst, CvRect region, int factor) {
int w, h, p, i;
for (h = region.y; h < region.y+region.height; h++) {
for (w = region.x; w < region.x + region.width; w++) {
for (i = 0; i < dst->nChannels; i++) {
p = h * dst->widthStep + w * dst->nChannels + i;
dst->imageData [p] += (unsigned char)(((unsigned char)B->imageData[p])/factor); } } } return E_OK; }
//for internal result (no OBMC)
ER Interpolation_bidirectional(IplImage* pIFrame_curr, IplImage* pIFrame_prev,
IplImage* pIFrame_intp_mv, CvSize SBlock_size,
int iFrame_no_in, int iFrame_no_out, IplImage** ppIFrame_intp)
{
int h, w, mv_id;
*ppIFrame_intp = cvCreateImage(cvSize(pIFrame_prev->width,
pIFrame_prev->height), pIFrame_prev->depth, pIFrame_prev->nChannels); mv_id = 0;
int p = 0;
int delta_x = 0, delta_y = 0;
int curr_pst_x = 0, curr_pst_y = 0;
int prev_pst_x = 0, prev_pst_y = 0;
/* block based processing */
for (h = 0; h <= (*ppIFrame_intp)->height - SBlock_size.height; h += SBlock_size.height)
{
for (w = 0; w <= (*ppIFrame_intp)->width - SBlock_size.width; w += SBlock_size.width)
{
p = h * pIFrame_intp_mv->widthStep + w * pIFrame_intp_mv- >nChannels;
delta_x = ((unsigned char*)pIFrame_intp_mv->imageData)[p] - 128;
delta_y = ((unsigned char*)pIFrame_intp_mv->imageData)[p+1] - 128; curr_pst_x = w + delta_x*iFrame_no_in/iFrame_no_out; curr_pst_y = h + delta_y*iFrame_no_in/iFrame_no_out; prev_pst_x = w - delta_x*iFrame_no_in/iFrame_no_out; prev_pst_y = h - delta_y*iFrame_no_in/iFrame_no_out; LinearInterpolation(pIFrame_curr, cvPoint(curr_pst_x,
curr_pst_y), pIFrame_prev, cvPoint(prev_pst_x, prev_pst_y), *ppIFrame_intp, cvPoint(w, h), SBlock_size);
} }
return E_OK;
}
ER LinearInterpolation(IplImage* pISrc1, CvPoint PPst1, IplImage* pISrc2, CvPoint PPst2, IplImage* pIDst, CvPoint PPst, CvSize SBlockSize)
{
int a;
for (h = 0; h < SBlockSize.height; h++) {