opencv 4.x新增了forEach的方式遍历像素值,比传统方式略快一些。因为它本身是使用多线程并行的方法来遍历的。从opencv源码能看到这句话:
parallel_for_(cv::Range(0, LINES), PixelOperationWrapper(reinterpret_cast<Mat_<_Tp>*>(this), operation));
写了一个测试用例,把它用起来。包括单通道,三通道,浮点型等cv::Mat的遍历。
#include <iostream>typedef cv::Point3_<uint8_t> Pixel;void test1(cv::Mat &image)
{//raw pointer access.double start = (double)cv::getTickCount();for (int r = 0; r < image.rows; ++r){Pixel *ptr = image.ptr<Pixel>(r, 0);const Pixel *ptr_end = ptr + image.cols;for (; ptr != ptr_end; ++ptr){ptr->x = 255 - ptr->x;ptr->y = 255 - ptr->y;ptr->z = 255 - ptr->z;}}double time = (((double)cv::getTickCount() - start)) / cv::getTickFrequency();printf(" raw pointer access time1 : %.4f seconds\n", time);
}void test2(cv::Mat &image)
{double start = (double)cv::getTickCount();int w = image.cols;int h = image.rows;for (int row = 0; row < h; row++){uchar *uc_pixel = image.data + row * image.step;for (int col = 0; col < w; col++){uc_pixel[0] = 255 - uc_pixel[0];uc_pixel[1] = 255 - uc_pixel[1];uc_pixel[2] = 255 - uc_pixel[2];uc_pixel += 3;}}double time = (((double)cv::getTickCount() - start)) / cv::getTickFrequency();printf(" raw pointer access time2 : %.4f seconds\n", time);
}void test3(cv::Mat &image) //OpenCV中C++11 lambda方式像素遍历,OpenCV4.x开始支持
{//forEach方式的像素遍历,三通道图像//Pixel和 position(分别指该像素的数值信息和位置信息)//使用了x,y,z分别代表该像素点的blue, grean, red这三个通道的颜色值//position是遍历的像素点坐标位置//position[0]=row, position[1]=coldouble start = (double)cv::getTickCount();image.forEach<Pixel>([](Pixel &p, const int *position) -> void {p.x = 255 - p.x;p.y = 255 - p.y;p.z = 255 - p.z;});double time = (((double)cv::getTickCount() - start)) / cv::getTickFrequency();printf(" forEach time3 : %.4f seconds\n", time);
}void test4(cv::Mat &image)
{cv::Mat gray;cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);//遍历单通道图像//position是遍历的像素点坐标位置//position[0]=row, position[1]=colgray.forEach<uint8_t>([](uint8_t &p, const int *position) -> void {p += 1;});
}void test5(cv::Mat &image)
{cv::Mat gray;cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);cv::Mat ft;gray.convertTo(ft, CV_32FC1, 1.0 / 255.0);//多线程并行遍历像素,需要加锁float score = 0.8;std::vector<cv::Point> vtPos;std::vector<float> vtConfidences;std::mutex mtx;ft.forEach<float>([&vtConfidences, &vtPos, &score, &mtx](float &val, const int *position) -> void {if (val > score){mtx.lock();vtPos.emplace_back(cv::Point(position[1], position[0])); //x,y==col,rowvtConfidences.emplace_back(val);mtx.unlock();}});std::cout << vtPos.size() << std::endl;
}int main(int argc, char *argv[])
{cv::Mat image = cv::imread("D:/temp/2-6-11.jpg", cv::IMREAD_COLOR);test1(image);test2(image);test3(image);test4(image);test5(image);return 0;
}