retinex: Port to GstOpencvVideoFilter base class

This allow reducing slightly the code. It also fixes a bug caused by
in-place buffer being mapped and never unmapped.
This commit is contained in:
Nicolas Dufresne 2016-12-03 22:02:23 -05:00
parent 54aaf84e08
commit ee940b130f
2 changed files with 37 additions and 50 deletions

View file

@ -108,7 +108,7 @@ gst_retinex_method_get_type (void)
return etype; return etype;
} }
G_DEFINE_TYPE (GstRetinex, gst_retinex, GST_TYPE_VIDEO_FILTER); G_DEFINE_TYPE (GstRetinex, gst_retinex, GST_TYPE_OPENCV_VIDEO_FILTER);
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
@ -125,10 +125,11 @@ static void gst_retinex_set_property (GObject * object, guint prop_id,
static void gst_retinex_get_property (GObject * object, guint prop_id, static void gst_retinex_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static GstFlowReturn gst_retinex_transform_ip (GstBaseTransform * btrans, static GstFlowReturn gst_retinex_transform_ip (GstOpencvVideoFilter * filter,
GstBuffer * buf); GstBuffer * buff, IplImage * img);
static gboolean gst_retinex_set_caps (GstBaseTransform * btrans, static gboolean gst_retinex_set_caps (GstOpencvVideoFilter* btrans,
GstCaps * incaps, GstCaps * outcaps); gint in_width, gint in_height, gint in_depth, gint in_channels,
gint out_width, gint out_height, gint out_depth, gint out_channels);
static void gst_retinex_release_all_images (GstRetinex * filter); static void gst_retinex_release_all_images (GstRetinex * filter);
@ -141,12 +142,15 @@ gst_retinex_class_init (GstRetinexClass * klass)
GObjectClass *gobject_class = (GObjectClass *) klass; GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass; GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
GstOpencvVideoFilterClass *cvbasefilter_class =
(GstOpencvVideoFilterClass *) klass;
gobject_class->set_property = gst_retinex_set_property; gobject_class->set_property = gst_retinex_set_property;
gobject_class->get_property = gst_retinex_get_property; gobject_class->get_property = gst_retinex_get_property;
btrans_class->transform_ip = gst_retinex_transform_ip; cvbasefilter_class->cv_trans_ip_func = gst_retinex_transform_ip;
btrans_class->set_caps = gst_retinex_set_caps; cvbasefilter_class->cv_set_caps = gst_retinex_set_caps;
btrans_class->stop = gst_retinex_stop; btrans_class->stop = gst_retinex_stop;
g_object_class_install_property (gobject_class, PROP_METHOD, g_object_class_install_property (gobject_class, PROP_METHOD,
@ -225,42 +229,33 @@ gst_retinex_get_property (GObject * object, guint prop_id,
} }
} }
/* GstElement vmethod implementations */
/* this function handles the link with other elements */
static gboolean static gboolean
gst_retinex_set_caps (GstBaseTransform * btrans, GstCaps * incaps, gst_retinex_set_caps (GstOpencvVideoFilter * filter, gint in_width, gint in_height,
GstCaps * outcaps) gint in_depth, gint in_channels, gint out_width, gint out_height,
gint out_depth, gint out_channels)
{ {
GstRetinex *retinex = GST_RETINEX (btrans); GstRetinex *retinex = GST_RETINEX (filter);
CvSize size; CvSize size;
GstVideoInfo info;
gst_video_info_from_caps (&info, incaps);
size = cvSize (info.width, info.height); size = cvSize (in_width, in_height);
/* If cvRGB is already allocated, it means there's a cap modification, if (retinex->cvA)
so release first all the images. */
if (NULL != retinex->cvRGBin)
gst_retinex_release_all_images (retinex); gst_retinex_release_all_images (retinex);
retinex->cvRGBin = cvCreateImageHeader (size, IPL_DEPTH_8U, 3); retinex->cvA = cvCreateImage (size, IPL_DEPTH_32F, in_channels);
retinex->cvRGBout = cvCreateImageHeader (size, IPL_DEPTH_8U, 3); retinex->cvB = cvCreateImage (size, IPL_DEPTH_32F, in_channels);
retinex->cvC = cvCreateImage (size, IPL_DEPTH_32F, in_channels);
retinex->cvA = cvCreateImage (size, IPL_DEPTH_32F, 3); retinex->cvD = cvCreateImage (size, IPL_DEPTH_32F, in_channels);
retinex->cvB = cvCreateImage (size, IPL_DEPTH_32F, 3);
retinex->cvC = cvCreateImage (size, IPL_DEPTH_32F, 3);
retinex->cvD = cvCreateImage (size, IPL_DEPTH_32F, 3);
return TRUE; return TRUE;
} }
/* Clean up */
static gboolean static gboolean
gst_retinex_stop (GstBaseTransform * basesrc) gst_retinex_stop (GstBaseTransform * basesrc)
{ {
GstRetinex *filter = GST_RETINEX (basesrc); GstRetinex *filter = GST_RETINEX (basesrc);
if (filter->cvRGBin != NULL) if (filter->cvA != NULL)
gst_retinex_release_all_images (filter); gst_retinex_release_all_images (filter);
g_free (filter->weights); g_free (filter->weights);
@ -274,9 +269,6 @@ gst_retinex_stop (GstBaseTransform * basesrc)
static void static void
gst_retinex_release_all_images (GstRetinex * filter) gst_retinex_release_all_images (GstRetinex * filter)
{ {
cvReleaseImage (&filter->cvRGBin);
cvReleaseImage (&filter->cvRGBout);
cvReleaseImage (&filter->cvA); cvReleaseImage (&filter->cvA);
cvReleaseImage (&filter->cvB); cvReleaseImage (&filter->cvB);
cvReleaseImage (&filter->cvC); cvReleaseImage (&filter->cvC);
@ -284,35 +276,30 @@ gst_retinex_release_all_images (GstRetinex * filter)
} }
static GstFlowReturn static GstFlowReturn
gst_retinex_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) gst_retinex_transform_ip (GstOpencvVideoFilter * filter, GstBuffer * buf,
IplImage * img)
{ {
GstRetinex *retinex = GST_RETINEX (btrans); GstRetinex *retinex = GST_RETINEX (filter);
GstMapInfo info;
double sigma = 14.0; double sigma = 14.0;
int gain = 128; int gain = 128;
int offset = 128; int offset = 128;
int filter_size; int filter_size;
Mat icvD = cvarrToMat(retinex->cvD, false); Mat icvD = cvarrToMat(retinex->cvD, false);
if (!gst_buffer_map (buf, &info, (GstMapFlags) GST_MAP_READWRITE)) {
return GST_FLOW_ERROR;
}
retinex->cvRGBin->imageData = (char *) info.data;
/* Basic retinex restoration. The image and a filtered image are converted /* Basic retinex restoration. The image and a filtered image are converted
to the log domain and subtracted. to the log domain and subtracted.
O = Log(I) - Log(H(I)) O = Log(I) - Log(H(I))
where O is the output, H is a gaussian 2d filter and I is the input image. */ where O is the output, H is a gaussian 2d filter and I is the input image. */
if (METHOD_BASIC == retinex->method) { if (METHOD_BASIC == retinex->method) {
/* Compute log image */ /* Compute log image */
cvConvert (retinex->cvRGBin, retinex->cvA); cvConvert (img, retinex->cvA);
cvLog (retinex->cvA, retinex->cvB); cvLog (retinex->cvA, retinex->cvB);
/* Compute log of blured image */ /* Compute log of blured image */
filter_size = (int) floor (sigma * 6) / 2; filter_size = (int) floor (sigma * 6) / 2;
filter_size = filter_size * 2 + 1; filter_size = filter_size * 2 + 1;
cvConvert (retinex->cvRGBin, retinex->cvD); cvConvert (img, retinex->cvD);
GaussianBlur (icvD, icvD, Size (filter_size, filter_size), 0.0, 0.0); GaussianBlur (icvD, icvD, Size (filter_size, filter_size), 0.0, 0.0);
cvLog (retinex->cvD, retinex->cvC); cvLog (retinex->cvD, retinex->cvC);
@ -320,7 +307,7 @@ gst_retinex_transform_ip (GstBaseTransform * btrans, GstBuffer * buf)
cvSub (retinex->cvB, retinex->cvC, retinex->cvA, NULL); cvSub (retinex->cvB, retinex->cvC, retinex->cvA, NULL);
/* Restore */ /* Restore */
cvConvertScale (retinex->cvA, retinex->cvRGBin, (float) gain, cvConvertScale (retinex->cvA, img, (float) gain,
(float) offset); (float) offset);
} }
/* Multiscale retinex restoration. The image and a set of filtered images are /* Multiscale retinex restoration. The image and a set of filtered images are
@ -349,7 +336,7 @@ gst_retinex_transform_ip (GstBaseTransform * btrans, GstBuffer * buf)
} }
/* Compute log image */ /* Compute log image */
cvConvert (retinex->cvRGBin, retinex->cvA); cvConvert (img, retinex->cvA);
cvLog (retinex->cvA, retinex->cvB); cvLog (retinex->cvA, retinex->cvB);
/* Filter at each scale */ /* Filter at each scale */
@ -357,7 +344,7 @@ gst_retinex_transform_ip (GstBaseTransform * btrans, GstBuffer * buf)
filter_size = (int) floor (retinex->sigmas[i] * 6) / 2; filter_size = (int) floor (retinex->sigmas[i] * 6) / 2;
filter_size = filter_size * 2 + 1; filter_size = filter_size * 2 + 1;
cvConvert (retinex->cvRGBin, retinex->cvD); cvConvert (img, retinex->cvD);
GaussianBlur (icvD, icvD, Size (filter_size, filter_size), 0.0, 0.0); GaussianBlur (icvD, icvD, Size (filter_size, filter_size), 0.0, 0.0);
cvLog (retinex->cvD, retinex->cvC); cvLog (retinex->cvD, retinex->cvC);
@ -367,7 +354,7 @@ gst_retinex_transform_ip (GstBaseTransform * btrans, GstBuffer * buf)
} }
/* Restore */ /* Restore */
cvConvertScale (retinex->cvB, retinex->cvRGBin, (float) gain, cvConvertScale (retinex->cvB, img, (float) gain,
(float) offset); (float) offset);
} }

View file

@ -65,22 +65,22 @@ typedef struct _GstRetinexClass GstRetinexClass;
struct _GstRetinex struct _GstRetinex
{ {
GstVideoFilter element; GstOpencvVideoFilter parent;
gint width, height;
gint method; gint method;
gint scales, current_scales; gint scales, current_scales;
double *weights; double *weights;
double *sigmas; double *sigmas;
IplImage *cvRGBin; IplImage *cvA;
IplImage *cvRGBout; IplImage *cvB;
IplImage *cvA, *cvB, *cvC, *cvD; IplImage *cvC;
IplImage *cvD;
}; };
struct _GstRetinexClass struct _GstRetinexClass
{ {
GstVideoFilterClass parent_class; GstOpencvVideoFilterClass parent_class;
}; };
GType gst_retinex_get_type (void); GType gst_retinex_get_type (void);