Open jorgevelap opened 3 years ago
He continuado con la extracción de canales para OpenCL. Esta prácticamente funcionando ya a falta de algún detalle. El problema que estoy teniendo es con la clase ChannelsExtractorLUV. Si no entendí mal, utilizando la función de OpenCV cv::cvtColor con el parámetro COLOR_BGR2Luv salen resultados distintos pero debería funcionar. Al probar, es verdad que los canales de U y V aparecen muy parecidos ( con un umbral < 0.2 se pasan los tests), sin embargo el canal correspondiente a la L sale muy diferente (valores mayores a 0.7) y creo que es lo que le está afectando.
Si utilizo las estrategias de OpenCL para gradMag y gradHist, y OpenCV para la extracción de canales, pasa las pruebas de BadacostDetector.
He seguido con las pruebas de velocidad de OpenCL. He visto que en las pruebas realizadas previamente había un error. Al final he ido paso a paso y he visto que lo que más estaba relentizando era por la forma de hacer la conversión a CV_32F, si se hace la conversión del cv::Umat no lo hace correctamente. Hay que convertir el cv::Mat a CV_32F y luego obtener el UMat. En el programa que he realizado para probar esto, he ido siguiendo los pasos de ChannelsExtractorGradMag. Para un bucle de 1000 iteraciones, los resultados son: 1225.54ms con UMat 2705.35ms con Mat
En caso de no realizar bucle, el resultado es:
4.65811ms con UMat 7.03705ms con Mat
La imagen de salida en ambos casos es la misma.
Con respecto a las últimas pruebas que comentamos, de intentar que los valores de las imagenes sean un entero en lugar de CV_32F, he continuado trabajando con ello y me está dando problemas. No consigo mejorar mucho la velocidad, pero especificamente funciones com sqrt() y phase() indican que necesitan una imagen en CV_32F o CV_64F. Un ejemplo es en el siguiente caso, si I es un UMat:
cv::filter2D(I, Gx, -1, k_horiz); cv::filter2D(I, Gy, -1, k_horiz.t());
cv::multiply(Gx, Gx, Gx2); cv::multiply(Gy, Gy, Gy2); cv::add(Gx2, Gy2, M); //M.convertTo(M, CV_32F); cv::sqrt(M, M);
Entonces está claro que necesitamos CV_32F en algunos casos. Y visto que no va más rápido, es probable que la estrategia de pasar a enteros no nos hace ganar mucho.
¿Qué pasa si intentas acelerar el trozo de código anterior (el de la magnitud del gradiente) en una función C++ separada? Lo mismo de esa manera logramos comprender cómo hacerlo funcionar rápido.
Estos días debido a las vacaciones y las nevadas no he podido hacer esta prueba ya que tengo el entorno Ubuntu con la GPU en el ordenador del trabajo.
Para seguir probando, en mi ordenador de Windows he estado instalando todo para poder utilizar la GPU con Visual Studio. Al realizar los test, he comprobado que las versiones con OpenCL son mas rápidas que las de OpenCV (en torno a 10 veces con Visual Studio y Windows) utilizando CV_32F. El problema es que la velocidad de OpenCL en Windows sigue siendo mas lenta que con OpenCV en Ubuntu, por lo que esta prueba (creo) que puede ayudar para indicar que el código va por el buen camino, pero poco más.
Voy a hacer la prueba que me comentas para intentar acelerar la magnitud del gradiente ahora que ya dispongo del ordenador con el que estaba trabajando en la GPU.
Gracias y un saludo.
Yo he estado haciendo pruebas también. Parece que consigo hacer que vaya más rápido OpenCL (con mi GPU intel) con imágenes grandes en color, pero no con las de grises (unos pocos milisegundos más lento).
Le dedicamos un poco más de tiempo a intentar acelerar, pero si no lo conseguimos cerramos el trabajo aquí.
¿Has tenido que cambiar mucha parte del código para conseguir que funcionara más rápido? Por saber si el código iba bien o hay muchas cosas que corregir.
Vale, yo acabo de hacer la prueba de intentar acelerar el trozo de código: cv::filter2D(I, Gx, -1, k_horiz); cv::filter2D(I, Gy, -1, k_horiz.t());
cv::multiply(Gx, Gx, Gx2); cv::multiply(Gy, Gy, Gy2); cv::add(Gx2, Gy2, M); //M.convertTo(M, CV_32F); cv::sqrt(M, M);
y si lo pongo en un fichero que solo haga eso, tarda en torno a 0.9 ms en ejecutarlo, mientras que en la ejecución del código dentro de ChannelsExtractorGradMagOpenCL tarda en torno a 1.0ms, no hay mucha diferencia.
¿Has probado con una imagen grande? Prueba con coches3, esa es grande y ahí es donde se tiene que ver la diferencia.
He cambiado el código para ir dejando los channels extractors para que les entre la imagen en cv::Mat. Quería ver si podía llegar a código que fuese la mínima expresión antes que poner un montón de código en UMat y no saber por dónde estaban los fallos.
La imagen con la que realizaba las pruebas era un poco más pequeña (1242 x 375). He cambiado la imagen por la que me dices pero sigo obteniendo resultados muy parecidos, pero OpenCL continua siendo un poco más lento. Con OpenCV tarda de media para una imagen 250ms, mientras que OpenCL 270ms.
He añadido una nueva estrategia para ChannelsPyramid que no usa un bucle sino que utiliza una imagen grande, pone todas las imágenes de la pirámide en ella y hace una única llamada a extraer canales. Desgraciadamente en mi GPU intel no es más rápido hacer un bucle e ir redimensionando y calculando canales para cada imagen usando UMat (T-API).
Todo está subido.
Vale, yo ahora no tengo el ordenador con GPU para poder probarlo, en cuanto pueda pruebo con GPU a ver si funciona a mayor velocidad.
Buenas tardes,
Estoy realizando las pruebas con la nueva estrategia de ChannelsPyramid pero por el momento no consigo que funcione correctamente, pues es mucho mas lento que el resto de las estrategias.
Utilizando una imagen grande ([3264 x 1840]), está tardando en torno a 2.5 segundos en realizar el cálculo, mientras que con la estrategia "approximated" utilizando "pdollar" tarda 0.82 ms en realizar el cálculo de píramides.
No se si estaré realizando algo mal, para esto he creado una funcion en TestChannelsPyramid. Comparando, en TestChannelsExtractorGradMag, con una imagen grande [3264 x 1840], si que me aparecen mejores resultados, obteniendo en torno a 112ms con OpenCL y 215ms con OpenCV.
He utilizado los otros métodos de cálculo de estrategia, ya que he caido que esto debe utilizar OpenCL pero los resultados obtenidos siguen sin ser buenos, pues me aparece mas tiempo que en las pruebas anteriores.
He realizado varias pruebas y parece que OpenCL funciona, instalando todo de nuevo y utilizando la version 4 de OpenCV.
Uno de los ejemplos es el siguiente:
cv::UMat img, gray; img = cv::imread( "006733.png", cv::IMREAD_COLOR ).getUMat( cv::ACCESS_READ ); //cv::Mat img, gray; //img = cv::imread( "006733.png", cv::IMREAD_COLOR ); auto startLoad = std::chrono::system_clock::now(); for(int i = 0; i < 100; i++){ cvtColor(img, gray, cv::COLOR_BGR2GRAY); cv::GaussianBlur(gray, gray,cv::Size(7, 7), 1.5); Canny(gray, gray, 0, 50); } auto endLoad = std::chrono::system_clock::now(); std::chrono::duration<float,std::milli> durationLoad = endLoad - startLoad; std::cout << durationLoad.count() << "ms " << std::endl; cv::imshow("edges", gray); cv::waitKey();
Cuando ejecuto el código de ejemplo utilizando cv::UMat , tarda 73ms en ejecutar. Sin embargo al utilizar cv::Mat, la ejecución tarda 146ms en ejecutar.
Además, ejecutando un codigo que detecta la GPU y versión me retorna lo siguiente:
1 GPU devices are detected. name : GeForce GTX 1050 available : 1 imageSupport : 1 OpenCL_C_Version : OpenCL C 1.2
OpenCV version : 4.5.0-dev Major version : 4 Minor version : 5 Subminor version : 0
Por lo que creo que la instalación es correcta.
Tras esto, he modificado la función gradMagOpenCV para que utilice cv::UMat, modificando varias operaciones (la nueva clase ChannelsExtractorGradMagOpenCL está ya en github), sin embargo, comparando las ejecuciones tarda con OpenCL 2.0 ms mientras que con opencv 0.25 ms. Estoy intentando detectar a que se debe esto pero no consigo ver si hay alguna cosa mal.