c++ - grafico - profundidad de un pixel
(opencv rc1) ¿Qué causa que la multiplicación de Mat sea 20 veces más lenta que la multiplicación por píxel? (2)
// 700 ms
cv::Mat in(height,width,CV_8UC1);
in /= 4;
Reemplazado con
//40 ms
cv::Mat in(height,width,CV_8UC1);
for (int y=0; y < in.rows; ++y)
{
unsigned char* ptr = in.data + y*in.step1();
for (int x=0; x < in.cols; ++x)
{
ptr[x] /= 4;
}
}
¿Qué puede causar tal comportamiento? ¿Se debe a que opencv "promociona" Mat con multiplicación escalar a una multiplicación Mat con Mat, o es una optimización fallada específica para el brazo? (NEON está habilitado).
Este es un tema muy antiguo (lo informé hace un par de años) de que muchas operaciones básicas están tomando más tiempo. No solo división sino también suma, abdominales, etc. No sé la razón real de ese comportamiento. Lo que es aún más extraño, es que las operaciones que se supone tardan más tiempo, como addWeighted, en realidad son muy eficientes. Prueba este:
addWeighted(in, 1.0/4, in, 0, 0, in);
Realiza múltiples operaciones por píxel, sin embargo, se ejecuta pocas veces más rápido que la función de agregar y la implementación de bucle.
Aquí está mi informe sobre el rastreador de errores.
Intenté lo mismo midiendo el tiempo de la CPU.
int main()
{
clock_t startTime;
clock_t endTime;
int height =1024;
int width =1024;
// 700 ms
cv::Mat in(height,width,CV_8UC1, cv::Scalar(255));
std::cout << "value: " << (int)in.at<unsigned char>(0,0) << std::endl;
cv::Mat out(height,width,CV_8UC1);
startTime = clock();
out = in/4;
endTime = clock();
std::cout << "1: " << (float)(endTime-startTime)/(float)CLOCKS_PER_SEC << std::endl;
std::cout << "value: " << (int)out.at<unsigned char>(0,0) << std::endl;
startTime = clock();
in /= 4;
endTime = clock();
std::cout << "2: " << (float)(endTime-startTime)/(float)CLOCKS_PER_SEC << std::endl;
std::cout << "value: " << (int)in.at<unsigned char>(0,0) << std::endl;
//40 ms
cv::Mat in2(height,width,CV_8UC1, cv::Scalar(255));
startTime = clock();
for (int y=0; y < in2.rows; ++y)
{
//unsigned char* ptr = in2.data + y*in2.step1();
unsigned char* ptr = in2.ptr(y);
for (int x=0; x < in2.cols; ++x)
{
ptr[x] /= 4;
}
}
std::cout << "value: " << (int)in2.at<unsigned char>(0,0) << std::endl;
endTime = clock();
std::cout << "3: " << (float)(endTime-startTime)/(float)CLOCKS_PER_SEC << std::endl;
cv::namedWindow("...");
cv::waitKey(0);
}
con resultados:
value: 255
1: 0.016
value: 64
2: 0.016
value: 64
3: 0.003
value: 63
verá que los resultados difieren, probablemente porque mat.divide()
realiza la división y el redondeo de coma flotante al siguiente. Mientras usa la división de enteros en su versión más rápida, que es más rápida pero da un resultado diferente.
Además, hay un saturate_cast en el cálculo de openCV, pero supongo que la mayor diferencia de carga de cálculo será la división de doble precisión.