OpenCV.jl icon indicating copy to clipboard operation
OpenCV.jl copied to clipboard

[WIP] Using c++ templates

Open kvmanohar22 opened this issue 8 years ago • 20 comments

In Ref #16 Adding functionality of templates. Will be updated with the usage of pointers for faster algorithm.

kvmanohar22 avatar Mar 03 '17 23:03 kvmanohar22

Nice to see such a quick start! Please see my comments in #17. Please remember to write tests to demonstrate that these new methods indeed work with Templates.

maxruby avatar Mar 04 '17 17:03 maxruby

I have added the test cases but couldn't test it locally on my laptop. How about we get travis up and running ?

kvmanohar22 avatar Mar 04 '17 21:03 kvmanohar22

Sure, we can get Travis CI running, but you and I should definitely be able to test everything locally first. I am looking into the error you reported with dlopen_e in #17. I think I have seen this before.

maxruby avatar Mar 04 '17 22:03 maxruby

I have now built the latest julia-0.6.0 master, tested Cxx.jl and OpenCV.jl, solved several issues relevant to moving this forward. I will push the commits today and then you can work with the latest version of OpenCV.jl.

In the meantime, I wanted to note that I had already implemented templates for std::vector containers in OpenCV.jl and used them effectively too :) See OpenCV_util.jl

# C++ std::vector class thin-wrappings for Julia
cxx"""
template <typename T>
    std::vector<T> stdvector(int size, T x)
      {
        std::vector<T> cppvec(size, x);
        return (cppvec);
      }
. . .
"""

maxruby avatar Mar 05 '17 09:03 maxruby

I came up with a different approach to deal with this error :

@cxx ptr_val(img, 10, 10) :1:1: error: no matching function for call to 'ptr_val' ^ __cxxjl_87.cpp:3:11: note: candidate template ignored: couldn't infer template argument 'T1' inline T1 ptr_val(cv::Mat &img, int row, int col) ^

something like this in src/OpenCV_Mat.jl :

  # Grayscale and binary images
  if (cvtypeval(img) == CV_8UC1)
    @cxx ptr_val<unsigned char>(img, row, col, value);
  elseif (cvtypeval(img) == CV_16SC1)
    @cxx ptr_val<short>(img, row, col, value);
  elseif (cvtypeval(img) == CV_32SC1)
    @cxx ptr_val<unsigned short>(img, row, col, value);
  elseif (cvtypeval(img) == CV_32FC1)
    @cxx ptr_val<float>(img, row, col, value);
  elseif (cvtypeval(img) == CV_64FC1)
    @cxx ptr_val<double>(img, row, col, value);

but this seems not to be supported yet in Cxx . I get the following error for a sample function :

julia> cxx""" #include <iostream>
       template <typename T>
       inline void _sum(int const& a, int const& b){
           T val = 0;
           val += static_cast<T>(a);
           val += static_cast<T>(b);
           
           std::cout<<val<<std::endl;
       }
       """
true

julia> @cxx _sum<int>(2,3);
ERROR: Unrecognized CPP Expression _sum < int > (2, 3) (comparison)

Simultaneously I'm working on implementing cv::Mat_<_Tp>. I think both these implementations accomplish the same. Any suggestions how to take this forward ?

kvmanohar22 avatar Mar 10 '17 07:03 kvmanohar22

Did you try the following?

cxx""" #include <iostream>
       template <typename T>
       inline void _sum(T const& a, T const& b){
           T val = static_cast<T>(0);
           val += static_cast<T>(a);
           val += static_cast<T>(b);         
           std::cout<<val<<std::endl;
       }
"""

and this one might be tricky because I am not sure how Cxxhandles img.at<T>

template <typename T>
inline void ptr_val(cv::Mat &img, int row, int col, T val)
{		  
    T value = static_cast<T>(val);
    img.at<T>(row, col) = value;
}		  

maxruby avatar Mar 10 '17 08:03 maxruby

Did you try the following?

Yep, that works. The only problem is when we don't specify the type in the arguements list.

In the case of extending functionality of Cxx to support,

 julia> @cxx _sum<int>(2,3);

we can address the present issue with the above type of implementation without the need of implementing Mat_<_Tp>.

kvmanohar22 avatar Mar 10 '17 08:03 kvmanohar22

Yep, that works. The only problem is when we don't specify the type in the arguements list.

Good to know. But the question is why do we need to specify in advance that you are passing an intor double? I thought the whole point is not to worry which type you pass to the function...

maxruby avatar Mar 10 '17 10:03 maxruby

Yes, with the implementation of Mat_<_Tp>, we wouldn't need to specify the type. I'm currently working on this.

kvmanohar22 avatar Mar 10 '17 11:03 kvmanohar22

I'm coming across an unusual error :

function convertToMat(image)
    img = permuteddimsview(channelview(image), (2,3,1))
    cd = Base.size(channelview(image))[1] > 3 ? 1 : 3
    _rows = Base.size(image, 1)
    _cols = Base.size(image, 2)

    if (typeof(img[1,1,1].i) == UInt8)
       if (cd == 3) 
         mat = Mat(_rows, _cols, CV_8UC3);
       end
    end
end

