]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7515: add opaque container for png to pass around and save width and height
authorAnthony Minessale <anthm@freeswitch.org>
Fri, 10 Apr 2015 21:39:03 +0000 (16:39 -0500)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:47:19 +0000 (12:47 -0500)
src/include/switch_core_video.h
src/mod/applications/mod_cv/mod_cv.cpp
src/switch_core_video.c

index b9b20b8b3e2d685ae2847e6570dbc4807649c165..3a42f3fe629e96e4dd8492abdb55741c6d4071aa 100644 (file)
@@ -82,6 +82,16 @@ typedef enum {
        SWITCH_CONVERT_FMT_YUYV = 0
 } switch_convert_fmt_t;
 
+struct switch_png_opaque_s;
+typedef struct switch_png_opaque_s switch_png_opaque_t;
+typedef struct switch_png_s {
+       switch_png_opaque_t *pvt;
+       int w;
+       int h;
+} switch_png_t;
+
+
+
 /*!\brief Open a descriptor, allocating storage for the underlying image
 *
 * Returns a descriptor for storing an image of the given format. The
@@ -211,9 +221,12 @@ SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_render(switch_img_txt_hand
 
 
 SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_image_rect_t *rect);
-SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name);
-SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char* file_name);
-SWITCH_DECLARE(switch_status_t) switch_img_patch_png(switch_image_t *img, int x, int y, const char *file_name);
+
+SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, switch_image_t *img, int x, int y);
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char *file_name);
+SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char *file_name);
+SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char *file_name);
+SWITCH_DECLARE(void) switch_png_free(switch_png_t **pngP);
 
 SWITCH_DECLARE(void) switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_color_t *yuv, int x, int y);
 
index cec59f1f024a34c71c5dce3aea26bbffca8beba5..b0804e2e293e40ad10c6519d6c0f5bc04b900bb0 100644 (file)
@@ -65,6 +65,20 @@ struct detect_stats {
     float avg;
 };
 
+struct shape {
+    int x;
+    int y;
+    int x2;
+    int y2;
+    int w;
+    int h;
+    int cx;
+    int cy;
+    int radius;
+};
+
+#define MAX_SHAPES 32
+
 typedef struct cv_context_s {
     CvBGCodeBookModel* model;
     bool ch[NCHANNELS];
@@ -81,6 +95,11 @@ typedef struct cv_context_s {
     struct detect_stats nestDetected;
     int detect_event;
     int nest_detect_event;
+    switch_png_t *png;
+    struct shape shape[MAX_SHAPES];
+    int shapeidx;
+    int x_off;
+    int y_off;
 } cv_context_t;
 
 
@@ -99,9 +118,13 @@ static void uninit_context(cv_context_t *context)
     if (context->nestedCascade) {
         delete context->nestedCascade;
     }
+
+    if (context->png) {
+        switch_png_free(&context->png);
+    }
 }
 
-static void init_context(cv_context_t *context, const char *cascade_name, const char *nested_cascade_name)
+static void init_context(cv_context_t *context, const char *cascade_name, const char *nested_cascade_name, int x_off, int y_off)
 {
     for (int i = 0; i < NCHANNELS; i++) {
         context->ch[i] = true;
@@ -112,8 +135,14 @@ static void init_context(cv_context_t *context, const char *cascade_name, const
         context->cascade->load(cascade_name);
 
         if (nested_cascade_name) {
-            context->nestedCascade = new CascadeClassifier;
-            context->nestedCascade->load(nested_cascade_name);
+            if (switch_stristr(".png", nested_cascade_name)) {
+                switch_png_open(&context->png, nested_cascade_name);
+                context->x_off = x_off;
+                context->y_off = y_off;
+            } else {
+                context->nestedCascade = new CascadeClassifier;
+                context->nestedCascade->load(nested_cascade_name);
+            }
         }
     } else {
         context->model = cvCreateBGCodeBookModel();
@@ -207,6 +236,9 @@ void detectAndDraw(cv_context_t *context)
     parse_stats(&context->detected, detectedObjs.size());
 
     //printf("SCORE: %d %f %d\n", context->detected.simo_count, context->detected.avg, context->detected.last_score);
+    
+    context->shapeidx = 0;
+    memset(context->shape, 0, sizeof(context->shape[0]) * MAX_SHAPES);
 
     for( vector<Rect>::iterator r = detectedObjs.begin(); r != detectedObjs.end(); r++, i++ ) {
         Mat smallImgROI;
@@ -214,17 +246,46 @@ void detectAndDraw(cv_context_t *context)
         Point center;
         Scalar color = colors[i%8];
         int radius;
-
+        
         double aspect_ratio = (double)r->width/r->height;
+
+        if (context->shapeidx >= MAX_SHAPES) {
+            break;
+        }
+        
         if(0.75 < aspect_ratio && aspect_ratio < 1.3 ) {
             center.x = cvRound((r->x + r->width*0.5)*scale);
             center.y = cvRound((r->y + r->height*0.5)*scale);
             radius = cvRound((r->width + r->height)*0.25*scale);
-            circle( img, center, radius, color, 3, 8, 0 );
+
+            if (!context->png) {
+                circle( img, center, radius, color, 3, 8, 0 );
+            }
+
+            context->shape[context->shapeidx].x = center.x - radius;
+            context->shape[context->shapeidx].y = center.y - radius;
+            context->shape[context->shapeidx].cx = center.x;
+            context->shape[context->shapeidx].cy = center.y;
+            context->shape[context->shapeidx].radius = radius;
+            context->shapeidx++;
+
         } else {
-            rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)),
-                       cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),
-                       color, 3, 8, 0);
+            context->shape[context->shapeidx].x = cvRound(r->x*scale);
+            context->shape[context->shapeidx].y = cvRound(r->y*scale);
+            context->shape[context->shapeidx].x2 = cvRound((r->x + r->width-1)*scale);
+            context->shape[context->shapeidx].y2 = cvRound((r->y + r->height-1)*scale);
+            context->shape[context->shapeidx].w = context->shape[context->shapeidx].x2 - context->shape[context->shapeidx].x;
+            context->shape[context->shapeidx].h = context->shape[context->shapeidx].y2 - context->shape[context->shapeidx].y;
+            context->shape[context->shapeidx].cx = context->shape[context->shapeidx].x + (context->shape[context->shapeidx].w / 2);
+            context->shape[context->shapeidx].cy = context->shape[context->shapeidx].y + (context->shape[context->shapeidx].h / 2);
+            
+            if (!context->png) {
+                rectangle( img, cvPoint(context->shape[context->shapeidx].x, context->shape[context->shapeidx].y),
+                           cvPoint(context->shape[context->shapeidx].x2, context->shape[context->shapeidx].y2),
+                           color, 3, 8, 0);
+            }
+
+            context->shapeidx++;
         }
 
         if(!context->nestedCascade || context->nestedCascade->empty() ) {
@@ -538,12 +599,21 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
         int w = context->rawImage->width;
         int h = context->rawImage->height;
 
-        libyuv::RGB24ToI420((uint8_t *)context->rawImage->imageData, w * 3,
-                            frame->img->planes[0], frame->img->stride[0],
-                            frame->img->planes[1], frame->img->stride[1],
-                            frame->img->planes[2], frame->img->stride[2],
-                            context->rawImage->width, context->rawImage->height);
-                            
+        if (context->png && context->shapeidx && context->shape[0].x) {
+            int x = 0, y = 0;
+
+            x = context->shape[0].cx - (context->png->w / 2) + context->x_off;
+            y = context->shape[0].cy - (context->png->h / 2) + context->y_off;
+
+            switch_png_patch_img(context->png, frame->img, x, y);
+        } else {
+            libyuv::RGB24ToI420((uint8_t *)context->rawImage->imageData, w * 3,
+                                frame->img->planes[0], frame->img->stride[0],
+                                frame->img->planes[1], frame->img->stride[1],
+                                frame->img->planes[2], frame->img->stride[2],
+                                context->rawImage->width, context->rawImage->height);
+        }
+        
     }
 
     return SWITCH_STATUS_SUCCESS;
@@ -560,15 +630,23 @@ SWITCH_STANDARD_APP(cv_start_function)
     char *nested_cascade_name;
        char *argv[6];
        int argc;
-    
+    int x_off = 0, y_off = 0;
 
        if (data && (lbuf = switch_core_session_strdup(session, data))
                && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
         cascade_name = argv[0];
         nested_cascade_name = argv[1];
+
+        if (argv[2]) {
+            x_off = atoi(argv[2]);
+        }
+
+        if (argv[3]) {
+            y_off = atoi(argv[3]);
+        }
     }
 
-    init_context(&context, cascade_name, nested_cascade_name);
+    init_context(&context, cascade_name, nested_cascade_name, x_off, y_off);
     
     switch_channel_answer(channel);
     switch_channel_set_flag_recursive(channel, CF_VIDEO_DECODED_READ);
@@ -607,6 +685,8 @@ struct cv_bug_helper {
     cv_context_t context;
     char *cascade_name;
     char *nested_cascade_name;
+    int x_off;
+    int y_off;
 };
 
 static switch_bool_t cv_bug_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
@@ -618,7 +698,7 @@ static switch_bool_t cv_bug_callback(switch_media_bug_t *bug, void *user_data, s
        case SWITCH_ABC_TYPE_INIT:
                {
             switch_channel_set_flag_recursive(channel, CF_VIDEO_DECODED_READ);
-            init_context(&cvh->context, cvh->cascade_name, cvh->nested_cascade_name);
+            init_context(&cvh->context, cvh->cascade_name, cvh->nested_cascade_name, cvh->x_off, cvh->y_off);
                }
                break;
        case SWITCH_ABC_TYPE_CLOSE:
@@ -670,6 +750,15 @@ SWITCH_STANDARD_APP(cv_bug_start_function)
                && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
         cascade_name = argv[1];
         nested_cascade_name = argv[2];
+
+        if (argv[3]) {
+            cvh->x_off = atoi(argv[3]);
+        }
+
+        if (argv[4]) {
+            cvh->y_off = atoi(argv[4]);
+        }
+
     }
 
        cvh->session = session;
index ed9b918fe0642f73fa77e0da1ec524d5d8bf64e2..b2945ba26c65f634ba7e294396f2dff556bee54b 100644 (file)
@@ -739,59 +739,121 @@ SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t *
 #define PNG_SKIP_SETJMP_CHECK
 #include <png.h>
 
+
 #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* available from libpng 1.6.0 */
 
