OpenCV.jl
OpenCV.jl copied to clipboard
[WIP] Using c++ templates
In Ref #16 Adding functionality of templates. Will be updated with the usage of pointers for faster algorithm.
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.
I have added the test cases but couldn't test it locally on my laptop. How about we get travis up and running ?
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.
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);
}
. . .
"""
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 ?
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 Cxx
handles 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;
}
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>
.
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 int
or double
? I thought the whole point is not to worry which type you pass to the function...
Yes, with the implementation of Mat_<_Tp>
, we wouldn't need to specify the type. I'm currently working on this.
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.
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 Int32
for 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);
?
mat = Mat(convert(Int32, _rows), convert(Int32, _cols), CV_8UC3);
I had tried that earlier, but there was no luck with that.
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?
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
That's true on a 64-bit CPU; it's Int32
on a 32-bit CPU. Safest is to use Int
.
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 ?
That's true on a 64-bit CPU; it's
Int32
on a 32-bit CPU. Safest is to useInt
.
What happens when you provide convert(Int, Base.size(img, 1))
and convert(Int, Base.size(img, 2))
?
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)
^
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.
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.