2015-05-11 16 views
8
// 700 ms 
cv::Mat in(height,width,CV_8UC1); 
in /= 4; 

sostituiti con(opencv rc1) Che cosa fa sì che la moltiplicazione di Mat sia 20 volte più lenta della moltiplicazione per pixel?

//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; 
    } 
} 

Che cosa può causare un comportamento del genere? È dovuto all'opencv "promuovere" Mat con moltiplicazione scalare a Mat con moltiplicazione Mat, oppure è una ottimizzazione fallita specifica per il braccio? (NEON è abilitato).

+0

puoi provare in * = 1.0f/4.0; ? non hai inizializzato gli elementi btw – Micka

+0

I risultati della moltiplicazione in virgola mobile sono identici alla divisione in interi fino all'incirca al 20% di incertezza/differenza nei miei test sia per la moltiplicazione per pixel sia per quella per tappetino intero. –

+0

Puoi correre perf? https://perf.wiki.kernel.org/index.php/Main_Page – auselen

risposta

1

Provato lo stesso misurando il tempo della 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 risultati:

value: 255 
1: 0.016 
value: 64 
2: 0.016 
value: 64 
3: 0.003 
value: 63 

si vede che i risultati differiscono, probabilmente perché mat.divide() fa eseguire floating point divisione e arrotondamento al successivo. Mentre si utilizza la divisione intera nella versione più veloce, che è più veloce ma dà un risultato diverso.

Inoltre, c'è un saturate_cast nel calcolo openCV, ma suppongo che la maggiore differenza di carico del calcolo sarà la divisione a doppia precisione.

+0

Puoi aggiungere 4: moltiplicare per 0,25 per elemento? Anche IIRC è stato "veloce" per me, suggerendo che sta accadendo qualcos'altro rispetto alle prestazioni di calcolo del flop/intop. –

+0

sulla mia macchina, la moltiplicazione/divisione di un float è pari a circa 2 volte il tempo della divisione di un carattere non firmato per 4 (che è un bithift btw). Divisione per doppio è uguale a float, che non mi fido di atm :) – Micka

2

Questo è un problema molto vecchio (l'ho segnalato un paio di anni fa) che molte operazioni di base richiedono più tempo. Non solo divisione ma anche addizione, addominali, ecc ... Non conosco la vera ragione di questo comportamento. Ciò che è ancora più strano, è che le operazioni che dovrebbero richiedere più tempo, come addWeighted, sono in realtà molto efficienti. Provate questo:

addWeighted(in, 1.0/4, in, 0, 0, in); 

Si esegue più operazioni per pixel ancora girare alcune volte più veloce di entrambe le funzioni e l'attuazione del ciclo aggiungere.

Ecco il mio report su bug tracker.

+0

Per la mia versione di setup e opencv, addWeighted è ugualmente lento, che è un altro problema. –

+0

Questo è ancora più strano, perché ho appena controllato e ho visto che addWeighted è molto più veloce. Quale versione di OpenCV stai usando? –

+0

Puoi anche fare lo stesso esperimento con qualche altra funzione? abs() per esempio. –

Problemi correlati