-SWITCH_DECLARE(switch_status_t) switch_img_patch_png(switch_image_t *img, int x, int y, const char *file_name)
+struct switch_png_opaque_s {
+       png_image png;
+       png_bytep buffer;       
+};
+
+
+
+SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char *file_name)
 {
-       png_image png = { 0 };
-       png_bytep buffer = NULL;
+       switch_png_t *use_png;
        switch_status_t status = SWITCH_STATUS_SUCCESS;
-       switch_rgb_color_t *rgb_color;
-       switch_yuv_color_t yuv_color;
-       uint8_t alpha;
-       int i, j;
 
-       png.version = PNG_IMAGE_VERSION;
+       switch_zmalloc(use_png, sizeof(*use_png));
+       switch_zmalloc(use_png->pvt, sizeof(struct switch_png_opaque_s));
+       use_png->pvt->png.version = PNG_IMAGE_VERSION;
+               
+       if (!png_image_begin_read_from_file(&use_png->pvt->png, file_name)) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read PNG %s\n", file_name);
+               switch_goto_status(SWITCH_STATUS_FALSE, end);
+       }
+               
+       use_png->pvt->png.format = PNG_FORMAT_RGBA;
 
-       if (!png_image_begin_read_from_file(&png, file_name)) {
+       use_png->pvt->buffer = malloc(PNG_IMAGE_SIZE(use_png->pvt->png));
+       switch_assert(use_png->pvt->buffer);
+
+       if (!png_image_finish_read(&use_png->pvt->png, NULL/*background*/, use_png->pvt->buffer, 0, NULL)) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read PNG %s\n", file_name);
                switch_goto_status(SWITCH_STATUS_FALSE, end);
        }
 
