日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁(yè) > > 充電吧
[導(dǎo)讀]歡迎轉(zhuǎn)載,尊重原創(chuàng),所以轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/bendanban/article/details/30527785本文講述了OpenCV中幾種訪問(wèn)矩陣元素的方法,在

歡迎轉(zhuǎn)載,尊重原創(chuàng),所以轉(zhuǎn)載請(qǐng)注明出處:

http://blog.csdn.net/bendanban/article/details/30527785


本文講述了OpenCV中幾種訪問(wèn)矩陣元素的方法,在指定平臺(tái)上給出性能比較,分析每種矩陣元素訪問(wèn)方法的代碼復(fù)雜度,易用性。


一、預(yù)備設(shè)置

本文假設(shè)你已經(jīng)正確配置了OpenCV的環(huán)境,為方便大家實(shí)驗(yàn),在文中也給出了編譯源程序的Makefile,其內(nèi)容如代碼段1所示。

采用如代碼段2所示的計(jì)時(shí)函數(shù),這段代碼你可以在我之前的博文中找到,abtic() 可以返回微秒(10^-6秒)級(jí),而且兼容WindowsLinux系統(tǒng)。

本文使用彩色圖像做實(shí)驗(yàn),所以矩陣是2維的3通道的。

CC = g++ 
CPPFLAGS = -O3 `pkg-config --cflags opencv` 
CPPLIB   = `pkg-config --libs opencv`

OBJS = test.o 

main.exe : $(OBJS)
  $(CC) $(CPPFLAGS) $^ -o $@ $(CPPLIB)

test.o: test.cpp
  $(CC) -c $(CPPFLAGS) $^ -o $@

clean:
  rm -rf *.out main.exe *.o

run:
  ./main.exe
代碼段 1. Makefile文件的內(nèi)容


#if defined(_WIN32) && defined(_MSC_VER)
#include 
double abtic() {
  __int64 freq;
  __int64 clock;
  QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );
  QueryPerformanceCounter( (LARGE_INTEGER *)&clock );
  return (double)clock/freq*1000*1000;
}
#else
#include 
#include 
double abtic() {
  double result = 0.0;
  struct timeval tv;
  gettimeofday( &tv, NULL );
  result = tv.tv_sec*1000*1000 + tv.tv_usec;
  return result;
}
#endif /* _WIN32 */
代碼段 2. 計(jì)時(shí)函數(shù)abtic()的定義


二、測(cè)試算法

??? 文中用于測(cè)試的算法:將矩陣中每個(gè)元素乘以一個(gè)標(biāo)量,寫(xiě)入一個(gè)新的矩陣,每個(gè)通道操作獨(dú)立。

??? 如果用im(r,c,k)表示矩陣im的第r行、第c列、第k個(gè)通道的值的話(huà),算法為:om(r,c,k) = im(r,c,k)*scale;其中scale是一個(gè)大于0、小于1的浮點(diǎn)數(shù)。


三、五種Mat元素的訪問(wèn)方法


方法1、使用Mat的成員函數(shù)at<>()

??? Mat的成員函數(shù)at()是一個(gè)模板函數(shù),我們這里用的是二維矩陣,所以我們使用的at()函數(shù)的聲明如代碼段3所示(取自OpenCV的源文件)。

template _Tp& at(int i0, int i1);
代碼段3 .at()函數(shù)的聲明


??? 代碼段4是本文第二部分描述的算法的實(shí)現(xiàn),矩陣元素使用at<>()函數(shù)來(lái)索引。

  Vec3b pix;
  for (int r = 0; r < im.rows; r++)
  {
    for (int c = 0; c < im.cols; c++)
    {   
      pix = im.at(r,c);
      pix = pix*scale;
      om.at(r,c) = pix;
    }   
  }
代碼段4. 使用at<>()函數(shù)訪問(wèn)矩陣元素

??? 注意:使用at函數(shù)時(shí),應(yīng)該知道矩陣元素的類(lèi)型和通道數(shù),根據(jù)矩陣元素類(lèi)型和通道數(shù)來(lái)確定at函數(shù)傳遞的類(lèi)型,代碼段4中使用的是Vec3b這個(gè)元素類(lèi)型,他是一個(gè)包含3個(gè)unsigned char類(lèi)型向量。之所以采用這個(gè)類(lèi)型來(lái)接受at的返回值,是因?yàn)椋覀兊木仃噄m是3通道,類(lèi)型為unsigned char類(lèi)型的。


方法2、使用Mat的成員函數(shù)ptr<>()

??? 此函數(shù)也是模板函數(shù),我們將會(huì)用到的ptr函數(shù)聲明如代碼段5所示。此函數(shù)返回指定的數(shù)據(jù)行的首地址。

template _Tp* ptr(int i0=0);
代碼段 5. ptr成員函數(shù)的聲明

??? 使用ptr<>()成員函數(shù)完成本文第二部分所述算法的代碼如代碼段6所示。

  Vec3b *ppix_im(NULL);
  Vec3b *ppix_om(NULL);
  for (int r = 0; r < im.rows; r++)
  {
    ppix_im = im.ptr(r);
    ppix_om = om.ptr(r);
    for (int c = 0; c < im.cols; c++)
    {
       ppix_om[c] = ppix_im[c]*scale;
    }
  }
