2nd week report.
My work is primarily to develop a clean way to convert between OpenCV’s Mat object into our Shogun’s SGMatrix object. This would be really cool, once we have it as there will be a seamless interaction between both the libraries. Whenever we need machine learning capabilities, we can switch to Shogun and whenever we need the Image processing manipulations we can work on with OpenCV.
Point:
To develop a Factory such that if in its arguments I give a cv::Mat object’s name, It returns me with a DenseFeature object of shogun containing that matrix. The flexibility should be like that whatever type the input Mat might be (i.e uint8, uin16, float32,..etc), the user can choose what kind of DenseFeature he wanna work with. And yeah going vice versa will also be needed.
Things that are needed to be done:
We have 3 methods of converting data as suggested by Kevin in his gist here . Those are namely:
- Using Constructors.
- Using for loops (i.e doing it all manually).
- Using Memcpy.
So, Using this I got a nice idea of how the main conversion would look like. Now comes the design part.
That means the functions declaration that we want would look something like this :
CDenseFeatures<T>* CV2FeaturesFactory::getDenseFeatures(cv::Mat, CV2SGOptions).
The 1st argument is to hold the name of the cv::Mat object that we want to transform.
The 2nd argument is to hold the name of the different options.
The template argument T would specify the type of the output CDenseFeatures that we want.
Initial Steps that came to my mind:
Now doing such a thing would require to define a template function in a non-templated class.
The non-templated class would look like :
class CV2FeaturesFactory
{
public:
template<class T> static CDenseFeatures<T>* CV2FeaturesFactory::getDenseFeatures(cv::Mat, CV2SGOptions);
};
We need to somehow extract few things from the cv::Mat before we start with the Kevin’s methods. Those are:
1. Number of Rows.
2. Number of Columns.
3. What type is cv::Mat object to start with!!
4. I think we may even need to convert it into the required type before we feed it into the 3 methods mentioned at the start.
Setting It all up:
Most things are quite straight forward.
- To calculate number of rows/cols for a obj named cvMat, we have :
int r=cvMat.rows;
int c=cvMat.cols;
- No need to know the type of cvMat. We just need to convert whatever it is into the required type using the
cvMat.convertTo(cvMat, the output typename);
- The only thing thats needed to be done here explicitly is to transfer the typename from the template argument (i.e <class T> in the function definition) to something understandable to OpenCV in its convertTo() function ‘s second argument.
- I checked out the way OpenCV handles it’s Types, and found about the enums:
8-bit unsigned integer (uchar)
8-bit signed integer (schar)
16-bit unsigned integer (ushort)
16-bit signed integer (short)
32-bit signed integer (int)
32-bit floating-point number (float)
64-bit floating-point number (double)
enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };
This was a great finding. What this means is that we only need to somehow convert the given T into the required integer. Say, if the user has specified ‘uint16_t’ as the ‘T’. Then we need to get integer value 2 into the arguments of convertTo() function.
Now, the thing is that I cannot possibly play with adding default enums for uint8_t, uint16t_t, float32_t …. . It is not allowed as I kept on getting the error as it being ‘redeclared’.
- The only thing I could come up with was a templated function which returns the required integers depending on the template arguement T. For eg:
int ans = get<uint8_t>() would set ans to 0;
int ans = get<float64_t>() would set ans to 6;
I searched and found USER SPECIALIZATION. It does exactly this thing.
By default, a template gives a single definition to be used for every template argument. This doesn’t always makes sense in the way that If I want my implementation to be different for different types say, for each of the 3 following types:
uint8, int16, float32 --- I want to write three different implementations of the same named templated functions. This can be achieved using Specialization.
So, I came up with this :
the general template must be declared before any specialization.
“The critical information supplied by the general template is the set of template parameters that the user must supply to use it or any of its specializations.”
template<typename T> class CV2SGTypeName;
template<> struct CV2SGTypeName<uint8_t>{
static const int get(){return 0;}
};
template<> struct CV2SGTypeName<int8_t>{
static const int get(){return 1;}
};
template<> struct CV2SGTypeName<uint16_t>{
static const int get(){return 2;}
} and so on
Here I have created few specializations which can be used as the common implementation for the user.
So now we have a function CV2SGTypeName<T>::get() which can be used very flexibly to return integers based on the template argument.
i.e
const int myType = CV2SGTypeName<T>::get();
I will add the source codes Once It gets ready to be merged.