OpenCVの使い方(2) ピクセルへのアクセス方法(5種・data,point,at,pointer,iterator)+速度比較
Sponsored Links
皆さんこんにちは
お元気ですか?私はプレゼン準備でひぃひぃいってます。
さて、今回はOpenCVについてやります。
だいぶご無沙汰してますね。
ところで、皆さんOpenCVを使っていて、ピクセルにアクセスしたいってことありませんでしたか?私は結構ありました。
カラーヒストグラム作ったりLBP(Local Binary Pattern)を作ったりと何かとピクセルに用事がありました。
ということで今回はピクセルへのアクセス方法を紹介するとともに、速度面について比較をしたいと思っています。
ピクセルへのアクセス方法
ポインターを使う
void PixelAccess::pointer(){ for(int height = 0; height < image.rows; height++){ Vec3b *ptr = image.ptr<Vec3b>(height); for(int width = 0; width < image.cols; width++){ Vec3b bgr = ptr[width]; } } }
iteratorを利用する方法
vectorのiteratorは脆弱でしたが、今回はどうか?
void PixelAccess::iterator(){ MatIterator_<Vec3b> itd = image.begin<Vec3b>(),itd_end = image.end<Vec3b>(); for(itd; itd != itd_end; itd++){ Vec3b bgr = (*itd); } }
atを使ったアクセス
void PixelAccess::atData(){ for(int height = 0; height < image.rows; height++){ for(int width = 0; width < image.cols; width++){ Vec3b bgr = image.at<Vec3b>(height,width); } } }
Pointを利用して…
void PixelAccess::execPoint(){ Mat3b dotImg = image; for(int height = 0; height < image.rows; height++){ for(int width = 0; width < image.cols; width++){ Vec3b bgr = dotImg(Point(width,height)); } } }
dataメソッドを使って
void PixelAccess::readData(){ for(int height = 0; height < image.rows; height++){ for(int width = 0; width < image.cols; width++){ for(int channel = 0; channel < image.channels(); channel++){ image.data[height * image.step + width * image.elemSize() + channel]; } } } }
以上の5種類あります。高さと横幅については間違えないでください。実装によっては反対になっています。
速度比較実験
実験内容
それぞれのメンバ関数を1000回回し、比較
また、コンパイルオプションでも比較
g++ pixel_access.cpp `pkg-config --cflags opencv` `pkg-config --libs opencv` g++ -O2 pixel_access.cpp `pkg-config --cflags opencv` `pkg-config --libs opencv`
実験環境
OS:X 10.9.1
CPU:2.8GHz IntelCore i7
メモリ:16GB 1600MHz DDR3
結果
関数 | 速度[ms](No option) | 速度(-O2) |
pointer | 903266 | 3 |
iterator | 2387590 | 134332 |
at | 1130726 | 14 |
Point | 1528948 | 28 |
data | 2058010 | 3 |
結論
ポインター使うのが一番早いが、オプションつけたらdataが早くなるかも…
どの参照方法を使うか迷った時は検討してみはいかがでしょうか?
参考文献
http://minus9d.hatenablog.com/entry/20130126/1359194404
http://d.akiroom.com/2012-06/opencv-pixel-read-write-get-set/
ソースコード全文
#include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/nonfree/nonfree.hpp> using namespace std; using namespace cv; class PixelAccess{ private: Mat image; void pointer(); void iterator(); void atData(); void execPoint(); void readData(); public: PixelAccess(string path); void executeProgram(); }; PixelAccess::PixelAccess(string path){ image = cv::imread(path); } void PixelAccess::pointer(){ for(int height = 0; height < image.rows; height++){ Vec3b *ptr = image.ptr<Vec3b>(height); for(int width = 0; width < image.cols; width++){ Vec3b bgr = ptr[width]; } } } void PixelAccess::iterator(){ MatIterator_<Vec3b> itd = image.begin<Vec3b>(),itd_end = image.end<Vec3b>(); for(itd; itd != itd_end; itd++){ Vec3b bgr = (*itd); } } void PixelAccess::atData(){ for(int height = 0; height < image.rows; height++){ for(int width = 0; width < image.cols; width++){ Vec3b bgr = image.at<Vec3b>(height,width); } } } void PixelAccess::execPoint(){ Mat3b dotImg = image; for(int height = 0; height < image.rows; height++){ for(int width = 0; width < image.cols; width++){ Vec3b bgr = dotImg(Point(width,height)); } } } void PixelAccess::readData(){ for(int height = 0; height < image.rows; height++){ for(int width = 0; width < image.cols; width++){ for(int channel = 0; channel < image.channels(); channel++){ image.data[height * image.step + width * image.elemSize() + channel]; } } } } void PixelAccess::executeProgram(){ void (PixelAccess::*executeCompare[])() = { &PixelAccess::pointer, &PixelAccess::iterator, &PixelAccess::atData, &PixelAccess::execPoint, &PixelAccess::readData }; for(int i = 0; i < 5; i++){ clock_t start = clock(); for(int t = 0; t < 1000; t++){ (this->*executeCompare[i])(); } clock_t end = clock(); cout << end - start << "[ms]" << endl; } } int main(int argc, char const *argv[]){ PixelAccess pixelaccess(argv[1]); pixelaccess.executeProgram(); return 0; }