Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental/threadcall #21

Merged
merged 5 commits into from
Jul 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions examples/threadcall_detect_in_image.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Images
#Additional required packages to run this example.
#Pkg.add("Images")

using AprilTags

# Simple method to show the image with the tags
function showImage(image, tags)
# Convert image to RGB
imageCol = RGB.(image)
#traw color box on tag corners
foreach(tag->drawTagBox!(imageCol, tag), tags)
imageCol
end


##
# Create default detector
detector = AprilTagDetector()

#Run against a file
image = load(dirname(Base.source_path()) *"/../data/tagtest.jpg")

@sync begin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think this is the right way to do it. Haven't worked with @threadcall before but understand from docs that it is non-blocking.

starttime = Dates.value(now())
#call detector in thread
@async global t1 = @timed begin
println("time before detector $(Dates.value(now())-starttime) ms")
global tags = AprilTags.threadcalldetect(detector, image)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global is slower since Julia optimizes at a per function level. This is fine for testing, but try avoid for general implementation.

# ↑ comment --- compare with this --- uncomment ↓
# global tags = detector(image)
println("time after detector $(Dates.value(now())-starttime) ms")

@show length(tags)
end
#carry on doing something else
@async global t2 = @timed begin
println("time starting other $(Dates.value(now())-starttime) ms")
imageCol = load(dirname(Base.source_path()) *"/../data/colortag.jpg")
A = randn(1000,1000)
randsum = sum(A*A')
println("time finished other $(Dates.value(now())-starttime) ms")
@show randsum
end
end

println("time for detector: $(t1[2]) seconds")
println("time for other: $(t2[2]) seconds")
println()

showImage(image, tags)



## clean up detector once finished
freeDetector!(detector)
31 changes: 31 additions & 0 deletions src/helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,37 @@ function (detector::AprilTagDetector)(image::Array{ColorTypes.RGB{T}, 2}) where
return detector(image)
end

"""
threadcalldetect(detector, image)
Run the april tag detector on a image
"""
function threadcalldetect(detector::AprilTagDetector, image::Array{T, 2}) where T <: U8Types

if detector.td == C_NULL
error("AprilTags Detector does not exist")
end

if detector.tf == C_NULL
error("AprilTags family does not exist")
end
#create image8 object for april tags
image8 = convert(AprilTags.image_u8_t, image)

# run detector on image
detections = threadcall_apriltag_detector_detect(detector.td, image8)

# copy and return detections julia struct
tags = AprilTags.copyAprilTagDetections(detections)
# copy and return detections c struct
# tags = getTagDetections(detections)

#distroy detections memmory
apriltag_detections_destroy(detections)

return tags

end

"""
freeDetector!(apriltagdetector)
Free the allocated memmory
Expand Down
14 changes: 13 additions & 1 deletion src/wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ mutable struct apriltag_detector
nquads::UInt32
tag_families::Ptr{zarray_t}
wp::Ptr{workerpool_t}

# mutex::pthread_mutex_t
mutex::NTuple{40, UInt8}

Expand Down Expand Up @@ -404,6 +404,18 @@ function apriltag_detector_detect(td, im_orig)
ccall((:apriltag_detector_detect, :libapriltag), Ptr{zarray_t}, (Ptr{apriltag_detector_t}, Ptr{image_u8_t}), td, Ref(im_orig))
end

"""
threadcall_apriltag_detector_detect(tag_detector, image)
*Experimental* call apriltag_detector_detect in a seperate thread using the experimantal `@threadcall`
Detect tags from an image and return an array of apriltag_detection_t*.
You can use apriltag_detections_destroy to free the array and the detections it contains, or call
detection_destroy and zarray_destroy yourself.
"""
function threadcall_apriltag_detector_detect(td, im_orig)
@threadcall((:apriltag_detector_detect, :libapriltag), Ptr{zarray_t}, (Ptr{apriltag_detector_t}, Ptr{image_u8_t}), td, Ref(im_orig))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as you are not calling back into Julia from the C implementation (which AprilTags is not doing).
https://docs.julialang.org/en/stable/stdlib/parallel/#ccall-using-a-threadpool-(Experimental)-1

Copy link
Member

@dehann dehann Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end


function apriltag_detection_destroy(det)
ccall((:apriltag_detection_destroy, :libapriltag), Void, (Ptr{apriltag_detection_t},), det)
end
Expand Down
5 changes: 5 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ using Base.Test
@test length(detector(gray.(image))) == 3
@test length(detector(reinterpret(UInt8,image))) == 3

tagsth = AprilTags.threadcalldetect(detector, image)
@test length(tagsth) == 3

#test on random image, should detect zero tags
@test length(detector(rand(Gray{N0f8},100,100))) == 0

Expand Down Expand Up @@ -175,6 +178,7 @@ using Base.Test
detector = AprilTagDetector()
freeDetector!(detector)
@test_throws ErrorException tags = detector(image)
@test_throws ErrorException tags = AprilTags.threadcalldetect(detector, image)
@test_throws ErrorException AprilTags.setnThreads(detector, 4)
@test_throws ErrorException AprilTags.setquad_decimate(detector, 1.0)
@test_throws ErrorException AprilTags.setquad_sigma(detector,0.0)
Expand All @@ -186,6 +190,7 @@ using Base.Test
detector = AprilTagDetector()
detector.tf = C_NULL
@test_throws ErrorException tags = detector(image)
@test_throws ErrorException tags = AprilTags.threadcalldetect(detector, image)
@test freeDetector!(detector) == nothing
end

Expand Down