Skip to content

Instantly share code, notes, and snippets.

@astarasikov
Created January 15, 2020 01:44
Show Gist options
  • Save astarasikov/7f56143d87dba37b4241c0e5c0a5965e to your computer and use it in GitHub Desktop.
Save astarasikov/7f56143d87dba37b4241c0e5c0a5965e to your computer and use it in GitHub Desktop.
gstreamer plugin for correcting fisheye lens distortion
diff -Naur ./gst/geometrictransform/gstdefisheye.c ../../gst-plugins-bad1.0-1.10.2/gst/geometrictransform/gstdefisheye.c
--- ./gst/geometrictransform/gstdefisheye.c 1970-01-01 03:00:00.000000000 +0300
+++ ../../gst-plugins-bad1.0-1.10.2/gst/geometrictransform/gstdefisheye.c 2017-01-10 02:55:38.186100000 +0300
@@ -0,0 +1,265 @@
+/*
+ * GStreamer
+ * Copyright (C) 2016 Alexander Tarasikov <alexander.tarasikov@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-defisheye
+ * @see_also: geometrictransform
+ *
+ * Defisheye is a geometric image transform element. It is intended to correct
+ * the image obtained from the camera with a wide-angle (fisheye) lens.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v videotestsrc ! defisheye ! videoconvert ! autovideosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <math.h>
+
+#include "gstdefisheye.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_defisheye_debug);
+#define GST_CAT_DEFAULT gst_defisheye_debug
+
+enum
+{
+ PROP_0,
+ PROP_CENTER_X,
+ PROP_CENTER_Y,
+
+ PROP_STRENGTH,
+ PROP_ZOOM,
+
+ PROP_SCALE_X,
+ PROP_SCALE_Y,
+};
+
+#define DEFAULT_CENTER_X (-0.3)
+#define DEFAULT_CENTER_Y (-0.6)
+
+#define DEFAULT_STRENGTH 0.3329
+#define DEFAULT_ZOOM 2.4311
+
+#define DEFAULT_SCALE_X 0.65
+#define DEFAULT_SCALE_Y 1.30
+
+#define gst_defisheye_parent_class parent_class
+G_DEFINE_TYPE (GstDefisheye, gst_defisheye, GST_TYPE_GEOMETRIC_TRANSFORM);
+
+static void
+gst_defisheye_set_property (GObject * object, guint prop_id, const GValue * value,
+ GParamSpec * pspec)
+{
+ GstDefisheye *defisheye;
+ GstGeometricTransform *gt;
+ gdouble v;
+
+ gt = GST_GEOMETRIC_TRANSFORM_CAST (object);
+ defisheye = GST_DEFISHEYE_CAST (object);
+
+#define DEFISHEYE_PROP_SETTER_CASE(field, prop) \
+ case PROP_##prop: \
+ v = g_value_get_double(value); \
+ if (v != defisheye->field) {\
+ defisheye->field = v;\
+ gst_geometric_transform_set_need_remap(gt);\
+ }\
+ break;
+
+ GST_OBJECT_LOCK (gt);
+ switch (prop_id) {
+ DEFISHEYE_PROP_SETTER_CASE(cx, CENTER_X);
+ DEFISHEYE_PROP_SETTER_CASE(cy, CENTER_Y);
+ DEFISHEYE_PROP_SETTER_CASE(strength, STRENGTH);
+ DEFISHEYE_PROP_SETTER_CASE(zoom, ZOOM);
+ DEFISHEYE_PROP_SETTER_CASE(sx, SCALE_X);
+ DEFISHEYE_PROP_SETTER_CASE(sy, SCALE_Y);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (gt);
+
+#undef DEFISHEYE_PROP_SETTER_CASE
+}
+
+static void
+gst_defisheye_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstDefisheye *defisheye;
+
+ defisheye = GST_DEFISHEYE_CAST (object);
+
+#define DEFISHEYE_PROP_GETTER_CASE(field, prop) \
+ case PROP_##prop:\
+ g_value_set_double(value, defisheye->field); \
+ break;
+
+ switch (prop_id) {
+ DEFISHEYE_PROP_GETTER_CASE(cx, CENTER_X);
+ DEFISHEYE_PROP_GETTER_CASE(cy, CENTER_Y);
+ DEFISHEYE_PROP_GETTER_CASE(strength, STRENGTH);
+ DEFISHEYE_PROP_GETTER_CASE(zoom, ZOOM);
+ DEFISHEYE_PROP_GETTER_CASE(sx, SCALE_X);
+ DEFISHEYE_PROP_GETTER_CASE(sy, SCALE_Y);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+#undef DEFISHEYE_PROP_GETTER_CASE
+}
+
+static gboolean
+defisheye_map (GstGeometricTransform * gt, gint x, gint y, gdouble * in_x,
+ gdouble * in_y)
+{
+ GstDefisheye *defisheye = GST_DEFISHEYE_CAST (gt);
+ gdouble norm_x;
+ gdouble norm_y;
+ gdouble r;
+
+ gdouble t_norm_x;
+ gdouble t_norm_y;
+
+ gdouble width = gt->width;
+ gdouble height = gt->height;
+
+ gdouble theta = 1.0;
+
+ /* calculate aspect ratio to work with cropped non-circular images */
+ /* for now, assume the image is cropped vertically */
+ gdouble aspect = (width / height);
+
+ /* normalize in ((-1.0, -1.0), (1.0, 1.0) */
+ norm_x = 2.0 * x / width - 1.0;
+ norm_y = 2.0 * aspect * y / height - 1.0;
+
+ /* tranlate the normalized coordinates relative to lens centre */
+ t_norm_x = norm_x - defisheye->cx;
+ t_norm_y = norm_y - defisheye->cy;
+
+ /* normalize radius to 1, simplifies following formula */
+ r = sqrt ((t_norm_x * t_norm_x + t_norm_y * t_norm_y)) / defisheye->strength;
+
+ if (fabs(r) > 0.0) {
+ theta = atan(r) / r;
+ }
+
+ /* undistort and post-scale */
+ norm_x *= defisheye->sx * theta * defisheye->zoom;
+ norm_y *= defisheye->sy * theta * defisheye->zoom;
+
+ /* unnormalize */
+ *in_x = 0.5 * (norm_x + 1.0) * width;
+ *in_y = 0.5 * (norm_y + 1.0) * height;
+
+ GST_DEBUG_OBJECT (defisheye, "Inversely mapped %d %d into %lf %lf",
+ x, y, *in_x, *in_y);
+
+ return TRUE;
+}
+
+static void
+gst_defisheye_class_init (GstDefisheyeClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstGeometricTransformClass *gstgt_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstgt_class = (GstGeometricTransformClass *) klass;
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "defisheye",
+ "Transform/Effect/Video",
+ "Correct the distortion caused by a wide-angle fisheye lens by converting to rectilinear coordinates.",
+ "Alexander Tarasikov <alexander.tarasikov@gmail.com>");
+
+ gobject_class->set_property = gst_defisheye_set_property;
+ gobject_class->get_property = gst_defisheye_get_property;
+
+#define DEFISHEYE_DECL_PROP(field, prop) do { \
+ g_object_class_install_property (gobject_class, PROP_##prop, \
+ g_param_spec_double (#field, #field, \
+ #field,\
+ -10.0, 10.0, DEFAULT_##prop, \
+ GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT)); \
+} while (0)
+
+ DEFISHEYE_DECL_PROP(cx, CENTER_X);
+ DEFISHEYE_DECL_PROP(cy, CENTER_Y);
+ DEFISHEYE_DECL_PROP(strength, STRENGTH);
+ DEFISHEYE_DECL_PROP(zoom, ZOOM);
+ DEFISHEYE_DECL_PROP(sx, SCALE_X);
+ DEFISHEYE_DECL_PROP(sy, SCALE_Y);
+
+#undef DEFISHEYE_DECL_PROP
+
+ gstgt_class->map_func = defisheye_map;
+}
+
+static void
+gst_defisheye_init (GstDefisheye * filter)
+{
+ GstGeometricTransform *gt = GST_GEOMETRIC_TRANSFORM (filter);
+
+ gt->off_edge_pixels = GST_GT_OFF_EDGES_PIXELS_CLAMP;
+}
+
+gboolean
+gst_defisheye_plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (gst_defisheye_debug, "defisheye", 0, "defisheye");
+
+ return gst_element_register (plugin, "defisheye", GST_RANK_NONE,
+ GST_TYPE_DEFISHEYE);
+}
diff -Naur ./gst/geometrictransform/gstdefisheye.h ../../gst-plugins-bad1.0-1.10.2/gst/geometrictransform/gstdefisheye.h
--- ./gst/geometrictransform/gstdefisheye.h 1970-01-01 03:00:00.000000000 +0300
+++ ../../gst-plugins-bad1.0-1.10.2/gst/geometrictransform/gstdefisheye.h 2017-01-10 02:45:23.803062000 +0300
@@ -0,0 +1,92 @@
+/*
+ * GStreamer
+ * Copyright (C) 2016 Alexander Tarasikov <alexander.tarasikov@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DEFISHEYE_H__
+#define __GST_DEFISHEYE_H__
+
+#include <gst/gst.h>
+#include "gstgeometrictransform.h"
+#include "geometricmath.h"
+
+G_BEGIN_DECLS
+/* #defines don't like whitespacey bits */
+#define GST_TYPE_DEFISHEYE \
+ (gst_defisheye_get_type())
+#define GST_DEFISHEYE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEFISHEYE,GstDefisheye))
+#define GST_DEFISHEYE_CAST(obj) \
+ ((GstDefisheye *)(obj))
+#define GST_DEFISHEYE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEFISHEYE,GstDefisheyeClass))
+#define GST_IS_DEFISHEYE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEFISHEYE))
+#define GST_IS_DEFISHEYE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEFISHEYE))
+typedef struct _GstDefisheye GstDefisheye;
+typedef struct _GstDefisheyeClass GstDefisheyeClass;
+
+struct _GstDefisheye
+{
+ GstGeometricTransform element;
+
+ gdouble cx;
+ gdouble cy;
+
+ gdouble strength;
+ gdouble zoom;
+
+ gdouble sx;
+ gdouble sy;
+};
+
+struct _GstDefisheyeClass
+{
+ GstGeometricTransformClass parent_class;
+};
+
+GType gst_defisheye_get_type (void);
+
+gboolean gst_defisheye_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_DEFISHEYE_H__ */
diff -Naur ./gst/geometrictransform/Makefile.am ../../gst-plugins-bad1.0-1.10.2/gst/geometrictransform/Makefile.am
--- ./gst/geometrictransform/Makefile.am 2016-11-04 20:07:13.000000000 +0300
+++ ../../gst-plugins-bad1.0-1.10.2/gst/geometrictransform/Makefile.am 2017-01-10 02:43:51.853110000 +0300
@@ -19,7 +19,8 @@
gstsquare.c \
gstmirror.c \
gstfisheye.c \
- gstperspective.c
+ gstperspective.c \
+ gstdefisheye.c
libgstgeometrictransform_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS)
@@ -48,4 +49,5 @@
gstsquare.h \
gstmirror.h \
gstfisheye.h \
- gstperspective.h
+ gstperspective.h \
+ gstdefisheye.h
diff -Naur ./gst/geometrictransform/plugin.c ../../gst-plugins-bad1.0-1.10.2/gst/geometrictransform/plugin.c
--- ./gst/geometrictransform/plugin.c 2016-11-04 20:07:13.000000000 +0300
+++ ../../gst-plugins-bad1.0-1.10.2/gst/geometrictransform/plugin.c 2017-01-10 02:44:14.736546000 +0300
@@ -37,6 +37,7 @@
#include "gstmirror.h"
#include "gstfisheye.h"
#include "gstperspective.h"
+#include "gstdefisheye.h"
static gboolean
plugin_init (GstPlugin * plugin)
@@ -88,6 +89,9 @@
if (!gst_perspective_plugin_init (plugin))
return FALSE;
+
+ if (!gst_defisheye_plugin_init (plugin))
+ return FALSE;
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment