7 #include "../src/img.h"
8 #include <opencv2/core/core_c.h>
9 #include <opencv2/imgproc/imgproc_c.h>
10 #include <opencv2/video/tracking.hpp>
11 #include<opencv2/highgui/highgui.hpp>
13 /* test single flow without smoothing */
16 /* test input image */
19 int flow_window = 30, border = 0;
20 double limit_frames = 0;
21 int interlace = 0, swap = 0;
23 static void field_img(int width, int height, unsigned short *img, int odd)
28 /* use even lines: 0, 2, 4... */
29 /* use odd lines: 1, 3, 5... */
30 for (y = (!!odd); y < height-2; y += 2) {
31 for (x = 0; x < width*3; x++) {
32 value = img[width * y * 3 + x];
33 value += img[width * (y+2) * 3 + x];
34 img[width * (y+1) * 3 + x] = (value >> 1);
37 /* duplicate border line that can't be interpolated */
39 memcpy(img + width * (height-1) * 3, img + width * (height-2) * 3, width * 3 * sizeof(unsigned short));
41 memcpy(img, img + width * 3, width * 3 * sizeof(unsigned short));
44 static inline void smooth_pixle(double *array, int width, int height, int i, int j)
50 val += array[i*width+j-1-width];
55 val += array[i*width+j-width];
59 if (i > 0 && j < width-1) {
60 val += array[i*width+j+1-width];
65 val += array[i*width+j-1];
70 val += array[i*width+j+1];
74 if (i < height-1 && j > 0) {
75 val += array[i*width+j-1+width];
80 val += array[i*width+j+width];
84 if (i < height-1 && j < width-1) {
85 val += array[i*width+j+1+width];
89 array[i*width+j] = val/num;
92 /* interpolate missing pixles in array */
93 static void smooth(double *array, double *mask, int width, int height)
97 for (iter = 0; iter < 3; iter++) {
98 for (i = 0; i < height; i++) {
99 for (j = 0; j < width; j++) {
102 smooth_pixle(array, width, height, i, j);
105 for (i = height-1; i >= 0; i--) {
106 for (j = width-1; j >= 0; j--) {
109 smooth_pixle(array, width, height, i, j);
115 /* use optical flow to interpolate two images with given offset */
116 static int interpolate(unsigned short *img1, unsigned short *img2, unsigned short *res, int width, int height, double offset, int frame)
118 static int lastframe = -1;
119 static CvMat *flow1 = NULL, *flow2 = NULL;
120 static IplImage *image1, *image2;
121 double *array1, *array2;
124 unsigned short *i1, *i2;
128 const float pyrScale = 0.5;
129 const float levels = 3;
130 const float winsize = flow_window;
131 const float iterations = 8;
132 const float polyN = 5;
133 const float polySigma = 1.2;
136 if (lastframe != frame && flow1) {
137 cvReleaseMat(&flow1);
140 if (lastframe != frame && flow2) {
141 cvReleaseMat(&flow2);
146 array1 = calloc(width*height*5*sizeof(*array1), 1);
147 array2 = calloc(width*height*5*sizeof(*array2), 1);
148 if (!array1 || !array2) {
149 printf("Failed to create image array\n");
153 /* if we need to make flow maps, we do it */
154 if (!flow1 || !flow2) {
155 printf(" -> calculating flow %d<->%d\n", frame, frame+1);
156 flow1 = cvCreateMat(height, width, CV_32FC2);
157 flow2 = cvCreateMat(height, width, CV_32FC2);
158 if (!flow1 || !flow2) {
159 printf("Failed to create flow map\n");
164 size.height = height;
165 // image1 = cvCreateImage(size, IPL_DEPTH_32F, 1);
166 // image2 = cvCreateImage(size, IPL_DEPTH_32F, 1);
167 image1 = cvCreateImage(size, IPL_DEPTH_16U, 1);
168 image2 = cvCreateImage(size, IPL_DEPTH_16U, 1);
169 if (!image1 || !image2) {
170 printf("Failed to create image for optical flow\n");
175 for (i = 0; i < height; i++) {
176 for (j = 0; j < width; j++) {
180 // CV_IMAGE_ELEM(image1, float, i, j) = grey / 76;
181 CV_IMAGE_ELEM(image1, ushort, i, j) = grey / 3;
185 // CV_IMAGE_ELEM(image2, float, i, j) = grey / 76;
186 CV_IMAGE_ELEM(image2, ushort, i, j) = grey / 3;
190 cvNamedWindow( "Image1", 0 );// Create a window for display.
191 cvShowImage( "Image1", image1); // Show our image inside it.
192 cvNamedWindow( "Image2", 0 );// Create a window for display.
193 cvShowImage( "Image2", image2); // Show our image inside it.
197 cvCalcOpticalFlowFarneback(image1, image2, flow1, pyrScale, levels, winsize, iterations, polyN, polySigma, flags);
198 cvCalcOpticalFlowFarneback(image2, image1, flow2, pyrScale, levels, winsize, iterations, polyN, polySigma, flags);
201 cvReleaseImage(&image1);
202 cvReleaseImage(&image2);
206 /* apply image to array using flow map */
207 for (i = 0; i < height; i++) {
208 f = (const float *)(flow1->data.ptr + flow1->step * i);
209 for (j = 0; j < width; j++) {
210 x = j + round(*f++ * offset);
211 y = i + round(*f++ * offset);
212 if (j < border || i < border || j >= width-border || i >= height-border)
214 if (x < 0 || x >= width || y < 0 || y >= height)
216 array1[y*width+x] += (double)img1[(i*width+j)*3+0] / 65535;
217 array1[y*width+x + width*height] += (double)img1[(i*width+j)*3+1] / 65535;
218 array1[y*width+x + width*height*2] += (double)img1[(i*width+j)*3+2] / 65535;
219 array1[y*width+x + width*height*3] += 1.0;
222 for (i = 0; i < height; i++) {
223 f = (const float *)(flow2->data.ptr + flow2->step * i);
224 for (j = 0; j < width; j++) {
225 x = j + round(*f++ * (1-offset));
226 y = i + round(*f++ * (1-offset));
227 if (j < border || i < border || j >= width-border || i >= height-border)
229 if (x < 0 || x >= width || y < 0 || y >= height)
231 array2[y*width+x] += (double)img2[(i*width+j)*3+0] / 65535;
232 array2[y*width+x + width*height] += (double)img2[(i*width+j)*3+1] / 65535;
233 array2[y*width+x + width*height*2] += (double)img2[(i*width+j)*3+2] / 65535;
234 array2[y*width+x + width*height*3] += 1.0;
238 /* mask unset pixles */
239 for (i = 0; i < height; i++) {
240 for (j = 0; j < width; j++) {
241 alpha = array1[i*width+j + width*height*3];
243 array1[i*width+j] = 0.0;
244 array1[i*width+j + width*height] = 0.0;
245 array1[i*width+j + width*height*2] = 0.0;
246 array1[i*width+j + width*height*3] = 0.0;
248 array1[i*width+j + width*height*4] = 1.0;
250 alpha = array2[i*width+j + width*height*3];
252 array2[i*width+j] = 0.0;
253 array2[i*width+j + width*height] = 0.0;
254 array2[i*width+j + width*height*2] = 0.0;
255 array2[i*width+j + width*height*3] = 0.0;
257 array2[i*width+j + width*height*4] = 1.0;
263 /* smooth image by interpolating missing (masked) pixles */
264 smooth(array1, array1+width*height*4, width, height);
265 smooth(array1+width*height, array1+width*height*4, width, height);
266 smooth(array1+width*height*2, array1+width*height*4, width, height);
267 smooth(array1+width*height*3, array1+width*height*4, width, height);
268 smooth(array2, array2+width*height*4, width, height);
269 smooth(array2+width*height, array2+width*height*4, width, height);
270 smooth(array2+width*height*2, array2+width*height*4, width, height);
271 smooth(array2+width*height*3, array2+width*height*4, width, height);
274 /* normalize smoothed image and compose */
275 for (i = 0; i < height; i++) {
276 for (j = 0; j < width; j++) {
277 alpha = array1[i*width+j + width*height*3];
279 array1[i*width+j] /= alpha;
280 array1[i*width+j + width*height] /= alpha;
281 array1[i*width+j + width*height*2] /= alpha;
282 array1[i*width+j + width*height*3] = 1.0;
284 alpha = array2[i*width+j + width*height*3];
286 array2[i*width+j] /= alpha;
287 array2[i*width+j + width*height] /= alpha;
288 array2[i*width+j + width*height*2] /= alpha;
289 array2[i*width+j + width*height*3] = 1.0;
292 array1[i*width+j] = (1.0-offset)*array1[i*width+j] + offset*array2[i*width+j];
293 array1[i*width+j + width*height] = (1.0-offset)*array1[i*width+j + width*height] + offset*array2[i*width+j + width*height];
294 array1[i*width+j + width*height*2] = (1.0-offset)*array1[i*width+j + width*height*2] + offset*array2[i*width+j + width*height*2];
297 if (i < (height>>1)) {
298 array1[i*width+j] = (double)CV_IMAGE_ELEM(image2, ushort, i, j) / 65535;
299 array1[i*width+j + width*height] = (double)CV_IMAGE_ELEM(image1, ushort, i, j) / 65535;
300 array1[i*width+j + width*height*2] = 0;
306 array2img_short(array1, width, height, res, width, height, 0);
314 static void print_help(const char *app)
316 printf("This tool will change frame rate using optical flow and interpolation.\n");
317 printf("Usage: %s [options] <input> <first> <output> <first> <oldfps> <newfps>\n", app);
318 printf(" -h --help This help\n");
319 printf(" -d --depth <bits> Change color depth from default %d to given bits\n", save_depth);
320 printf(" -b --border <pixles> Remove border pixles, if darker than image (try 1)\n");
321 printf(" -w --window <size> Change optical flow window size (default %d)\n", flow_window);
322 printf(" -f --frames <number> Limit number of input frames (default infinite)\n");
323 printf(" -i --interlace Handle input image as interlaced image\n");
324 printf(" Note: oldfps refers to frames, not the individual fields\n");
325 printf(" -e --even Use even lines for first field, instead of odd lines\n");
326 printf(" input Input image sequence (e.g. input_%%05d.ppm)\n");
327 printf(" output Output image sequence (e.g. output_%%05d.ppm)\n");
328 printf(" first Index of first input and output image\n");
329 printf(" oldfps Old frame rate (complete frames in case of interlace)\n");
330 printf(" newfps New frame rate\n");
333 static int handle_options(int argc, char **argv)
338 int option_index = 0, c;
339 static struct option long_options[] = {
341 {"depth", 1, 0, 'd'},
342 {"border", 1, 0, 'b'},
343 {"window", 1, 0, 'w'},
344 {"frames", 1, 0, 'f'},
345 {"interlace", 0, 0, 'i'},
350 c = getopt_long(argc, argv, "hd:b:w:f:ie", long_options, &option_index);
360 save_depth = atoi(optarg);
364 border = atoi(optarg);
368 flow_window = atoi(optarg);
372 limit_frames = atoi(optarg);
391 int main(int argc, char *argv[])
393 unsigned short *img1 = NULL, *img2 = NULL, *res = NULL;
394 int width, height, width2, height2;
395 const char *inputname, *outputname;
396 double oldfps, newfps, step, inputframe, baseframe, offset;
399 const char *app_name = argv[0];
402 skip_args = handle_options(argc, argv);
403 argc -= skip_args + 1;
404 argv += skip_args + 1;
407 print_help(app_name);
412 inputframe = atoi(argv[1]);
413 outputname = argv[2];
414 outputframe = atoi(argv[3]);
415 oldfps = strtod(argv[4], NULL);
416 newfps = strtod(argv[5], NULL);
418 step = oldfps / newfps;
419 printf("Time Scale Factor: %.4f\n", step);
420 printf("Optical Flow window: %d\n", flow_window);
422 printf("Limit number of input frames: %.0f\n", limit_frames);
425 baseframe = floor(inputframe);
426 offset = inputframe - baseframe;
429 else if (interlace && offset < 0.501 && offset > 0.499)
431 else if (offset > 0.999) {
435 if (offset == 0.0 || (interlace && offset == 0.5)) {
438 printf("Copy input frame %d (first field), output frame %d\n", (int)baseframe, outputframe);
440 printf("Copy input frame %d (second field), output frame %d\n", (int)baseframe, outputframe);
442 printf("Copy input frame %d, output frame %d\n", (int)baseframe, outputframe);
443 res = load_img(&width, &height, inputname, baseframe);
448 field_img(width, height, res, (!swap)); // first field
450 field_img(width, height, res, swap); // second field
452 rc = save_img(res, width, height, 0, outputname, outputframe);
456 printf("Processing input frame %.4f, output frame %d\n", inputframe, outputframe);
457 img1 = load_img(&width, &height, inputname, baseframe);
460 if (interlace && offset < 0.5) {
461 field_img(width, height, img1, (!swap)); // first field of baseframe
462 img2 = load_img(&width2, &height2, inputname, baseframe);
465 field_img(width2, height2, img2, swap); // second field of baseframe
467 img2 = load_img(&width2, &height2, inputname, baseframe+1);
471 field_img(width, height, img1, swap); // second field of baseframe
472 field_img(width2, height2, img2, (!swap)); // first field of baseframe+1
475 if (width != width2) {
476 printf("Frame %d and %d have different width (%d != %d)\n", (int)baseframe, (int)baseframe+1, width, width2);
479 if (height != height2) {
480 printf("Frame %d and %d have different height (%d != %d)\n", (int)baseframe, (int)baseframe+1, height, height2);
483 if (interlace && (height & 1)) {
484 printf("Interlaced frame %d must have even number of lines (not %d)\n", (int)baseframe, height);
487 res = malloc(width * height * 3 * sizeof(unsigned short));
492 rc = interpolate(img1, img2, res, width, height, offset * 2.0, ((int)baseframe) * 2);
494 rc = interpolate(img1, img2, res, width, height, (offset * 2.0) - 1.0, ((int)baseframe) * 2 + 1);
496 rc = interpolate(img1, img2, res, width, height, offset, (int)baseframe);
499 rc = save_img(res, width, height, 0, outputname, outputframe);
514 limit_frames -= step;
515 if (limit_frames <= 0)
521 printf("We end here, since there is no more image to process\n");