Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang async face detection

I'm using an OpenCV binding library for Go and trying to asynchronously detect objects in 10 images but keep getting this panic. Detecting only 4 images never fails.

var wg sync.WaitGroup

for j := 0; j < 10; j++ {
    wg.Add(1)
    go func(i int) {
        image := opencv.LoadImage(strconv.Itoa(i) + ".jpg")
        defer image.Release()

        faces := cascade.DetectObjects(image)
        fmt.Println((len(faces) > 0))
        wg.Done()
    }(j)
}

wg.Wait()

I'm fairly new to OpenCV and Go and trying to figure where the problem lies. I'm guessing some resource is being exhausted but which one.

like image 252
bradley Avatar asked Sep 10 '14 21:09

bradley


3 Answers

Each time you call DetectObjects the underlying implementation of OpenCV builds a tree of classifiers and stores them inside of cascade. You can see part of the handling of these chunks of memory at https://github.com/Itseez/opencv/blob/master/modules/objdetect/src/haar.cpp line 2002

Your original code only had one cascade as a global. Each new go routine call DetectObjects used the same root cascade. Each new image would have free'd the old memory and rebuilt a new tree and eventually they would stomp on each other's memory use and cause a dereference through 0, causing the panic.

Moving the allocation of the cascade inside the goroutine allocates a new one for each DetectObject call and they do not share any memory.

The fact that it never happened on 4 images, but failed on 5 images is the nature of computing. You got lucky with 4 images and never saw the problem. You always saw the problem on 5 images because exactly the same thing happened each time (regardless of concurrency).

Repeating the same image multiple times doesn't cause the cascade tree to be rebuilt. If the image didn't change why do the work ... an optimization in OpenCV to handle multiple images frames.

like image 149
AndrewN Avatar answered Oct 24 '22 08:10

AndrewN


The problem seemed to be having the cascade as a global variable.

Once I moved
cascade := opencv.LoadHaarClassifierCascade("haarcascade_frontalface_alt.xml")
into the goroutine all was fine.

like image 3
bradley Avatar answered Oct 24 '22 09:10

bradley


You are not handling for a nil image

image := opencv.LoadImage(strconv.Itoa(i) + ".jpg")
if image == nil {
    // handle error
}
like image 2
jmaloney Avatar answered Oct 24 '22 08:10

jmaloney