代碼段 6. 使用ptr訪問(wèn)矩陣元素


方法3、使用迭代器

??? 這里使用的迭代器是OpenCV自己定義的。使用迭代器完成第二部分所述算法的代碼如代碼段7所示。

  MatIterator_ it_im, itEnd_im;
  MatIterator_ it_om;
  it_im    = im.begin();
  itEnd_im = im.end();
  it_om    = om.begin();
  for (; it_im != itEnd_im; it_im++, it_om++)
  {
    *it_om = (*it_im)*scale;
  }
代碼段 7. 使用迭代器訪問(wèn)矩陣元素


方法4、使用Mat_簡(jiǎn)化索引

??? Mat_這個(gè)類(lèi)的元素訪問(wèn)比較容易一點(diǎn),把原Mat類(lèi)的對(duì)象可以直接賦值給Mat_對(duì)象,當(dāng)然賦值操作并不會(huì)開(kāi)辟新的數(shù)據(jù)空間,這點(diǎn)大家放心。也就是說(shuō)使用Mat_時(shí),不會(huì)在內(nèi)存拷貝上花時(shí)間。使用這種方法完成第二部分所述算法的代碼如代碼段8所示。

  Mat_ im_, om_;
  im_ = im;
  om_ = om;
  for (int r = 0; r < im.rows; r++)
  {
    for (int c = 0; c < im.cols; c++)
    {
      om_(r,c) = im_(r,c) * scale;
    }
  }
代碼段 8. 使用Mat_訪問(wèn)矩陣數(shù)據(jù)元素


方法5、使用OpenCV原有的實(shí)現(xiàn)

??? 我們的算法實(shí)際上OpenCV中已經(jīng)有實(shí)現(xiàn)。就是×運(yùn)算符重載,代碼如代碼段9所示。

om = im*scale;
代碼段 9. 使用OpenCV的原有實(shí)現(xiàn)訪問(wèn)矩陣元素


四、實(shí)驗(yàn)測(cè)試1、測(cè)試代碼

??? 為了測(cè)試方便,將前面的方法統(tǒng)一寫(xiě)到一個(gè)c++源文件test.cpp中,其內(nèi)容如代碼段10所示。

/*************************************************************************
  > File Name: test.cpp
  > Author: aban
  > Mail: sawpara@126.com 
  > Created Time: 2014年06月13日 星期五 18時(shí)47分19秒
 ************************************************************************/


#include 
#include 
using namespace cv;
using namespace std;

#if defined(_WIN32) && defined(_MSC_VER)
#include 
double abtic() {
	__int64 freq;
	__int64 clock;
	QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );
	QueryPerformanceCounter( (LARGE_INTEGER *)&clock );
	return (double)clock/freq*1000*1000;
}
#else
#include 
#include 
double abtic() {
	double result = 0.0;
	struct timeval tv;
	gettimeofday( &tv, NULL );
	result = tv.tv_sec*1000*1000 + tv.tv_usec;
	return result;
}
#endif /* _WIN32 */

#define ISSHOW 0

int main(int argc, char** argv)
{
	double tRecorder(0.0);
	Mat im = imread("./bigim.tif");
	Mat om;
	om.create(im.rows, im.cols, CV_8UC3);

#if ISSHOW
	imshow("orignal Image", im);
	waitKey();
#endif
	
	float scale = 150.0f/255.0f;

	// 1. using at()
	tRecorder = abtic();
	Vec3b pix;
	for (int r = 0; r < im.rows; r++)
	{
		for (int c = 0; c < im.cols; c++)
		{
			pix = im.at(r,c);
			pix = pix*scale;
			om.at(r,c) = pix;
		}
	}
	cout << (abtic() - tRecorder) << " using at<>()" << endl;
#if ISSHOW
	imshow("Scaled Image: using at<>()", om);
	waitKey();
#endif

	// 2. using ptr
	tRecorder = abtic();
	Vec3b *ppix_im(NULL);
	Vec3b *ppix_om(NULL);
	for (int r = 0; r < im.rows; r++)
	{
		ppix_im = im.ptr(r);
		ppix_om = om.ptr(r);
		for (int c = 0; c < im.cols; c++)
		{
			 ppix_om[c] = ppix_im[c]*scale;
		}
	}
	cout << (abtic() - tRecorder) << " using ptr<>() " << endl;
#if ISSHOW
	imshow("Scaled Image: using ptr<>()", om);
	waitKey();
#endif

	// 3. using iterator
	tRecorder = abtic();
	MatIterator_ it_im, itEnd_im;
	MatIterator_ it_om;
	it_im    = im.begin();
	itEnd_im = im.end();
	it_om    = om.begin();
	for (; it_im != itEnd_im; it_im++, it_om++)
	{
		*it_om = (*it_im)*scale;
	}
	cout << (abtic() - tRecorder) << " using iterator " << endl;
#if ISSHOW
	imshow("Scaled Image: using iterator", om);
	waitKey();
#endif

	// 4. using Mat_
	tRecorder = abtic();
	Mat_ im_, om_;
	im_ = im;
	om_ = om;
	for (int r = 0; r < im.rows; r++)
	{
		for (int c = 0; c < im.cols; c++)
		{
			om_(r,c) = im_(r,c) * scale;
		}
	}
	cout << (abtic() - tRecorder) << " using Mat_ " << endl;
#if ISSHOW
	imshow("Scaled Image: using Mat_", om);
	waitKey();
#endif

	// 5. using *
	tRecorder = abtic();
	om = im*scale;
	cout << (abtic() - tRecorder) << " using * " << endl;
#if ISSHOW
	imshow("Scaled Image: using *", om);
	waitKey();
#endif

	return 0;
}
代碼段10. 測(cè)試代碼

