Open zhlangsas opened 5 years ago
Hello @zhlangsas you should know that as far as I know none of the OpenCV algorithms are re-entrant.
This applies to the CascadeClassifier
. The solution is to create a new instance of the algorithm per goroutine. You would remove this code from your main function:
classifier := gocv.NewCascadeClassifier()
defer classifier.Close()
modelPath := "./haarcascade_frontalface_default.xml"
if !classifier.Load(modelPath) {
panic(fmt.Errorf("Error loading cascade file: %v", modelPath))
}
Then replace your go routine code with something like this (untested) code:
for _, imgBytes := range imgs {
wg.Add(1)
go func(imgBytes []byte) {
classifier := gocv.NewCascadeClassifier()
defer classifier.Close()
modelPath := "./haarcascade_frontalface_default.xml"
if !classifier.Load(modelPath) {
panic(fmt.Errorf("Error loading cascade file: %v", modelPath))
}
img, _, err := image.Decode(bytes.NewReader(imgBytes))
if err != nil {
panic(err)
}
mat, err := gocv.ImageToMatRGB(img)
if err != nil {
panic(err)
}
rects := classifier.DetectMultiScale(mat)
fmt.Println(rects)
wg.Done()
}(imgBytes)
}
Hope that helps!
@deadprogram is there a way to clone the CascadeClassifier
instance instead of having to load from disk each time ? I am experiencing the same here. I tried copying the instance into another variable still getting the same issue.
Also, it's seems like calling classifier.Load(path)
causes a memory leak even if classifier.Close()
is called. I can provide a code sample if needed.
@deadprogram what do you think?
Yes, please provide a code sample. Certainly looks like it should free the classifier on Close()
.
https://github.com/hybridgroup/gocv/blob/0d9b22a6450a7d81761a4b763f58fb99e962ab47/objdetect.cpp#L10
Thanks!
Here is a code sample: https://github.com/zak905/gocv-classifiers-memory-leak-demo
I also added instructions on how to test.
Just on a brief lookover of that code, seems like imageMat
never gets freed:
imageMat, _ := gocv.IMDecode(imageBytes, gocv.IMReadUnchanged)
You might want to try
imageMat, _ := gocv.IMDecode(imageBytes, gocv.IMReadUnchanged)
defer imageMat.Close()
Let me know if that helps.
@deadprogram thanks for checking. With your change it's not leaking memory. In my code, I have some leak even if I close the mat. I must be looking at wrong piece of code.
It turns out gocv.HoughCirclesWithParams
takes forever, and does not terminate if given large images (I tried with two right now), event with different parameters (I tried with various minDistance and radius values). This may be related directly to the behavior of OpenCV, it would be nice if there is a timeout. Is this a good idea for a PR ? we could use a channel / goroutine and if C.HoughCirclesWithParams
or C.HoughCircles
goes beyond some timeout return an error or an empty mat.
Here is an example of an image that causes that https://s3-eu-west-1.amazonaws.com/gwidgets/large_image.jpg it's possible to reproduce by using the image in this test https://github.com/hybridgroup/gocv/blob/master/imgproc_test.go#L648
It turns out, it's not possible to interrupt a cgo call directly, even if I use a channel + select statements, the actual call will still be running and will still be consuming cpu and memory in the background.
The only solution I found is creating a separate executable : calling it directly using cmd
package, and in case it takes more than a certain amount of time, killing it.
More findings: using the same picture with OpenCV 3, does not take forever and does return.
DetectMultiScale panic when used concurrently
Description
When running cascade detection concurrently in goroutines I receive a variety of panics and segmentation faults.
Steps to Reproduce
Your Environment
env.sh
orenv.cmd
script before trying togo run
orgo build
? No