在对图像进行操作时,免不了要对整个图像进行循环,下面对复制图像的三种不同的遍历方式进行比较
<pre name="code" class="cpp">int _tmain(int argc, _TCHAR* argv[])
{
Mat src = imread("Lena.jpg", 0);
if (src.empty())
{
cout << "failed" << endl;
return -1;
}
imshow("src", src);
// ......
Mat dst(src.size(), src.type());
double start = getTickCount();
for (int r = 0; r < src.rows; r++)
{
const uchar* ps = src.ptr<uchar>(r);
uchar* pd = dst.ptr<uchar>(r);
for (int c = 0; c < src.cols; c++)
{
pd[c] = ps[c];
}
}
double end = getTickCount();
double time = (end - start) / getTickFrequency();
cout << "dst1\t" << time << endl;
imshow("dst1", dst);
int rows = src.rows;
int cols = src.cols;
// ......
dst.setTo(Scalar(0));
start = getTickCount();
if (src.isContinuous() && dst.isContinuous())
{
cols *= rows;
rows = 1;
}
for (int r = 0; r < rows; r++)
{
const uchar* ps = src.ptr<uchar>(r);
uchar* pd = dst.ptr<uchar>(r);
for (int c = 0; c < cols; c++)
{
pd[c] = ps[c];
}
}
end = getTickCount();
time = (end - start) / getTickFrequency();
cout << "dst2\t" << time << endl;
imshow("dst2", dst);
rows = src.rows;
cols = src.cols;
dst.setTo(Scalar(0));
start = getTickCount();
// ......
// 此种遍历方式,在openCV源码中会经常看到
if (src.isContinuous() && dst.isContinuous())
{
cols *= rows;
rows = 1;
}
for (int r = 0; r < rows; r++)
{
const uchar* ps = src.ptr<uchar>(r);
uchar* pd = dst.ptr<uchar>(r);
int c = 0;
for ( ; c < cols - 4; c += 4)
{
pd[c] = ps[c];
pd[c + 1] = ps[c + 1];
pd[c + 2] = ps[c + 2];
pd[c + 3] = ps[c + 3];
}
for ( ; c < cols; c++)
{
pd[c] = ps[c];
}
}
end = getTickCount();
time = (end - start) / getTickFrequency();
cout << "dst3\t" << time << endl;
imshow("dst3", dst);
waitKey();
return 0;
}
下面是相对应的消耗的时间:
可以看出最后一种遍历方式是最快的。
方式2与方式1比较、方式3与方式2比较,存在一个for循环的优化上面,可以参考嵌套For循环性能优化案例。