02c995d5d6638d2bc0f97f465b01d1a7f4f5b32c
[platform/upstream/gstreamer.git] / ext / opencv / gstcvsmooth.cpp
1 /*
2  * GStreamer
3  * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Alternatively, the contents of this file may be used under the
24  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
25  * which case the following provisions apply instead of the ones
26  * mentioned above:
27  *
28  * This library is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU Library General Public
30  * License as published by the Free Software Foundation; either
31  * version 2 of the License, or (at your option) any later version.
32  *
33  * This library is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36  * Library General Public License for more details.
37  *
38  * You should have received a copy of the GNU Library General Public
39  * License along with this library; if not, write to the
40  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
41  * Boston, MA 02110-1301, USA.
42  */
43
44 /**
45  * SECTION:element-cvsmooth
46  *
47  * Smooths the image using thes cvSmooth OpenCV function.
48  *
49  * ## Example launch line
50  *
51  * |[
52  * gst-launch-1.0 videotestsrc ! cvsmooth ! videoconvert ! autovideosink
53  * ]|
54  */
55
56 #ifdef HAVE_CONFIG_H
57 #  include <config.h>
58 #endif
59
60 #include "gst/opencv/gstopencvutils.h"
61 #include "gstcvsmooth.h"
62 #include <opencv2/imgproc.hpp>
63
64
65 GST_DEBUG_CATEGORY_STATIC (gst_cv_smooth_debug);
66 #define GST_CAT_DEFAULT gst_cv_smooth_debug
67
68 using namespace cv;
69 /* Filter signals and args */
70 enum
71 {
72   /* FILL ME */
73   LAST_SIGNAL
74 };
75 enum
76 {
77   PROP_0,
78   PROP_SMOOTH_TYPE,
79   PROP_KERNELWIDTH,
80   PROP_KERNELHEIGHT,
81   PROP_COLORSIGMA,
82   PROP_SPATIALSIGMA,
83   PROP_POSITION_X,
84   PROP_POSITION_Y,
85   PROP_WIDTH,
86   PROP_HEIGHT
87 };
88
89 /* blur-no-scale only handle: gray 8bits -> gray 16bits
90  * FIXME there is no way in base transform to override pad's getcaps
91  * to be property-sensitive, instead of using the template caps as
92  * the base caps, this might lead us to negotiating rgb in this
93  * smooth type.
94  *
95  * Keep it deactivated for now.
96  */
97
98 enum GstCvSmoothMethod
99 {
100   GST_SMOOTH_BLUR = 1,
101   GST_SMOOTH_GAUSSIAN = 2,
102   GST_SMOOTH_MEDIAN = 3,
103   GST_SMOOTH_BILATERAL = 4
104 };
105
106
107 #define GST_TYPE_CV_SMOOTH_TYPE (gst_cv_smooth_type_get_type ())
108 static GType
109 gst_cv_smooth_type_get_type (void)
110 {
111   static GType cv_smooth_type_type = 0;
112
113   static const GEnumValue smooth_types[] = {
114     {GST_SMOOTH_BLUR, "CV Blur", "blur"},
115     {GST_SMOOTH_GAUSSIAN, "CV Gaussian", "gaussian"},
116     {GST_SMOOTH_MEDIAN, "CV Median", "median"},
117     {GST_SMOOTH_BILATERAL, "CV Bilateral", "bilateral"},
118     {0, NULL, NULL},
119   };
120
121   if (!cv_smooth_type_type) {
122     cv_smooth_type_type =
123         g_enum_register_static ("GstCvSmoothTypeType", smooth_types);
124   }
125   return cv_smooth_type_type;
126 }
127
128 #define DEFAULT_CV_SMOOTH_TYPE GST_SMOOTH_GAUSSIAN
129 #define DEFAULT_KERNELWIDTH 3
130 #define DEFAULT_KERNELHEIGHT 3
131 #define DEFAULT_COLORSIGMA 0.0
132 #define DEFAULT_SPATIALSIGMA 0.0
133 #define DEFAULT_POSITION_X 0
134 #define DEFAULT_POSITION_Y 0
135 #define DEFAULT_WIDTH G_MAXINT
136 #define DEFAULT_HEIGHT G_MAXINT
137
138 G_DEFINE_TYPE (GstCvSmooth, gst_cv_smooth, GST_TYPE_OPENCV_VIDEO_FILTER);
139
140 static void gst_cv_smooth_set_property (GObject * object, guint prop_id,
141     const GValue * value, GParamSpec * pspec);
142 static void gst_cv_smooth_get_property (GObject * object, guint prop_id,
143     GValue * value, GParamSpec * pspec);
144
145 static GstFlowReturn gst_cv_smooth_transform_ip (GstOpencvVideoFilter *
146     filter, GstBuffer * buf, Mat img);
147
148 /* initialize the cvsmooth's class */
149 static void
150 gst_cv_smooth_class_init (GstCvSmoothClass * klass)
151 {
152   GObjectClass *gobject_class;
153   GstOpencvVideoFilterClass *gstopencvbasefilter_class;
154   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
155   GstCaps *caps;
156   GstPadTemplate *templ;
157
158   gobject_class = (GObjectClass *) klass;
159   gstopencvbasefilter_class = (GstOpencvVideoFilterClass *) klass;
160
161   gobject_class->set_property = gst_cv_smooth_set_property;
162   gobject_class->get_property = gst_cv_smooth_get_property;
163
164   gstopencvbasefilter_class->cv_trans_ip_func = gst_cv_smooth_transform_ip;
165
166   g_object_class_install_property (gobject_class, PROP_SMOOTH_TYPE,
167       g_param_spec_enum ("type",
168           "type",
169           "Smooth Type",
170           GST_TYPE_CV_SMOOTH_TYPE,
171           DEFAULT_CV_SMOOTH_TYPE,
172           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))
173       );
174   g_object_class_install_property (gobject_class, PROP_KERNELWIDTH,
175       g_param_spec_int ("kernel-width", "kernel width",
176           "The gaussian kernel width (must be positive and odd)."
177           "If type is median, this means the aperture linear size."
178           "Check OpenCV docs: http://docs.opencv.org"
179           "/2.4/modules/imgproc/doc/filtering.htm",
180           1, G_MAXINT, DEFAULT_KERNELWIDTH,
181           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
182   g_object_class_install_property (gobject_class, PROP_KERNELHEIGHT,
183       g_param_spec_int ("kernel-height", "kernel height",
184           "The gaussian kernel height (must be positive and odd).",
185           0, G_MAXINT, DEFAULT_KERNELHEIGHT,
186           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
187   g_object_class_install_property (gobject_class, PROP_COLORSIGMA,
188       g_param_spec_double ("color", "color (gaussian standard deviation or "
189           "color sigma",
190           "If type is gaussian, this means the standard deviation."
191           "If type is bilateral, this means the color-sigma. If zero, "
192           "Default values are used.",
193           0, G_MAXDOUBLE, DEFAULT_COLORSIGMA,
194           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
195   g_object_class_install_property (gobject_class, PROP_SPATIALSIGMA,
196       g_param_spec_double ("spatial", "spatial (spatial sigma, bilateral only)",
197           "Only used in bilateral type, means the spatial-sigma.",
198           0, G_MAXDOUBLE, DEFAULT_SPATIALSIGMA,
199           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
200   g_object_class_install_property (gobject_class, PROP_POSITION_X,
201       g_param_spec_int ("position-x", "starting x position for blur",
202           "Starting x position for blur (in pixels).",
203           0, G_MAXINT, DEFAULT_POSITION_X,
204           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
205   g_object_class_install_property (gobject_class, PROP_POSITION_Y,
206       g_param_spec_int ("position-y", "starting y position for blur",
207           "Starting y position for blur (in pixels).",
208           0, G_MAXINT, DEFAULT_POSITION_Y,
209           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
210   g_object_class_install_property (gobject_class, PROP_WIDTH,
211       g_param_spec_int ("width", "width of area to blur",
212           "Width of the area to blur (in pixels).",
213           0, G_MAXINT, DEFAULT_WIDTH,
214           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
215   g_object_class_install_property (gobject_class, PROP_HEIGHT,
216       g_param_spec_int ("height", "height of area to blur",
217           "Height of the area to blur (in pixels).",
218           0, G_MAXINT, DEFAULT_HEIGHT,
219           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
220
221   gst_element_class_set_static_metadata (element_class,
222       "cvsmooth",
223       "Transform/Effect/Video",
224       "Applies cvSmooth OpenCV function to the image",
225       "Thiago Santos<thiago.sousa.santos@collabora.co.uk>");
226
227   /* add sink and source pad templates */
228   caps = gst_opencv_caps_from_cv_image_type (CV_8UC3);
229   gst_caps_append (caps, gst_opencv_caps_from_cv_image_type (CV_8UC1));
230   templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
231       gst_caps_ref (caps));
232   gst_element_class_add_pad_template (element_class, templ);
233   templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
234   gst_element_class_add_pad_template (element_class, templ);
235   gst_caps_unref (caps);
236 }
237
238 /* initialize the new element
239  * instantiate pads and add them to element
240  * set pad calback functions
241  * initialize instance structure
242  */
243 static void
244 gst_cv_smooth_init (GstCvSmooth * filter)
245 {
246   filter->type = DEFAULT_CV_SMOOTH_TYPE;
247   filter->kernelwidth = DEFAULT_KERNELWIDTH;
248   filter->kernelheight = DEFAULT_KERNELHEIGHT;
249   filter->colorsigma = DEFAULT_COLORSIGMA;
250   filter->spatialsigma = DEFAULT_SPATIALSIGMA;
251   filter->positionx = DEFAULT_POSITION_X;
252   filter->positiony = DEFAULT_POSITION_Y;
253   filter->width = DEFAULT_WIDTH;
254   filter->height = DEFAULT_HEIGHT;
255
256   gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST (filter),
257       TRUE);
258 }
259
260 static void
261 gst_cv_smooth_change_type (GstCvSmooth * filter, gint value)
262 {
263   GST_DEBUG_OBJECT (filter, "Changing type from %d to %d", filter->type, value);
264   if (filter->type == value)
265     return;
266
267   filter->type = value;
268   switch (value) {
269     case GST_SMOOTH_GAUSSIAN:
270     case GST_SMOOTH_BLUR:
271       gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST
272           (filter), TRUE);
273       break;
274     default:
275       gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST
276           (filter), FALSE);
277       break;
278   }
279 }
280
281 static void
282 gst_cv_smooth_set_property (GObject * object, guint prop_id,
283     const GValue * value, GParamSpec * pspec)
284 {
285   GstCvSmooth *filter = GST_CV_SMOOTH (object);
286
287   switch (prop_id) {
288     case PROP_SMOOTH_TYPE:
289       gst_cv_smooth_change_type (filter, g_value_get_enum (value));
290       break;
291     case PROP_KERNELWIDTH:{
292       gint prop = g_value_get_int (value);
293
294       if (prop % 2 == 1) {
295         filter->kernelwidth = prop;
296       } else {
297         GST_WARNING_OBJECT (filter, "Ignoring value for kernel-width, not odd"
298             "(%d)", prop);
299       }
300     }
301       break;
302     case PROP_KERNELHEIGHT:{
303       gint prop = g_value_get_int (value);
304
305       if (prop % 2 == 1) {
306         filter->kernelheight = prop;
307       } else {
308         GST_WARNING_OBJECT (filter, "Ignoring value for kernel-height, not odd"
309             " nor zero (%d)", prop);
310       }
311     }
312       break;
313     case PROP_COLORSIGMA:
314       filter->colorsigma = g_value_get_double (value);
315       break;
316     case PROP_SPATIALSIGMA:
317       filter->spatialsigma = g_value_get_double (value);
318       break;
319     case PROP_POSITION_X:
320       filter->positionx = g_value_get_int (value);
321       break;
322     case PROP_POSITION_Y:
323       filter->positiony = g_value_get_int (value);
324       break;
325     case PROP_WIDTH:
326       filter->width = g_value_get_int (value);
327       break;
328     case PROP_HEIGHT:
329       filter->height = g_value_get_int (value);
330       break;
331     default:
332       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
333       break;
334   }
335 }
336
337 static void
338 gst_cv_smooth_get_property (GObject * object, guint prop_id,
339     GValue * value, GParamSpec * pspec)
340 {
341   GstCvSmooth *filter = GST_CV_SMOOTH (object);
342
343   switch (prop_id) {
344     case PROP_SMOOTH_TYPE:
345       g_value_set_enum (value, filter->type);
346       break;
347     case PROP_KERNELWIDTH:
348       g_value_set_int (value, filter->kernelwidth);
349       break;
350     case PROP_KERNELHEIGHT:
351       g_value_set_int (value, filter->kernelheight);
352       break;
353     case PROP_COLORSIGMA:
354       g_value_set_double (value, filter->colorsigma);
355       break;
356     case PROP_SPATIALSIGMA:
357       g_value_set_double (value, filter->spatialsigma);
358       break;
359     case PROP_POSITION_X:
360       g_value_set_int (value, filter->positionx);
361       break;
362     case PROP_POSITION_Y:
363       g_value_set_int (value, filter->positiony);
364       break;
365     case PROP_WIDTH:
366       g_value_set_int (value, filter->width);
367       break;
368     case PROP_HEIGHT:
369       g_value_set_int (value, filter->height);
370       break;
371     default:
372       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
373       break;
374   }
375 }
376
377 static GstFlowReturn
378 gst_cv_smooth_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
379     Mat img)
380 {
381   GstCvSmooth *filter = GST_CV_SMOOTH (base);
382
383   if (filter->positionx != 0 || filter->positiony != 0 ||
384       filter->width != G_MAXINT || filter->height != G_MAXINT) {
385     Size mat_size = img.size ();
386
387     /* if the effect would start outside the image, just skip it */
388     if (filter->positionx >= mat_size.width
389         || filter->positiony >= mat_size.height)
390       return GST_FLOW_OK;
391     /* explicitly account for empty area */
392     if (filter->width <= 0 || filter->height <= 0)
393       return GST_FLOW_OK;
394
395     Rect mat_rect (filter->positionx,
396         filter->positiony,
397         MIN (filter->width, mat_size.width - filter->positionx),
398         MIN (filter->height, mat_size.height - filter->positiony));
399
400     img = img (mat_rect);
401   }
402
403   switch (filter->type) {
404     case GST_SMOOTH_BLUR:
405       blur (img, img, Size (filter->kernelwidth, filter->kernelheight),
406           Point (-1, -1));
407       break;
408     case GST_SMOOTH_GAUSSIAN:
409       GaussianBlur (img, img, Size (filter->kernelwidth, filter->kernelheight),
410           filter->colorsigma, filter->colorsigma);
411       break;
412     case GST_SMOOTH_MEDIAN:
413       medianBlur (img, img, filter->kernelwidth);
414       break;
415     case GST_SMOOTH_BILATERAL:
416       bilateralFilter (img, img, -1, filter->colorsigma, 0.0);
417       break;
418     default:
419       break;
420   }
421
422   return GST_FLOW_OK;
423 }
424
425 gboolean
426 gst_cv_smooth_plugin_init (GstPlugin * plugin)
427 {
428   GST_DEBUG_CATEGORY_INIT (gst_cv_smooth_debug, "cvsmooth", 0, "cvsmooth");
429
430   return gst_element_register (plugin, "cvsmooth", GST_RANK_NONE,
431       GST_TYPE_CV_SMOOTH);
432 }