maxruby / OpenCV.jl

The OpenCV (C++) interface for Julia
Other
105 stars 28 forks source link

[WIP] Using c++ templates #18

Open kvmanohar22 opened 7 years ago

kvmanohar22 commented 7 years ago

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

maxruby commented 7 years ago

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.

kvmanohar22 commented 7 years ago

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

maxruby commented 7 years ago

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 commented 7 years ago

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);
      }
. . .
"""
kvmanohar22 commented 7 years ago

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 ?

maxruby commented 7 years ago

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;
}         
kvmanohar22 commented 7 years ago

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>.

maxruby commented 7 years ago

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...

kvmanohar22 commented 7 years ago

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

kvmanohar22 commented 7 years ago

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.

maxruby commented 7 years ago

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);?

kvmanohar22 commented 7 years ago

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

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

maxruby commented 7 years ago

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?

kvmanohar22 commented 7 years ago

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
timholy commented 7 years ago

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

kvmanohar22 commented 7 years ago

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 ?

maxruby commented 7 years ago

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))?

kvmanohar22 commented 7 years ago

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)
     ^
maxruby commented 7 years ago

See the following posts (old but still relevant)

maxruby commented 7 years ago

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.