??? 如果你想使用第一部分提到的Makefile,你需要將代碼段10保存成test.cpp,或者保存成你希望的某個(gè)名字,但是同時(shí)應(yīng)該修改Makfile中的所有“test.cpp”。

??? 在正確執(zhí)行之前,將代碼段10中的第40行代碼改成你的圖片名稱(chēng)。


2、實(shí)驗(yàn)平臺(tái)


CPU:Intel(R) Pentium(R) CPU G840 @ 2.80GHz

G++:4.8.2

OpenCV : 2.4.9


3、實(shí)驗(yàn)結(jié)果


編譯選項(xiàng)使用-O3時(shí),其中一次執(zhí)行結(jié)果:

489570 using at<>()
467315 using ptr<>() 
468603 using iterator 
469041 using Mat_ 
621367 using * 

編譯選項(xiàng)使用-O0 -g時(shí),其中一次執(zhí)行結(jié)果:

2.48216e+06 using at<>()
2.15397e+06 using ptr<>() 
3.80784e+06 using iterator 
2.38941e+06 using Mat_ 
621099 using * 


4、實(shí)驗(yàn)分析

從上面的結(jié)果可以看出,使用×?xí)r,在兩種模式下,計(jì)算速度差不多,這實(shí)際是由于我們的程序調(diào)用的OpenCV的庫(kù)函數(shù),而這個(gè)庫(kù)函數(shù)調(diào)用的是同一個(gè)。


如果你的產(chǎn)品要求執(zhí)行速度,從-O3條件下的輸出結(jié)果可以看出,ptr這種方式速度稍微快一點(diǎn)。但是他們的差別并不大,所以應(yīng)該再考慮代碼的復(fù)雜度。


代碼復(fù)雜度用代碼量(代碼行數(shù)、列數(shù))、使用變量的個(gè)數(shù)、使用變量個(gè)類(lèi)型掌握難度(比如指針可能難一點(diǎn))等因素來(lái)度量。

最小的就是使用×了(最后一個(gè)方法)。雖然他的復(fù)雜度較小,實(shí)際只有一行代碼,但是對(duì)于實(shí)際的應(yīng)用,你要想調(diào)用OpenCV已經(jīng)實(shí)現(xiàn)的功能,首先要確定OpenCV里已經(jīng)實(shí)現(xiàn)了這個(gè)功能。

其次,我認(rèn)為復(fù)雜度較小的是方法一,因?yàn)樗鼘?shí)際上可以不借用pix變量,完成前述算法,使用變量數(shù)較少,代碼量也不多。

Mat_和ptr這兩種方式的復(fù)雜度差不多,如果使用指針是一種稍微難一點(diǎn)的方式的話(huà),那么Mat_的復(fù)雜度可以認(rèn)為稍微小一點(diǎn)。

一般認(rèn)為迭代器是C++里面比較高級(jí)的特性,也是學(xué)習(xí)C++最靠后的技術(shù),再加上它使用了指針,如果指針?biāo)闶潜容^難掌握的技術(shù)的話(huà),使用迭代器這種方式復(fù)雜度可以說(shuō)是最復(fù)雜的了。


有些情況下,需要考慮安全性,比如防止越界訪問(wèn),如果你不想考慮過(guò)多邊界的問(wèn)題,使用迭代器也許是一種不錯(cuò)的選擇!


五、總結(jié)


選擇哪種元素訪問(wèn)方式,應(yīng)該根據(jù)自己的實(shí)際應(yīng)用環(huán)境,具體分析作出決定。主要考慮三個(gè)因素:性能、代碼復(fù)雜度、安全性,根據(jù)自己的程序類(lèi)型,選擇。





本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢(shì)抑制與過(guò)流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問(wèn)題卻十分常見(jiàn),不僅增加了維護(hù)成本,還影響了用戶(hù)體驗(yàn)。要解決這一問(wèn)題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(chē)(EV)作為新能源汽車(chē)的重要代表,正逐漸成為全球汽車(chē)產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車(chē)的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車(chē)的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車(chē) 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車(chē)場(chǎng)照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢(shì)逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問(wèn)題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對(duì)周?chē)娮釉O(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來(lái)解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開(kāi)關(guān)電源具有效率高的特性,而且開(kāi)關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開(kāi)關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