title: Why is the star (*) operator faster than pointer access multiplication in matrix scaling using OpenCV?
body: <p>I'm trying to learn how to manipulate OpenCV matrix values in the most optimized way. I tried scaling a large image stored in OpenCV matrix four different ways. </p>
  
  <p>1) Using the star <code>*</code> operator</p>
  
  <p>2) Using <code>at</code> function and <code>for</code> loops</p>
  
  <p>3) Using pointer access and <code>for</code> loops</p>
  
  <p>4) Using a lookup table</p>
  
  <p>The rounded results of this experiment were as follows</p>
  
  <p><code>*</code> operator ------- <code>3 ms</code> </p>
  
  <p><code>at</code> function ------- <code>12 ms</code></p>
  
  <p>pointer access ---- <code>9 ms</code></p>
  
  <p>lookup table -------- <code>1 ms</code></p>
  
  <p>Now it is pretty obvious as to why lookup tables are the fastest. But I'm not always going to be able to use them. For the cases that I can't use a lookup table for, I need to understand how OpenCV implements scaling using the <code>*</code> operator so I can use that method as reference in my other matrix value manipulations. </p>
  
  <p>I would very much appreciate it if someone could tell me what happens behind the <code>*</code> operation that makes it faster than the pointer access method?</p>
  
  <p>Please find the following code for your reference. </p>
  
  <p>Thanks,</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;vector&gt;
  #include &lt;opencv2/opencv.hpp&gt;
  #include &lt;chrono&gt;
  
  typedef std::chrono::system_clock Timer;
  typedef std::chrono::duration&lt;double&gt; Duration;
  
  using std::cout;
  using std::endl;
  using std::vector;
  
  double profile(Timer::time_point start, Timer::time_point end) {
      Duration span = end - start;
      return span.count() * 1000;
  }
  
  int main() {
  
      cv::Mat image = cv::imread("../data/large.jpg", 0);
      float sc = 1;
  
      while (true) {
  
          //=================== first method ====================
          Timer::time_point s1 = Timer::now();
          cv::Mat mine = image * sc;
          Timer::time_point s2 = Timer::now();
  
          //=================== second method ====================
          cv::Mat yours(image.size(), image.type());
          Timer::time_point s3 = Timer::now();
          for (int i = 0; i &lt; image.rows; i++) {
              for (int j = 0; j &lt; image.cols; j++) {
                  yours.at&lt;uchar&gt;(i, j) = image.at&lt;uchar&gt;(i, j) * sc;
              }
          }
          Timer::time_point s4 = Timer::now();
  
          //=================== third method ====================
          if (!image.isContinuous()) {
              std::cerr &lt;&lt; "ERROR: image matrix isn't stored as a 1D array" &lt;&lt; endl;
              exit(-1);
          }
          Timer::time_point s5 = Timer::now();
          cv::Mat result(image.size(), image.type());
          for (int i = 0; i &lt; image.rows; i++) {
              for (int j = 0; j &lt; image.cols; j++) {
                  result.data[i * image.cols + j] = image.data[i * image.cols + j] * sc;
              }
          }
          Timer::time_point s6 = Timer::now();
  
          //=================== fourth method ====================
          Timer::time_point s7 = Timer::now();
          cv::Mat lookupTable(1, 256, image.type());
          for (int i = 0; i &lt; 256; i++)
              lookupTable.data[i] = i * sc;
          cv::Mat his;
          cv::LUT(image, lookupTable, his);
          Timer::time_point s8 = Timer::now();
  
  
          cout &lt;&lt; "first = " &lt;&lt; profile(s1, s2) &lt;&lt; endl;
          cout &lt;&lt; "second = " &lt;&lt; profile(s3, s4) &lt;&lt; endl;
          cout &lt;&lt; "third = " &lt;&lt; profile(s5, s6) &lt;&lt; endl;
          cout &lt;&lt; "fourth = " &lt;&lt; profile(s7, s8) &lt;&lt; endl;
          cout &lt;&lt; "=============== " &lt;&lt; endl;
  
      }
  
      return 0;
  }
  </code></pre>