1

I am trying to write code to convert an opencv image to a QImage. I want to implement this as a generic function using templates. This is what I have:

#include <QImage>
#include <opencv2/core/core.hpp>

void setPixel(int j, int i, unsigned char v, QImage & img)
{
    img.setPixel(j, i, qRgb(v, v, v)); 
}        

void setPixel(int j, int i, cv::Vec3b v, QImage & img)
{
    img.setPixel(j, i, qRgb(v[2], v[1], v[0]));
}

template <typename ImageType>
QImage toQImageARGB (const cv::Mat & image)
{
    QImage res(image.cols, image.rows, QImage::Format_ARGB32_Premultiplied);
    ImageType tmp;
    for (int i = 0; i < image.rows; ++i)
    {   
        for (int j = 0; j < image.cols; ++j)
        {   
            tmp = image.at<ImageType>(i,j);
            setPixel(j, i, tmp, res); 
        }   
    }   
    return res;
}

I get the following compile time error

CMakeFiles/annotate.dir/main.cpp.o: In function `std::remove_reference<cv::ximgproc::SuperpixelSEEDS*&>::type&& std::move<cv::ximgproc::SuperpixelSEEDS*&>(cv::ximgproc::SuperpixelSEEDS*&)':
.../util.h:8: multiple definition of `setPixel(int, int, unsigned char, QImage&)'
CMakeFiles/annotate.dir/moc_widget.cxx.o:.../build/../util.h:8: first defined here
CMakeFiles/annotate.dir/main.cpp.o: In function `cv::Vec<unsigned char, 3> const& cv::Mat::at<cv::Vec<unsigned char, 3> >(int, int) const':
.../util.h:13: multiple definition of `setPixel(int, int, cv::Vec<unsigned char, 3>, QImage&)'
CMakeFiles/annotate.dir/moc_widget.cxx.o:.../build/../util.h:13: first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [...] Error 1
make[1]: *** [CMakeFiles/annotate.dir/all] Error 2
make: *** [all] Error 2

from my main method.

Is it possible to do this with function templates, and does it make sense?

fuji
  • 1,173
  • 1
  • 10
  • 27

1 Answers1

2

It seems those function definitions (in particular, the two non-template overloads of setPixel()) come from a header file that gets included into more than one translation unit (i.e. .cpp file), thus violating the One Definition Rule.

If you want those functions' definitions to appear in the header file, declare them as inline:

inline void setPixel(int j, int i, unsigned char v, QImage & img)
{
    img.setPixel(j, i, qRgb(v, v, v)); 
}        

inline void setPixel(int j, int i, cv::Vec3b v, QImage & img)
{
    img.setPixel(j, i, qRgb(v[2], v[1], v[0]));
}
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • I am wrapping the `util.h` header file in my `CMakeLists.txt`. It also has the `#ifndef` guards. I added the complete compile error. – fuji Jan 23 '15 at 11:28
  • 1
    @j.dog: First of all, those errors do not come from the compiler, but from the linker. Secondly, header guards do not protect you from multiple inclusions of function definitions from different .cpp files. For more information, see the second question/answer in [this post](http://stackoverflow.com/questions/14909997/why-arent-my-include-guards-preventing-recursive-inclusion-and-multiple-symbol). To fix the problem, just declare those functions as `inline`, or move their definition to a .cpp file (while leaving the declarations only in the header). – Andy Prowl Jan 23 '15 at 11:32