I get the following error which is something unexpected.

:1:1: error: no matching constructor for initialization of 'cv::Mat'
^
/usr/local/include/opencv2/core/mat.inl.hpp:339:6: note: candidate constructor not viable: no known conversion from 'long *' to 'int' for 2nd argument; dereference the argument with *
Mat::Mat(int _rows, int _cols, int _type)
     ^

I could boil down the error to this, Base.size(image, 1) and Base.size(image, 2) is causing the error. This was evident when I replaced _rows and _cols with 512, 512 in the Mat() constructor.

kvmanohar22 avatar Mar 17 '17 01:03 kvmanohar22

I don't have access now to my julia/openCV.jl setup, but the error clearly says that long * cannot be used instead of int for the 2nd argument. To me it seems to suggest that Base.size is returning an Int64 instead of an expected Int32for the covertToMat function to work. I am not sure if this will fix the error, but can you test mat = Mat(convert(Int32, _rows), convert(Int32, _cols), CV_8UC3);?

maxruby avatar Mar 17 '17 07:03 maxruby

mat = Mat(convert(Int32, _rows), convert(Int32, _cols), CV_8UC3);

I had tried that earlier, but there was no luck with that.

kvmanohar22 avatar Mar 17 '17 08:03 kvmanohar22

OK. Let me try to understand better the problem. Can you check what type exactly does Base.size(image, 1) return in the julia REPL? And if you convert to Int32 using convert, what does it show?

maxruby avatar Mar 17 '17 08:03 maxruby

what type exactly does Base.size(image, 1) return

Int64

convert to Int32 using convert

test 6: Conversion of images from Images.jl to OpenCV Mat
ERROR: LoadError: LoadError: MethodError: no method matching Mat(::Int32, ::Int32, ::Int64)
Closest candidates are:
  Mat(::Any, !Matched::Int64, ::Any) at /home/kv/.julia/v0.6/OpenCV/./src/OpenCV_core.jl:368
  Mat(::Any, ::Any) at /home/kv/.julia/v0.6/OpenCV/./src/OpenCV_core.jl:385
  Mat(!Matched::Int64, !Matched::Ptr{Int64}, ::Int64) at /home/kv/.julia/v0.6/OpenCV/./src/OpenCV_core.jl:375
  ...
Stacktrace:
 [1] convertToMat(::Array{ColorTypes.RGB{FixedPointNumbers.Normed{UInt8,8}},2}) at /home/kv/.julia/v0.6/OpenCV/./src/OpenCV_ImagesSupport.jl:17
 [2] test6() at /home/kv/.julia/v0.6/OpenCV/./test/jl/tests.jl:146
 [3] include_from_node1(::String) at ./loading.jl:539
 [4] include(::String) at ./sysimg.jl:14
 [5] include_from_node1(::String) at ./loading.jl:539
 [6] include(::String) at ./sysimg.jl:14
 [7] process_options(::Base.JLOptions) at ./client.jl:305
 [8] _start() at ./client.jl:371
while loading /home/kv/.julia/v0.6/OpenCV/./test/jl/tests.jl, in expression starting on line 149
while loading /home/kv/gsoc/OpenCV.jl/test/runtests.jl, in expression starting on line 6

kvmanohar22 avatar Mar 17 '17 08:03 kvmanohar22

That's true on a 64-bit CPU; it's Int32 on a 32-bit CPU. Safest is to use Int.

timholy avatar Mar 17 '17 08:03 timholy

but I don't get any errors while doing mat = Mat(512, 512, CV_8UC3) the problem is only when I deduce the size using Base.size() and use it in the function : mat = Mat(_rows, _cols, CV_8UC3). I'm unable to figure out why ?

kvmanohar22 avatar Mar 17 '17 08:03 kvmanohar22

That's true on a 64-bit CPU; it's Int32 on a 32-bit CPU. Safest is to use Int.

What happens when you provide convert(Int, Base.size(img, 1)) and convert(Int, Base.size(img, 2))?

maxruby avatar Mar 17 '17 09:03 maxruby

What happens when you provide convert(Int, Base.size(img, 1)) and convert(Int, Base.size(img, 2))?

I get the following error :

:1:1: error: no matching constructor for initialization of 'cv::Mat'
^
/usr/local/include/opencv2/core/mat.inl.hpp:339:6: note: candidate constructor not viable: no known conversion from 'long *' to 'int' for 2nd argument; dereference the argument with *
Mat::Mat(int _rows, int _cols, int _type)
     ^

kvmanohar22 avatar Mar 17 '17 11:03 kvmanohar22

See the following posts (old but still relevant)

  • http://bytefish.de/blog/opencv/code_snippets/
  • http://stackoverflow.com/questions/11511715/opencv-indexing-through-mat-of-unknowna-type.

maxruby avatar Mar 17 '17 22:03 maxruby

I found a solution for conversion of image arrays from JuliaImages to Mat using templates and have written wrappers to test it. The key is to use cv::DataType<T>::type when constructing cv::Mat because otherwise you always need to specify the image type, e.g., CV_8UC1. I will first commit this tonight, then we can look into the next steps.

maxruby avatar Mar 19 '17 16:03 maxruby