I am making an application that would process some images for me, using OpenCV. It should allow for processing different types of images (type specified by the user).
Most processing is done is a same manner, and only depends on the type of data held in the cv:Mat
(used in functions such as cv::Mat.at<type>()
to reference the data correctly). For this, I built a Base class ImageProcessor
which would contain the common implementation, virtual interfaces for functions which need to know the type, and a Factory Method. I further built a templated Derived TypedProcessor<datatype>
class, such that I can implement the data-access methods.
However, I am getting an odd compilation error whenever I use OpenCV templated access functions inside the Derived class. Here is the Minimal (non-)Working Example:
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
class ImageProcessor{
public:
static ImageProcessor *NewProcessor(char option, std::string imgPath);
virtual ~ImageProcessor() {}
virtual void printMaxElem() = 0;
protected:
ImageProcessor(const std::string &imgPath) : workingImagePath(imgPath) {
this->workingImage = cv::imread(imgPath.c_str(), CV_LOAD_IMAGE_ANYDEPTH);
}
cv::Mat workingImage;
std::string workingImagePath;
};
template <typename datatype>
class TypedProcessor : public ImageProcessor{
public:
TypedProcessor(std::string imgPath) : ImageProcessor(imgPath) {}
virtual ~TypedProcessor() {}
void printMaxElem();
void preprocess();
private:
void calculateDisplayValue();
};
template <typename datatype>
void TypedProcessor<datatype>::printMaxElem(){
std::cerr << (datatype)(*std::max_element(this->workingImage.begin<datatype>(), this->workingImage.end<datatype>())) << std::endl;
}
ImageProcessor* ImageProcessor::NewProcessor(char option, std::string imgPath){
ImageProcessor *processor = NULL;
switch (option){
case 'h': // input correctly as CV_32F
processor = new TypedProcessor<float>(imgPath);
// GOAL: AVOIDING THIS:
//std::cerr << (float)(*std::max_element(processor->workingImage.begin<float>(), processor->workingImage.end<float>())) << std::endl;
break;
case 'i': // input as CV_16U but should be interpreted as CV_16S
processor = new TypedProcessor<short>(imgPath);
processor->workingImage.flags = (processor->workingImage.flags & ~CV_MAT_TYPE_MASK) | CV_16S;
// GOAL: AVOIDING THIS:
//std::cerr << (short)(*std::max_element(processor->workingImage.begin<short>(), processor->workingImage.end<short>())) << std::endl;
break;
default:
break;
}
processor->printMaxElem();
return processor;
}
int main(void){
ImageProcessor *myprocessor = ImageProcessor::NewProcessor('h', "user/will/input/this");
return 0;
}
The errors I am getting are:
In member function ‘void TypedProcessor<datatype>::printMaxElem()’:
test.cpp:35:84: error: expected primary-expression before ‘>’ token
std::cerr << (datatype)(*std::max_element(this->workingImage.begin<datatype>(), this->workingImage.end<datatype>())) << std::endl;
^
test.cpp:35:86: error: expected primary-expression before ‘)’ token
std::cerr << (datatype)(*std::max_element(this->workingImage.begin<datatype>(), this->workingImage.end<datatype>())) << std::endl;
^
I also get equivalent errors for this->workingImage.end<datatype>()
. A very similar error shows up if I replace datatype
with short
(not the functionality I want; just for testing purposes). The variable this->workingImage
is normally visible inside the function as expected (and I can use any variables I declare as protected
inside ImageProcessor
), and the function call passes normally if I change the body.
The errors only arise when I am specifically using any templated access function from OpenCV (the begin
and end
from the example, at
, etc...).
Even more curious, if I uncomment the lines marked by GOAL: AVOIDING THIS
, they compile and execute perfectly. However, this is not an option as the whole point of this structure is to avoid this and implement either data-type-dependant or data-type-specific functions through the use of the templated Derived class.
Note: the functionalities as well as types of images supported in this example are not final. For now, there are only two types of images but this is likely to change in the future. Also, the processing functions will sometimes be the same (except the need to specify a different data type), sometimes they will have a common part and part dependent of the data/image type (e.g. preprocessing requires looping through all the elements, getting the min and max values (common), and then interpolating all the missing values (different approach for my float
and short
images)). Some functionalities will also be encapsulated directly in the Base class (if they do not require data specification, e.g. getting width/height of the image comes to mind).
Does anybody know how to help with correcting the code or achieving the desired functionality?