1 /* GStreamer
2  * Copyright (C) <2010> Thiago Santos <thiago.sousa.santos@collabora.co.uk>
3  * Copyright (C) <2018> Nicola Murino <nicola.murino@gmail.com>
4  *
5  * gstopencvutils.c: miscellaneous utility functions
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "gstopencvutils.h"
28 #include <opencv2/core.hpp>
29 
30 /*
31 The various opencv image containers or headers store the following information:
32 - number of channels (usually 1, 3 or 4)
33 - depth (8, 16, 32, 64...); all channels have the same depth.
34 The channel layout (BGR vs RGB) is not stored...
35 
36 This gives us the following list of supported image formats:
37   CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4
38   CV_8SC1, CV_8SC2, CV_8SC3, CV_8SC4
39   CV_16UC1, CV_16UC2, CV_16UC3, CV_16UC4
40   CV_16SC1, CV_16SC2, CV_16SC3, CV_16SC4
41   CV_32SC1, CV_32SC2, CV_32SC3, CV_32SC4
42   CV_32FC1, CV_32FC2, CV_32FC3, CV_32FC4
43   CV_64FC1, CV_64FC2, CV_64FC3, CV_64FC4
44 
45 Where the first part of the format name is the depth followed by a digit
46 representing the number of channels.
47 Note that opencv supports more that 4 channels.
48 
49 The opencv algorithms don't all support all the image types.
50 For example findChessboardCorners() supports only 8 bits formats
51 (gray scale and color).
52 
53 And, typically, this algorithm will convert the image to gray scale before
54 proceeding. It will do so with something like this:
55    cvtColor(srcImg, destImg, CV_BGR2GRAY);
56 
57 The conversion will work on any BGR format (BGR, BGRA, BGRx).
58 The extra channel(s) will be ignored.
59 It will also produce a result for any RGB format.
60 The result will be "wrong" to the human eye and might affect some algorithms
61 (not findChessboardCorners() afaik...).
62 This is due to how RGB gets converted to gray where each color has a
63 different weight.
64 
65 Another example is the 2D rendering API.
66 It work with RGB but the colors will be wrong.
67 
68 Likewise other layouts like xBGR and ABGR formats will probably misbehave
69 with most algorithms.
70 
71 The bad thing is that it is not possible to change the "default" BGR format.
72 Safest is to not assume that RGB will work and always convert to BGR.
73 
74 That said, the current opencv gstreamer elements all accept BGR and RGB caps !
75 Some have restrictions but if a format is supported then both BGR and RGB
76 layouts will be supported.
77 */
78 
gst_opencv_parse_cv_mat_params_from_caps(GstCaps * caps,gint * width,gint * height,int * cv_type,GError ** err)79 gboolean gst_opencv_parse_cv_mat_params_from_caps
80     (GstCaps * caps, gint * width, gint * height, int *cv_type, GError ** err)
81 {
82   GstVideoInfo info;
83   gchar *caps_str;
84 
85   if (!gst_video_info_from_caps (&info, caps)) {
86     caps_str = gst_caps_to_string (caps);
87     GST_ERROR ("Failed to get video info from caps %s", caps_str);
88     g_set_error (err, GST_CORE_ERROR, GST_CORE_ERROR_NEGOTIATION,
89         "Failed to get video info from caps %s", caps_str);
90     g_free (caps_str);
91     return FALSE;
92   }
93 
94   return gst_opencv_cv_mat_params_from_video_info (&info, width, height,
95       cv_type, err);
96 }
97 
gst_opencv_cv_mat_params_from_video_info(GstVideoInfo * info,gint * width,gint * height,int * cv_type,GError ** err)98 gboolean gst_opencv_cv_mat_params_from_video_info
99     (GstVideoInfo * info, gint * width, gint * height, int *cv_type,
100     GError ** err)
101 {
102   GstVideoFormat format;
103 
104   format = GST_VIDEO_INFO_FORMAT (info);
105   if (!gst_opencv_cv_image_type_from_video_format (format, cv_type, err)) {
106     return FALSE;
107   }
108 
109   *width = GST_VIDEO_INFO_WIDTH (info);
110   *height = GST_VIDEO_INFO_HEIGHT (info);
111 
112   return TRUE;
113 }
114 
115 gboolean
gst_opencv_cv_image_type_from_video_format(GstVideoFormat format,int * cv_type,GError ** err)116 gst_opencv_cv_image_type_from_video_format (GstVideoFormat format,
117     int *cv_type, GError ** err)
118 {
119   const gchar *format_str;
120 
121   switch (format) {
122     case GST_VIDEO_FORMAT_GRAY8:
123       *cv_type = CV_8UC1;
124       break;
125     case GST_VIDEO_FORMAT_RGB:
126     case GST_VIDEO_FORMAT_BGR:
127       *cv_type = CV_8UC3;
128       break;
129     case GST_VIDEO_FORMAT_RGBx:
130     case GST_VIDEO_FORMAT_xRGB:
131     case GST_VIDEO_FORMAT_BGRx:
132     case GST_VIDEO_FORMAT_xBGR:
133     case GST_VIDEO_FORMAT_RGBA:
134     case GST_VIDEO_FORMAT_ARGB:
135     case GST_VIDEO_FORMAT_BGRA:
136     case GST_VIDEO_FORMAT_ABGR:
137       *cv_type = CV_8UC4;
138       break;
139     case GST_VIDEO_FORMAT_GRAY16_LE:
140     case GST_VIDEO_FORMAT_GRAY16_BE:
141       *cv_type = CV_16UC1;
142       break;
143     default:
144       format_str = gst_video_format_to_string (format);
145       g_set_error (err, GST_CORE_ERROR, GST_CORE_ERROR_NEGOTIATION,
146           "Unsupported video format %s", format_str);
147       return FALSE;
148   }
149 
150   return TRUE;
151 }
152 
153 GstCaps *
gst_opencv_caps_from_cv_image_type(int cv_type)154 gst_opencv_caps_from_cv_image_type (int cv_type)
155 {
156   GstCaps *c = gst_caps_new_empty ();
157   switch (cv_type) {
158     case CV_8UC1:
159       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("GRAY8")));
160       break;
161     case CV_8UC3:
162       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("RGB")));
163       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("BGR")));
164       break;
165     case CV_8UC4:
166       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("RGBx")));
167       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("xRGB")));
168       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("BGRx")));
169       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("xBGR")));
170       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("RGBA")));
171       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("ARGB")));
172       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("BGRA")));
173       gst_caps_append (c, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("ABGR")));
174       break;
175     case CV_16UC1:
176       gst_caps_append (c,
177           gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("GRAY16_LE")));
178       gst_caps_append (c,
179           gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("GRAY16_BE")));
180       break;
181   }
182   return c;
183 }
184