近期編譯了android下支持opencl的opencv,使用opencl能力的關鍵是用cv::UMat替換cv::Mat。
實際使用后發現坑很多,非常不成熟,不推薦使用這種方式來提升實際產品的性能。
- 每個UMat產生的時候會從gpu分配內存,而GPU分配內存是很慢的;使用Mat的時候,這點開銷不值得一提,但是UMat完全不是一回事。因此,UMat一定一定要重用,避免反復分配。
- mat.getUMat()方法很多坑,引用計數的錯誤很難查,至今沒搞明白原理。因此一直用mat.copyTo(umat)來代替。
- mat.copyTo(umat) 和 umat.copyTo(mat)也是很慢的,因此,一定要計算時間大於數據拷貝時間,抵消了拷貝的開銷,使用umat才能帶來性能提升。
- 例如這樣一個函數 cv::cvtColor(umat_in, umat_out),第一次使用是很慢的,因為opencl的核函數編譯很耗時。因此要使用很多次,多到第一次使用的編譯開銷可以忽略。
- 再說核函數編譯的問題:opencv是C風格的,每次調用,核函數都要編譯一次,雖然第二次以后很快,但是這種每次調用都編譯一次核函數沒有意義。
- T-API看起來很好,一套API既支持Mat又支持UMat,但其中的坑是:計算到底用GPU完成的還是CPU完成的,你不知道。例如我使用cv::dft()一樣,傳入的UMat必須按照2的倍數對齊,否則就會退化到用CPU計算。這下大坑就來了——我先mat.copyTo(umat),然后傳給cv::dft(), 函數內部檢測無法用GPU計算后,自動退化成CPU計算,然后內部umat.getMat(), 計算完成后再mat.getUMat,白白多了兩次GPU內存拷貝,加上外部調用又拷貝了兩次,來回有四次GPU內存拷貝。
- opencv的函數都沒有提供opencl的Queue的支持,也就是所有的拷貝和計算無法讓CPU和GPU做到異步。就算GPU分擔了CPU的壓力,但是CPU在等着GPU計算的結果。
- 從opencl支持的源碼風格上看,很可能T-API最初只在intel GPU & AMD GPU上測試,網上的android+opencv+opencl的文章也很少——由此猜測:android下的opencv中的opencl加速,可能並沒有專門針對android平台去測試加速情況。沒有前人證明過這條路可行!