-       // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "png format: %d, size: %dx%d\n", png.format, png.width, png.height);
-       // if (png.format | PNG_FORMAT_FLAG_ALPHA) {
-       //      printf("Alpha\n");
-       // }
 
-       png.format = PNG_FORMAT_RGBA;
+       use_png->w = use_png->pvt->png.width;
+       use_png->h = use_png->pvt->png.height;
 
-       buffer = malloc(PNG_IMAGE_SIZE(png));
-       switch_assert(buffer);
+end:
 
-       if (!png_image_finish_read(&png, NULL/*background*/, buffer, 0, NULL)) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read PNG %s\n", file_name);
-               switch_goto_status(SWITCH_STATUS_FALSE, end);
+       if (status == SWITCH_STATUS_SUCCESS) {
+               *pngP = use_png;
+       } else {
+               switch_png_free(&use_png);
+               *pngP = NULL;
        }
 
-       for (i = 0; i < png.height; i++) {
-               for (j = 0; j < png.width; j++) {
-                       alpha = buffer[i * png.width * 4 + j * 4 + 3];
+       return status;
+}
+
+SWITCH_DECLARE(void) switch_png_free(switch_png_t **pngP)
+{
+       switch_png_t *use_png;
+
+       if (pngP) {
+               use_png = *pngP;
+               *pngP = NULL;
+               png_image_free(&use_png->pvt->png);
+               switch_safe_free(use_png->pvt->buffer);
+               switch_safe_free(use_png->pvt);
+               switch_safe_free(use_png);
+       }
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, switch_image_t *img, int x, int y)
+{
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+       switch_rgb_color_t *rgb_color;
+       switch_yuv_color_t yuv_color;
+       uint8_t alpha;
+       int i, j;
+       
+       switch_assert(use_png);
+
+       for (i = 0; i < use_png->pvt->png.height; i++) {
+               for (j = 0; j < use_png->pvt->png.width; j++) {
+                       alpha = use_png->pvt->buffer[i * use_png->pvt->png.width * 4 + j * 4 + 3];
                        // printf("%d, %d alpha: %d\n", j, i, alpha);
 
                        if (alpha) { // todo, mux alpha with the underlying pixel
-                               rgb_color = (switch_rgb_color_t *)(buffer + i * png.width * 4 + j * 4);
+                               rgb_color = (switch_rgb_color_t *)(use_png->pvt->buffer + i * use_png->pvt->png.width * 4 + j * 4);
                                switch_color_rgb2yuv(rgb_color, &yuv_color);
-                               switch_img_draw_pixel(img, x + j, i, &yuv_color);
+                               switch_img_draw_pixel(img, x + j, y + i, &yuv_color);
                        }
                }
        }
 
-end:
-       png_image_free(&png);
-       switch_safe_free(buffer);
        return status;
 }
 
+#else /* libpng < 1.6.0 */
+
+SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char *file_name)
+{
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT IMPLEMENTED\n");
+       return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_DECLARE(void) switch_png_free(switch_png_t **pngP) 
+{
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT IMPLEMENTED\n");
+}
+
+SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, switch_image_t *img, int x, int y) 
+{
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT IMPLEMENTED\n");
+       return SWITCH_STATUS_FALSE;
+}
+
+#endif
+
+
+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* available from libpng 1.6.0 */
+
 SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name)
 {
        png_image png = { 0 };
@@ -836,12 +898,6 @@ err:
 
 #else /* libpng < 1.6.0 */
 
-SWITCH_DECLARE(switch_status_t) switch_img_patch_png(switch_image_t *img, int x, int y, const char *file_name)
-{
-       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This function is not implemented on libpng < 1.6.0\n");
-       return SWITCH_STATUS_FALSE;
-}
-
 // ref: most are out-dated, man libpng :)
 // http://zarb.org/~gc/html/libpng.html
 // http://www.libpng.org/pub/png/book/toc.html