版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
OpenCV2基礎(chǔ)(補(bǔ)充材料)OpenCV_tutorials翻譯資料整理而來(lái)翻譯材料出處:/opencvdoc/2.3.2/html/doc/tutorials/tutorials.html[2[2014/10]
目錄一、 Mat-基本圖像容器 1二、 OpenCV如何掃描圖像、利用查找表和計(jì)時(shí) 1三、 矩陣的掩碼操作 1四、 使用OpenCV對(duì)兩幅圖像求和(求混合(blending)) 1五、 改變圖像的對(duì)比度和亮度 1六、 圖像平滑處理 1七、 腐蝕與膨脹(ErodingandDilating) 1八、 實(shí)現(xiàn)自己的線性濾波器 1九、 給圖像添加邊界 1十、 Sobel導(dǎo)數(shù) 1十一、 霍夫線變換 1十二、 直方圖均衡化 1十三、 仿射變換 1十四、 Remapping重映射 1
Mat-基本圖像容器目的從真實(shí)世界中獲取數(shù)字圖像有很多方法,比如數(shù)碼相機(jī)、掃描儀、CT或者磁共振成像。無(wú)論哪種方法,我們(人類)看到的是圖像,而讓數(shù)字設(shè)備來(lái)“看“的時(shí)候,則是在記錄圖像中的每一個(gè)點(diǎn)的數(shù)值。比如上面的圖像,在標(biāo)出的鏡子區(qū)域中你見到的只是一個(gè)矩陣,該矩陣包含了所有像素點(diǎn)的強(qiáng)度值。如何獲取并存儲(chǔ)這些像素值由我們的需求而定,最終在計(jì)算機(jī)世界里所有圖像都可以簡(jiǎn)化為數(shù)值矩以及矩陣信息。作為一個(gè)計(jì)算機(jī)視覺庫(kù),OpenCV其主要目的就是通過(guò)處理和操作這些信息,來(lái)獲取更高級(jí)的信息。因此,OpenCV如何存儲(chǔ)并操作圖像是你首先要學(xué)習(xí)的。Mat在2001年剛剛出現(xiàn)的時(shí)候,OpenCV基于C語(yǔ)言接口而建。為了在內(nèi)存(memory)中存放圖像,當(dāng)時(shí)采用名為IplImage的C語(yǔ)言結(jié)構(gòu)體,時(shí)至今日這仍出現(xiàn)在大多數(shù)的舊版教程和教學(xué)材料。但這種方法必須接受C語(yǔ)言所有的不足,這其中最大的不足要數(shù)手動(dòng)內(nèi)存管理,其依據(jù)是用戶要為開辟和銷毀內(nèi)存負(fù)責(zé)。雖然對(duì)于小型的程序來(lái)說(shuō)手動(dòng)管理內(nèi)存不是問(wèn)題,但一旦代碼開始變得越來(lái)越龐大,你需要越來(lái)越多地糾纏于這個(gè)問(wèn)題,而不是著力解決你的開發(fā)目標(biāo)。幸運(yùn)的是,C++出現(xiàn)了,并且?guī)?lái)類的概念,這給用戶帶來(lái)另外一個(gè)選擇:自動(dòng)的內(nèi)存管理(不嚴(yán)謹(jǐn)?shù)卣f(shuō))。這是一個(gè)好消息,如果C++完全兼容C的話,這個(gè)變化不會(huì)帶來(lái)兼容性問(wèn)題。為此,OpenCV在2.0版本中引入了一個(gè)新的C++接口,利用自動(dòng)內(nèi)存管理給出了解決問(wèn)題的新方法。使用這個(gè)方法,你不需要糾結(jié)在管理內(nèi)存上,而且你的代碼會(huì)變得簡(jiǎn)潔(少寫多得)。但C++接口唯一的不足是當(dāng)前許多嵌入式開發(fā)系統(tǒng)只支持C語(yǔ)言。所以,當(dāng)目標(biāo)不是這種開發(fā)平臺(tái)時(shí),沒有必要使用舊方法(除非你是自找麻煩的受虐狂碼農(nóng))。關(guān)于Mat,首先要知道的是你不必再手動(dòng)地(1)為其開辟空間(2)在不需要時(shí)立即將空間釋放。但手動(dòng)地做還是可以的:大多數(shù)OpenCV函數(shù)仍會(huì)手動(dòng)地為輸出數(shù)據(jù)開辟空間。當(dāng)傳遞一個(gè)已經(jīng)存在的Mat對(duì)象時(shí),開辟好的矩陣空間會(huì)被重用。也就是說(shuō),我們每次都使用大小正好的內(nèi)存來(lái)完成任務(wù)?;旧现vMat是一個(gè)類,由兩個(gè)數(shù)據(jù)部分組成:矩陣頭(包含矩陣尺寸,存儲(chǔ)方法,存儲(chǔ)地址等信息)和一個(gè)指向存儲(chǔ)所有像素值的矩陣(根據(jù)所選存儲(chǔ)方法的不同矩陣可以是不同的維數(shù))的指針。矩陣頭的尺寸是常數(shù)值,但矩陣本身的尺寸會(huì)依圖像的不同而不同,通常比矩陣頭的尺寸大數(shù)個(gè)數(shù)量級(jí)。因此,當(dāng)在程序中傳遞圖像并創(chuàng)建拷貝時(shí),大的開銷是由矩陣造成的,而不是信息頭。OpenCV是一個(gè)圖像處理庫(kù),囊括了大量的圖像處理函數(shù),為了解決問(wèn)題通常要使用庫(kù)中的多個(gè)函數(shù),因此在函數(shù)中傳遞圖像是家常便飯。同時(shí)不要忘了我們正在討論的是計(jì)算量很大的圖像處理算法,因此,除非萬(wàn)不得已,我們不應(yīng)該拷貝大的圖像,因?yàn)檫@會(huì)降低程序速度。MatA,C;//只創(chuàng)建信息頭部分A=imread(argv[1],CV_LOAD_IMAGE_COLOR);//這里為矩陣開辟內(nèi)存
MatB(A);//使用拷貝構(gòu)造函數(shù)C=A;//賦值運(yùn)算符為了搞定這個(gè)問(wèn)題,OpenCV使用引用計(jì)數(shù)機(jī)制。其思路是讓每個(gè)Mat對(duì)象有自己的信息頭,但共享同一個(gè)矩陣。這通過(guò)讓矩陣指針指向同一地址而實(shí)現(xiàn)。而拷貝構(gòu)造函數(shù)則只拷貝信息頭和矩陣指針,而不拷貝矩陣。以上代碼中的所有Mat對(duì)象最終都指向同一個(gè)也是唯一一個(gè)數(shù)據(jù)矩陣。雖然它們的信息頭不同,但通過(guò)任何一個(gè)對(duì)象所做的改變也會(huì)影響其它對(duì)象。實(shí)際上,不同的對(duì)象只是訪問(wèn)相同數(shù)據(jù)的不同途徑而已。這里還要提及一個(gè)比較棒的功能:你可以創(chuàng)建只引用部分?jǐn)?shù)據(jù)的信息頭。比如想要?jiǎng)?chuàng)建一個(gè)感興趣區(qū)域(ROI),你只需要?jiǎng)?chuàng)建包含邊界信息的信息頭:MatD(A,Rect(10,10,100,100));//usingarectangleMatE=A(Range:all(),Range(1,3));//usingrowandcolumnboundaries現(xiàn)在你也許會(huì)問(wèn),如果矩陣屬于多個(gè)Mat對(duì)象,那么當(dāng)不再需要它時(shí)誰(shuí)來(lái)負(fù)責(zé)清理?簡(jiǎn)單的回答是:最后一個(gè)使用它的對(duì)象。通過(guò)引用計(jì)數(shù)機(jī)制來(lái)實(shí)現(xiàn)。無(wú)論什么時(shí)候有人拷貝了一個(gè)Mat對(duì)象的信息頭,都會(huì)增加矩陣的引用次數(shù);反之當(dāng)一個(gè)頭被釋放之后,這個(gè)計(jì)數(shù)被減一;當(dāng)計(jì)數(shù)值為零,矩陣會(huì)被清理。但某些時(shí)候你仍會(huì)想拷貝矩陣本身(不只是信息頭和矩陣指針),這時(shí)可以使用函數(shù)clone()或者copyTo()。MatF=A.clone();MatG;A.copyTo(G);在改變F或者G就不會(huì)影響Mat信息頭所指向的矩陣。總結(jié)一下,你需要記住的是OpenCV函數(shù)中輸出圖像的內(nèi)存分配是自動(dòng)完成的(如果不特別指定的話)。使用OpenCV的C++接口時(shí)不需要考慮內(nèi)存釋放問(wèn)題。賦值運(yùn)算符和拷貝構(gòu)造函數(shù)(ctor)只拷貝信息頭。使用函數(shù)clone()或者copyTo()來(lái)拷貝一副圖像的矩陣。存儲(chǔ)方法這里講述如何存儲(chǔ)像素值。需要指定顏色空間和數(shù)據(jù)類型。顏色空間是指對(duì)一個(gè)給定的顏色,如何組合顏色元素以對(duì)其編碼。最簡(jiǎn)單的顏色空間要屬灰度級(jí)空間,只處理黑色和白色,對(duì)它們進(jìn)行組合可以產(chǎn)生不同程度的灰色。對(duì)于彩色方式則有更多種類的顏色空間,但不論哪種方式都是把顏色分成三個(gè)或者四個(gè)基元素,通過(guò)組合基元素可以產(chǎn)生所有的顏色。RGB顏色空間是最常用的一種顏色空間,這歸功于它也是人眼內(nèi)部構(gòu)成顏色的方式。它的基色是紅色、綠色和藍(lán)色,有時(shí)為了表示透明顏色也會(huì)加入第四個(gè)元素alpha(A)。有很多的顏色系統(tǒng),各有自身優(yōu)勢(shì):RGB是最常見的,這是因?yàn)槿搜鄄捎孟嗨频墓ぷ鳈C(jī)制,它也被顯示設(shè)備所采用。HSV和HLS把顏色分解成色調(diào)、飽和度和亮度/明度。這是描述顏色更自然的方式,比如可以通過(guò)拋棄最后一個(gè)元素,使算法對(duì)輸入圖像的光照條件不敏感。YCrCb在JPEG圖像格式中廣泛使用。CIEL*a*b*是一種在感知上均勻的顏色空間,它適合用來(lái)度量?jī)蓚€(gè)顏色之間的距離。每個(gè)組成元素都有其自己的定義域,取決于其數(shù)據(jù)類型。如何存儲(chǔ)一個(gè)元素決定了我們?cè)谄涠x域上能夠控制的精度。最小的數(shù)據(jù)類型是char,占一個(gè)字節(jié)或者8位,可以是有符號(hào)型(0到255之間)或無(wú)符號(hào)型(-127到+127之間)。盡管使用三個(gè)char型元素已經(jīng)可以表示1600萬(wàn)種可能的顏色(使用RGB顏色空間),但若使用float(4字節(jié),32位)或double(8字節(jié),64位)則能給出更加精細(xì)的顏色分辨能力。但同時(shí)也要切記增加元素的尺寸也會(huì)增加了圖像所占的內(nèi)存空間。顯式地創(chuàng)建一個(gè)Mat對(duì)象教程讀取、修改、保存圖像已經(jīng)講解了如何使用函數(shù)imwrite()將一個(gè)矩陣寫入圖像文件中。但是為了debug,更加方便的方式是看實(shí)際值。為此,你可以通過(guò)Mat的運(yùn)算符<<來(lái)實(shí)現(xiàn),但要記住這只對(duì)二維矩陣有效。Mat不但是一個(gè)很贊的圖像容器類,它同時(shí)也是一個(gè)通用的矩陣類,所以可以用來(lái)創(chuàng)建和操作多維矩陣。創(chuàng)建一個(gè)Mat對(duì)象有多種方法:Mat()構(gòu)造函數(shù)MatM(2,2,CV_8UC3,Scalar(0,0,255));
out<<"M="<<endl<<""<<M<<endl<<endl;對(duì)于二維多通道圖像,首先要定義其尺寸,即行數(shù)和列數(shù)。然后,需要指定存儲(chǔ)元素的數(shù)據(jù)類型以及每個(gè)矩陣點(diǎn)的通道數(shù)。為此,依據(jù)下面的規(guī)則有多種定義CV_[Thenumberofbitsperitem][SignedorUnsigned][TypePrefix]C[Thechannelnumber]比如CV_8UC3表示使用8位的unsignedchar型,每個(gè)像素由三個(gè)元素組成三通道。預(yù)先定義的通道數(shù)可以多達(dá)四個(gè)。Scalar是個(gè)short型vector。指定這個(gè)能夠使用指定的定制化值來(lái)初始化矩陣。當(dāng)然,如果你需要更多通道數(shù),你可以使用大寫的宏并把通道數(shù)放在小括號(hào)中,如下所示·在C\C++中通過(guò)構(gòu)造函數(shù)進(jìn)行初始化intsz[3]={2,2,2};
MatL(3,sz,CV_8UC(1),Scalar::all(0));上面的例子演示了如何創(chuàng)建一個(gè)超過(guò)兩維的矩陣:指定維數(shù),然后傳遞一個(gè)指向一個(gè)數(shù)組的指針,這個(gè)數(shù)組包含每個(gè)維度的尺寸;其余的相同為已存在IplImage指針創(chuàng)建信息頭:IplImage*img=cvLoadImage("greatwave.png",1);Matmtx(img);//convertIplImage*->MatCreate()function:函數(shù)M.create(4,4,CV_8UC(2));
cout<<"M="<<endl<<""<<M<<endl<<endl;這個(gè)創(chuàng)建方法不能為矩陣設(shè)初值,它只是在改變尺寸時(shí)重新為矩陣數(shù)據(jù)開辟內(nèi)存。·MATLAB形式的初始化方式:zeros(),ones(),:eyes()。使用以下方式指定尺寸和數(shù)據(jù)類型:MatE=Mat::eye(4,4,CV_64F);
cout<<"E="<<endl<<""<<E<<endl<<endl;
MatO=Mat::ones(2,2,CV_32F);
cout<<"O="<<endl<<""<<O<<endl<<endl;
MatZ=Mat::zeros(3,3,CV_8UC1);cout<<"Z="<<endl<<""<<Z<<endl<<endl;對(duì)于小矩陣你可以用逗號(hào)分隔的初始化函數(shù):MatC=(Mat_<double>(3,3)<<0,-1,0,-1,5,-1,0,-1,0);cout<<"C="<<endl<<""<<C<<endl<<endl;·使用clone()或者copyTo()為一個(gè)存在的Mat對(duì)象創(chuàng)建一個(gè)新的信息頭。MatRowClone=C.row(1).clone();
cout<<"RowClone="<<endl<<""<<RowClone<<endl<<endl;格式化打印Note:調(diào)用函數(shù)randu()來(lái)對(duì)一個(gè)矩陣使用隨機(jī)數(shù)填充,需要指定隨機(jī)數(shù)的上界和下界:MatR=Mat(3,2,CV_8UC3);
randu(R,Scalar::all(0),Scalar::all(255));從上面的例子中可以看到默認(rèn)格式,除此之外,OpenCV還支持以下的輸出習(xí)慣·默認(rèn)方式cout<<"R(default)="<<endl<<R<<endl<<endl;·Pythoncout<<"R(python)="<<endl<<format(R,"python")<<endl<<endl;·以逗號(hào)分隔的數(shù)值(CSV)cout<<"R(csv)="<<endl<<format(R,"csv")<<endl<<endl;·Numpycout<<"R(numpy)="<<endl<<format(R,"numpy")<<endl<<endl;·C語(yǔ)言cout<<"R(c)="<<endl<<format(R,"C")<<endl<<endl;打印其它常用項(xiàng)目OpenCV支持使用運(yùn)算符<<來(lái)打印其它常用OpenCV數(shù)據(jù)結(jié)構(gòu)?!?維點(diǎn)Point2fP(5,1);
cout<<"Point(2D)="<<P<<endl<<endl;·3維點(diǎn)Point3fP3f(2,6,7);
cout<<"Point(3D)="<<P3f<<endl<<endl;·基于cv::Mat的std::vectorvector<float>v;
v.push_back((float)CV_PI);v.push_back(2);v.push_back(3.01f);
cout<<"VectoroffloatsviaMat="<<Mat(v)<<endl<<endl;·std::vector點(diǎn)vector<Point2f>vPoints(20);
for(size_tE=0;E<vPoints.size();++E)
vPoints[E]=Point2f((float)(E*5),(float)(E%7));
cout<<"Avectorof2DPoints="<<vPoints<<endl<<endl;這里的例子大多數(shù)出現(xiàn)在一個(gè)短小的控制臺(tái)應(yīng)用程序中,你可以在here下載到,或者在c++示例部分中找到。
OpenCV如何掃描圖像、利用查找表和計(jì)時(shí)目的我們將探索以下問(wèn)題的答案:如何遍歷圖像中的每一個(gè)像素?OpenCV的矩陣值是如何存儲(chǔ)的?如何測(cè)試我們所實(shí)現(xiàn)算法的性能?查找表是什么?為什么要用它?測(cè)試用例\o"Permalinktothisheadline"這里我們測(cè)試的,是一種簡(jiǎn)單的顏色縮減方法。如果矩陣元素存儲(chǔ)的是單通道像素,使用C或C++的無(wú)符號(hào)字符類型,那么像素可有256個(gè)不同值。但若是三通道圖像,這種存儲(chǔ)格式的顏色數(shù)就太多了(確切地說(shuō),有一千六百多萬(wàn)種)。用如此之多的顏色可能會(huì)對(duì)我們的算法性能造成嚴(yán)重影響。其實(shí)有時(shí)候,僅用這些顏色的一小部分,就足以達(dá)到同樣效果。這種情況下,常用的一種方法是顏色空間縮減。其做法是:將現(xiàn)有顏色空間值除以某個(gè)輸入值,以獲得較少的顏色數(shù)。例如,顏色值0到9可取為新值0,10到19可取為10,以此類推。uchar(無(wú)符號(hào)字符,即0到255之間取值的數(shù))類型的值除以int值,結(jié)果仍是char。因?yàn)榻Y(jié)果是char類型的,所以求出來(lái)小數(shù)也要向下取整。利用這一點(diǎn),剛才提到在uchar定義域中進(jìn)行的顏色縮減運(yùn)算就可以表達(dá)為下列形式:這樣的話,簡(jiǎn)單的顏色空間縮減算法就可由下面兩步組成:一、遍歷圖像矩陣的每一個(gè)像素;二、對(duì)像素應(yīng)用上述公式。值得注意的是,我們這里用到了除法和乘法運(yùn)算,而這兩種運(yùn)算又特別費(fèi)時(shí),所以,我們應(yīng)盡可能用代價(jià)較低的加、減、賦值等運(yùn)算替換它們。此外,還應(yīng)注意到,上述運(yùn)算的輸入僅能在某個(gè)有限范圍內(nèi)取值,如uchar類型可取256個(gè)值。由此可知,對(duì)于較大的圖像,有效的方法是預(yù)先計(jì)算所有可能的值,然后需要這些值的時(shí)候,利用查找表直接賦值即可。查找表是一維或多維數(shù)組,存儲(chǔ)了不同輸入值所對(duì)應(yīng)的輸出值,其優(yōu)勢(shì)在于只需讀取、無(wú)需計(jì)算。我們的測(cè)試用例程序(以及這里給出的示例代碼)做了以下幾件事:以命令行參數(shù)形式讀入圖像(可以是彩色圖像,也可以是灰度圖像,由命令行參數(shù)決定),然后用命令行參數(shù)給出的整數(shù)進(jìn)行顏色縮減。目前,OpenCV主要有三種逐像素遍歷圖像的方法。我們將分別用這三種方法掃描圖像,并將它們所用時(shí)間輸出到屏幕上。我想這樣的對(duì)比應(yīng)該很有意思。你可以從這里下載源代碼,也可以找到OpenCV的samples目錄,進(jìn)入cpp的tutorial_code的core目錄,查閱該程序的代碼。程序的基本用法是:how_to_scan_imagesimageName.jpgintValueToReduce[G]最后那個(gè)參數(shù)是可選的。如果提供該參數(shù),則圖像以灰度格式載入,否則使用彩色格式。在該程序中,我們首先要計(jì)算查找表。intdivideWith;//convertourinputstringtonumber-C++style
stringstreams;
s<<argv[2];
s>>divideWith;
if(!s)
{
cout<<"Invalidnumberenteredfordividing."<<endl;
return-1;
}
uchartable[256];
for(inti=0;i<256;++i)
table[i]=divideWith*(i/divideWith);這里我們先使用C++的stringstream類,把第三個(gè)命令行參數(shù)由字符串轉(zhuǎn)換為整數(shù)。然后,我們用數(shù)組和前面給出的公式計(jì)算查找表。這里并未涉及有關(guān)OpenCV的內(nèi)容。另外有個(gè)問(wèn)題是如何計(jì)時(shí)。沒錯(cuò),OpenCV提供了兩個(gè)簡(jiǎn)便的可用于計(jì)時(shí)的函數(shù)getTickCount()和getTickFrequency()。第一個(gè)函數(shù)返回你的CPU自某個(gè)事件(如啟動(dòng)電腦)以來(lái)走過(guò)的時(shí)鐘周期數(shù),第二個(gè)函數(shù)返回你的CPU一秒鐘所走的時(shí)鐘周期數(shù)。這樣,我們就能輕松地以秒為單位對(duì)某運(yùn)算計(jì)時(shí):doublet=(double)getTickCount();//做點(diǎn)什么...t=((double)getTickCount()-t)/getTickFrequency();cout<<"Timespassedinseconds:"<<t<<endl;圖像矩陣是如何存儲(chǔ)在內(nèi)存之中的?\o"Permalinktothisheadline"在我的教程Mat-基本圖像容器中,你或許已了解到,圖像矩陣的大小取決于我們所用的顏色模型,確切地說(shuō),取決于所用通道數(shù)。如果是灰度圖像,矩陣就會(huì)像這樣:而對(duì)多通道圖像來(lái)說(shuō),矩陣中的列會(huì)包含多個(gè)子列,其子列個(gè)數(shù)與通道數(shù)相等。例如,RGB顏色模型的矩陣:注意到,子列的通道順序是反過(guò)來(lái)的:BGR而不是RGB。很多情況下,因?yàn)閮?nèi)存足夠大,可實(shí)現(xiàn)連續(xù)存儲(chǔ),因此,圖像中的各行就能一行一行地連接起來(lái),形成一個(gè)長(zhǎng)行。連續(xù)存儲(chǔ)有助于提升圖像掃描速度,我們可以使用isContinuous()來(lái)去判斷矩陣是否是連續(xù)存儲(chǔ)的.相關(guān)示例會(huì)在接下來(lái)的內(nèi)容中提供。1.高效的方法EfficientWay\o"Permalinktothisheadline"說(shuō)到性能,經(jīng)典的C風(fēng)格運(yùn)算符[](指針)訪問(wèn)要更勝一籌.因此,我們推薦的效率最高的查找表賦值方法,還是下面的這種:Mat&ScanImageAndReduceC(Mat&I,constuchar*consttable){
//acceptonlychartypematrices
CV_Assert(I.depth()!=sizeof(uchar));
intchannels=I.channels();
intnRows=I.rows*channels;
intnCols=I.cols;
if(I.isContinuous())
{
nCols*=nRows;
nRows=1;
}
inti,j;
uchar*p;
for(i=0;i<nRows;++i)
{
p=I.ptr<uchar>(i);
for(j=0;j<nCols;++j)
{
p[j]=table[p[j]];
}
}
returnI;}這里,我們獲取了每一行開始處的指針,然后遍歷至該行末尾。如果矩陣是以連續(xù)方式存儲(chǔ)的,我們只需請(qǐng)求一次指針、然后一路遍歷下去就行。彩色圖像的情況有必要加以注意:因?yàn)槿齻€(gè)通道的原因,我們需要遍歷的元素?cái)?shù)目也是3倍。這里有另外一種方法來(lái)實(shí)現(xiàn)遍歷功能,就是使用data,data會(huì)從Mat中返回指向矩陣第一行第一列的指針。注意如果該指針為NULL則表明對(duì)象里面無(wú)輸入,所以這是一種簡(jiǎn)單的檢查圖像是否被成功讀入的方法。當(dāng)矩陣是連續(xù)存儲(chǔ)時(shí),我們就可以通過(guò)遍歷data來(lái)掃描整個(gè)圖像。例如,一個(gè)灰度圖像,其操作如下:uchar*p=I.data;
for(unsignedinti=0;i<ncol*nrows;++i)
*p++=table[*p];這回得出和前面相同的結(jié)果。但是這種方法編寫的代碼可讀性方面差,并且進(jìn)一步操作困難。同時(shí),我發(fā)現(xiàn)在實(shí)際應(yīng)用中,該方法的性能表現(xiàn)上并不明顯優(yōu)于前一種(因?yàn)楝F(xiàn)在大多數(shù)編譯器都會(huì)對(duì)這類操作做出優(yōu)化)。2.迭代法Theiterator(safe)method\o"Permalinktothisheadline"在高性能法(theefficientway)中,我們可以通過(guò)遍歷正確的uchar域并跳過(guò)行與行之間可能的空缺-你必須自己來(lái)確認(rèn)是否有空缺,來(lái)實(shí)現(xiàn)圖像掃描,迭代法則被認(rèn)為是一種以更安全的方式來(lái)實(shí)現(xiàn)這一功能。在迭代法中,你所需要做的僅僅是獲得圖像矩陣的begin和end,然后增加迭代直至從begin到end。將*操作符添加在迭代指針前,即可訪問(wèn)當(dāng)前指向的內(nèi)容。Mat&ScanImageAndReduceIterator(Mat&I,constuchar*consttable){
//acceptonlychartypematrices
CV_Assert(I.depth()!=sizeof(uchar));
constintchannels=I.channels();
switch(channels)
{
case1:
{
MatIterator_<uchar>it,end;
for(it=I.begin<uchar>(),end=I.end<uchar>();it!=end;++it)
*it=table[*it];
break;
}
case3:
{
MatIterator_<Vec3b>it,end;
for(it=I.begin<Vec3b>(),end=I.end<Vec3b>();it!=end;++it)
{
(*it)[0]=table[(*it)[0]];
(*it)[1]=table[(*it)[1]];
(*it)[2]=table[(*it)[2]];
}
}
}
returnI;}對(duì)于彩色圖像中的一行,每列中有3個(gè)uchar元素,這可以被認(rèn)為是一個(gè)小的包含uchar元素的vector,在OpenCV中用Vec3b來(lái)命名。如果要訪問(wèn)第n個(gè)子列,我們只需要簡(jiǎn)單的利用[]來(lái)操作就可以。需要指出的是,OpenCV的迭代在掃描過(guò)一行中所有列后會(huì)自動(dòng)跳至下一行,所以說(shuō)如果在彩色圖像中如果只使用一個(gè)簡(jiǎn)單的uchar而不是Vec3b迭代的話就只能獲得藍(lán)色通道(B)里的值。3.通過(guò)相關(guān)返回值的On-the-fly地址計(jì)算\o"Permalinktothisheadline"事實(shí)上這個(gè)方法并不推薦被用來(lái)進(jìn)行圖像掃描,它本來(lái)是被用于獲取或更改圖像中的隨機(jī)元素。它的基本用途是要確定你試圖訪問(wèn)的元素的所在行數(shù)與列數(shù)。在前面的掃描方法中,我們觀察到知道所查詢的圖像數(shù)據(jù)類型是很重要的。這里同樣的你得手動(dòng)指定好你要查找的數(shù)據(jù)類型。下面的代碼中是一個(gè)關(guān)于灰度圖像的示例(運(yùn)用+at()函數(shù)):Mat&ScanImageAndReduceRandomAccess(Mat&I,constuchar*consttable){
//acceptonlychartypematrices
CV_Assert(I.depth()!=sizeof(uchar));
constintchannels=I.channels();
switch(channels)
{
case1:
{
for(inti=0;i<I.rows;++i)
for(intj=0;j<I.cols;++j)
I.at<uchar>(i,j)=table[I.at<uchar>(i,j)];
break;
}
case3:
{
Mat_<Vec3b>_I=I;
for(inti=0;i<I.rows;++i)
for(intj=0;j<I.cols;++j)
{
_I(i,j)[0]=table[_I(i,j)[0]];
_I(i,j)[1]=table[_I(i,j)[1]];
_I(i,j)[2]=table[_I(i,j)[2]];
}
I=_I;
break;
}
}
returnI;}該函數(shù)輸入為數(shù)據(jù)類型及需求元素的坐標(biāo),返回的是一個(gè)對(duì)應(yīng)的值-如果用get則是constant,如果是用set、則為non-constant.處于程序安全,當(dāng)且僅當(dāng)在debug模式下它會(huì)檢查你的輸入坐標(biāo)是否有效或者超出范圍.如果坐標(biāo)有誤,則會(huì)輸出一個(gè)標(biāo)準(zhǔn)的錯(cuò)誤信息.和高性能法(theefficientway)相比,在release模式下,它們之間的區(qū)別僅僅是On-the-fly方法對(duì)于圖像矩陣的每個(gè)元素,都會(huì)獲取一個(gè)新的行指針,通過(guò)該指針和[]操作來(lái)獲取列元素.當(dāng)你對(duì)一張圖片進(jìn)行多次查詢操作時(shí),為避免反復(fù)輸入數(shù)據(jù)類型和at帶來(lái)的麻煩和浪費(fèi)的時(shí)間,OpenCV提供了:basicstructures:Mat_<id3>datatype.它同樣可以被用于獲知矩陣的數(shù)據(jù)類型,你可以簡(jiǎn)單利用()操作返回值來(lái)快速獲取查詢結(jié)果.值得注意的是你可以利用at()函數(shù)來(lái)用同樣速度完成相同操作.它僅僅是為了讓懶惰的程序員少寫點(diǎn)>_<.4.核心函數(shù)LUT(TheCoreFunction)\o"Permalinktothisheadline"這是最被推薦的用于實(shí)現(xiàn)批量圖像元素查找和更該操作圖像方法。在圖像處理中,對(duì)于一個(gè)給定的值,將其替換成其他的值是一個(gè)很常見的操作,OpenCV提供里一個(gè)函數(shù)直接實(shí)現(xiàn)該操作,并不需要你自己掃描圖像,就是:operationsOnArrays:LUT()<lut>,一個(gè)包含于coremodule的函數(shù).首先我們建立一個(gè)mat型用于查表:MatlookUpTable(1,256,CV_8U);
uchar*p=lookUpTable.data;
for(inti=0;i<256;++i)
p[i]=table[i];然后我們調(diào)用函數(shù)(I是輸入J是輸出):LUT(I,lookUpTable,J);性能表現(xiàn)\o"Permalinktothisheadline"為了得到最優(yōu)的結(jié)果,你最好自己編譯并運(yùn)行這些程序.為了更好的表現(xiàn)性能差異,我用了一個(gè)相當(dāng)大的圖片(2560X1600).性能測(cè)試這里用的是彩色圖片,結(jié)果是數(shù)百次測(cè)試的平均值.EfficientWay79.4717millisecondsIterator83.7201millisecondsOn-The-FlyRA93.7878millisecondsLUTfunction32.5759milliseconds我們得出一些結(jié)論:盡量使用OpenCV內(nèi)置函數(shù).調(diào)用LUT函數(shù)可以獲得最快的速度.這是因?yàn)镺penCV庫(kù)可以通過(guò)英特爾線程架構(gòu)啟用多線程.當(dāng)然,如果你喜歡使用指針的方法來(lái)掃描圖像,迭代法是一個(gè)不錯(cuò)的選擇,不過(guò)速度上較慢。在debug模式下使用on-the-fly方法掃描全圖是一個(gè)最浪費(fèi)資源的方法,在release模式下它的表現(xiàn)和迭代法相差無(wú)幾,但是從安全性角度來(lái)考慮,迭代法是更佳的選擇。
矩陣的掩碼操作矩陣的掩碼操作很簡(jiǎn)單。其思想是:根據(jù)掩碼矩陣(也稱作核)重新計(jì)算圖像中每個(gè)像素的值。掩碼矩陣中的值表示近鄰像素值(包括該像素自身的值)對(duì)新像素值有多大影響。從數(shù)學(xué)觀點(diǎn)看,我們用自己設(shè)置的權(quán)值,對(duì)像素鄰域內(nèi)的值做了個(gè)加權(quán)平均。測(cè)試用例思考一下圖像對(duì)比度增強(qiáng)的問(wèn)題。我們可以對(duì)圖像的每個(gè)像素應(yīng)用下面的公式:上面那種表達(dá)法是公式的形式,而下面那種是以掩碼矩陣表示的緊湊形式。使用掩碼矩陣的時(shí)候,我們先把矩陣中心的元素(上面的例子中是(0,0)位置的元素,也就是5)對(duì)齊到要計(jì)算的目標(biāo)像素上,再把鄰域像素值和相應(yīng)的矩陣元素值的乘積加起來(lái)。雖然這兩種形式是完全等價(jià)的,但在大矩陣情況下,下面的形式看起來(lái)會(huì)清楚得多?,F(xiàn)在,我們來(lái)看看實(shí)現(xiàn)掩碼操作的兩種方法。一種方法是用基本的像素訪問(wèn)方法,另一種方法是用filter2D函數(shù)?;痉椒╘o"Permalinktothisheadline"下面是實(shí)現(xiàn)了上述功能的函數(shù):voidSharpen(constMat&myImage,Mat&Result){
CV_Assert(myImage.depth()==CV_8U);//僅接受uchar圖像
Result.create(myImage.size(),myImage.type());
constintnChannels=myImage.channels();
for(intj=1;j<myImage.rows-1;++j)
{
constuchar*previous=myImage.ptr<uchar>(j-1);
constuchar*current=myImage.ptr<uchar>(j);
constuchar*next=myImage.ptr<uchar>(j+1);
uchar*output=Result.ptr<uchar>(j);
for(inti=nChannels;i<nChannels*(myImage.cols-1);++i)
{
*output++=saturate_cast<uchar>(5*current[i]
-current[i-nChannels]-current[i+nChannels]-previous[i]-next[i]);
}
}
Result.row(0).setTo(Scalar(0));
Result.row(Result.rows-1).setTo(Scalar(0));
Result.col(0).setTo(Scalar(0));
Result.col(Result.cols-1).setTo(Scalar(0));}剛進(jìn)入函數(shù)的時(shí)候,我們要確保輸入圖像是無(wú)符號(hào)字符類型的。為了做到這點(diǎn),我們使用了CV_Assert函數(shù)。若該函數(shù)括號(hào)內(nèi)的表達(dá)式為false,則會(huì)拋出一個(gè)錯(cuò)誤。CV_Assert(myImage.depth()==CV_8U);//僅接受uchar圖像然后,我們創(chuàng)建了一個(gè)與輸入有著相同大小和類型的輸出圖像。在圖像矩陣是如何存儲(chǔ)在內(nèi)存之中的?一節(jié)可以看到,根據(jù)圖像的通道數(shù),我們有一個(gè)或多個(gè)子列。我們用指針在每一個(gè)通道上迭代,因此通道數(shù)就決定了需計(jì)算的元素總數(shù)。Result.create(myImage.size(),myImage.type());constintnChannels=myImage.channels();利用C語(yǔ)言的[]操作符,我們能簡(jiǎn)單明了地訪問(wèn)像素。因?yàn)橐瑫r(shí)訪問(wèn)多行像素,所以我們獲取了其中每一行像素的指針(分別是前一行、當(dāng)前行和下一行)。此外,我們還需要一個(gè)指向計(jì)算結(jié)果存儲(chǔ)位置的指針。有了這些指針后,我們使用[]操作符,就能輕松訪問(wèn)到目標(biāo)元素。為了讓輸出指針向前移動(dòng),我們?cè)诿恳淮尾僮髦髮?duì)輸出指針進(jìn)行了遞增(移動(dòng)一個(gè)字節(jié)):for(intj=1;j<myImage.rows-1;++j){
constuchar*previous=myImage.ptr<uchar>(j-1);
constuchar*current=myImage.ptr<uchar>(j);
constuchar*next=myImage.ptr<uchar>(j+1);
uchar*output=Result.ptr<uchar>(j);
for(inti=nChannels;i<nChannels*(myImage.cols-1);++i)
{
*output++=saturate_cast<uchar>(5*current[i]
-current[i-nChannels]-current[i+nChannels]-previous[i]-next[i]);
}}在圖像的邊界上,上面給出的公式會(huì)訪問(wèn)不存在的像素位置(比如(0,-1))。因此我們的公式對(duì)邊界點(diǎn)來(lái)說(shuō)是未定義的。一種簡(jiǎn)單的解決方法,是不對(duì)這些邊界點(diǎn)使用掩碼,而直接把它們?cè)O(shè)為0:Result.row(0).setTo(Scalar(0));//上邊界Result.row(Result.rows-1).setTo(Scalar(0));//下邊界Result.col(0).setTo(Scalar(0));//左邊界Result.col(Result.cols-1).setTo(Scalar(0));//右邊界filter2D函數(shù)\o"Permalinktothisheadline"濾波器在圖像處理中的應(yīng)用太廣泛了,因此OpenCV也有個(gè)用到了濾波器掩碼(某些場(chǎng)合也稱作核)的函數(shù)。不過(guò)想使用這個(gè)函數(shù),你必須先定義一個(gè)表示掩碼的Mat對(duì)象:Matkern=(Mat_<char>(3,3)<<0,-1,0,
-1,5,-1,
0,-1,0);然后調(diào)用filter2D函數(shù),參數(shù)包括輸入、輸出圖像以及用到的核:filter2D(I,K,I.depth(),kern);它還帶有第五個(gè)可選參數(shù)——指定核的中心,和第六個(gè)可選參數(shù)——指定函數(shù)在未定義區(qū)域(邊界)的行為。使用該函數(shù)有一些優(yōu)點(diǎn),如代碼更加清晰簡(jiǎn)潔、通常比自己實(shí)現(xiàn)的方法速度更快(因?yàn)橛幸恍iT針對(duì)它實(shí)現(xiàn)的優(yōu)化技術(shù))等等。例如,我測(cè)試的濾波器方法僅花了13毫秒,而前面那樣自己實(shí)現(xiàn)迭代方法花了約31毫秒,二者有著不小差距。示例:你可以從here下載這個(gè)示例的源代碼,也可瀏覽OpenCV源代碼庫(kù)的示例目錄samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp。
使用OpenCV對(duì)兩幅圖像求和(求混合(blending))目的在這節(jié)教程中您將學(xué)到線性混合(linearblending)是什么以及有什么用處.如何使用addWeighted進(jìn)行兩幅圖像求和原理\o"Permalinktothisheadline"Note以下解釋基于RichardSzeliski所著ComputerVision:AlgorithmsandApplications在前面的教程中,我們已經(jīng)了解一點(diǎn)像素操作的知識(shí)。線性混合操作也是一種典型的二元(兩個(gè)輸入)的像素操作:通過(guò)在范圍內(nèi)改變,這個(gè)操可以用來(lái)對(duì)兩幅圖像或兩段視頻產(chǎn)生時(shí)間上的畫面疊化(cross-dissolve)效果,就像在幻燈片放映和電影制作中那樣(很酷吧?)(譯者注:在幻燈片翻頁(yè)時(shí)可以設(shè)置為前后頁(yè)緩慢過(guò)渡以產(chǎn)生疊加效果,電影中經(jīng)常在情節(jié)過(guò)渡時(shí)出現(xiàn)畫面疊加效果)。代碼\o"Permalinktothisheadline"在簡(jiǎn)短的說(shuō)明后我們來(lái)看代碼:#include<cv.h>#include<highgui.h>#include<iostream>
usingnamespacecv;
intmain(intargc,char**argv){
doublealpha=0.5;doublebeta;doubleinput;
Matsrc1,src2,dst;
///Asktheuserenteralpha
std::cout<<"SimpleLinearBlender"<<std::endl;
std::cout<<""<<std::endl;
std::cout<<"*Enteralpha[0-1]:";
std::cin>>input;
///Weusethealphaprovidedbytheuseriffitisbetween0and1
if(alpha>=0&&alpha<=1)
{alpha=input;}
///Readimage(samesize,sametype)
src1=imread("../../images/LinuxLogo.jpg");
src2=imread("../../images/WindowsLogo.jpg");
if(!src1.data){printf("Errorloadingsrc1\n");return-1;}
if(!src2.data){printf("Errorloadingsrc2\n");return-1;}
///CreateWindows
namedWindow("LinearBlend",1);
beta=(1.0-alpha);
addWeighted(src1,alpha,src2,beta,0.0,dst);
imshow("LinearBlend",dst);
waitKey(0);
return0;}說(shuō)明\o"Permalinktothisheadline"1.既然我們要執(zhí)行我們需要兩幅輸入圖像(和)。相應(yīng)地,我們使用常用的方法加載圖像src1=imread("../../images/LinuxLogo.jpg");src2=imread("../../images/WindowsLogo.jpg");Warning因?yàn)槲覀儗?duì)src1和src2求和,它們必須要有相同的尺寸(寬度和高度)和類型?,F(xiàn)在我們生成圖像.為此目的,使用函數(shù)addWeighted可以很方便地實(shí)現(xiàn):beta=(1.0-alpha);addWeighted(src1,alpha,src2,beta,0.0,dst);這是因?yàn)閍ddWeighted進(jìn)行如下計(jì)算這里對(duì)應(yīng)于上面代碼中被設(shè)為的參數(shù)。3.創(chuàng)建顯示窗口,顯示圖像并等待用戶結(jié)束程序。結(jié)果\o"Permalinktothisheadline"改變圖像的對(duì)比度和亮度目的\o"Permalinktothisheadline"本篇教程中,你將學(xué)到:訪問(wèn)像素值用0初始化矩陣saturate_cast是做什么用的,以及它為什么有用一些有關(guān)像素變換的精彩內(nèi)容原理\o"Permalinktothisheadline"Note以下解釋節(jié)選自RichardSzeliski所著ComputerVision:AlgorithmsandApplications圖像處理\o"Permalinktothisheadline"一般來(lái)說(shuō),圖像處理算子是帶有一幅或多幅輸入圖像、產(chǎn)生一幅輸出圖像的函數(shù)。圖像變換可分為以下兩種:點(diǎn)算子(像素變換)鄰域(基于區(qū)域的)算子像素變換\o"Permalinktothisheadline"在這一類圖像處理變換中,僅僅根據(jù)輸入像素值(有時(shí)可加上某些全局信息或參數(shù))計(jì)算相應(yīng)的輸出像素值。這類算子包括亮度和對(duì)比度調(diào)整,以及顏色校正和變換。亮度和對(duì)比度調(diào)整\o"Permalinktothisheadline"·兩種常用的點(diǎn)過(guò)程(即點(diǎn)算子),是用常數(shù)對(duì)點(diǎn)進(jìn)行乘法和加法運(yùn)算:··兩個(gè)參數(shù)和一般稱作增益和偏置參數(shù)。我們往往用這兩個(gè)參數(shù)來(lái)分別控制對(duì)比度和亮度?!つ憧梢园芽闯稍磮D像像素,把看成輸出圖像像素。這樣一來(lái),上面的式子就能寫得更清楚些:其中,和表示像素位于第i行和第j列。代碼\o"Permalinktothisheadline"下列代碼執(zhí)行運(yùn)算:#include<opencv2/core/core.hpp>#include<opencv2/highgui/highgui.hpp>#include<iostream>
usingnamespacestd;usingnamespacecv;
doublealpha;/**<控制對(duì)比度*/intbeta;/**<控制亮度*/
intmain(intargc,char**argv){
///讀入用戶提供的圖像
Matimage=imread(argv[1]);
Matnew_image=Mat::zeros(image.size(),image.type());
///初始化
cout<<"BasicLinearTransforms"<<endl;
cout<<""<<endl;
cout<<"*Enterthealphavalue[1.0-3.0]:";
cin>>alpha;
cout<<"*Enterthebetavalue[0-100]:";
cin>>beta;
///執(zhí)行運(yùn)算new_image(i,j)=alpha*image(i,j)+beta
for(inty=0;y<image.rows;y++)
{
for(intx=0;x<image.cols;x++)
{
for(intc=0;c<3;c++)
{
new_image.at<Vec3b>(y,x)[c]=saturate_cast<uchar>(alpha*(image.at<Vec3b>(y,x)[c])+beta);
}
}
}
///創(chuàng)建窗口
namedWindow("OriginalImage",1);
namedWindow("NewImage",1);
///顯示圖像
imshow("OriginalImage",image);
imshow("NewImage",new_image);
///等待用戶按鍵
waitKey();
return0;}說(shuō)明\o"Permalinktothisheadline"1.一上來(lái),我們要建立兩個(gè)變量,以存儲(chǔ)用戶輸入的和:doublealpha;intbeta;2.然后,用imread載入圖像,并將其存入一個(gè)Mat對(duì)象:Matimage=imread(argv[1]);3.此時(shí),因?yàn)橐獙?duì)圖像進(jìn)行一些變換,所以我們需要一個(gè)新的Mat對(duì)象,以存儲(chǔ)變換后的圖像。我們希望這個(gè)Mat對(duì)象擁有下面的性質(zhì):像素值初始化為0與原圖像有相同的大小和類型Matnew_image=Mat::zeros(image.size(),image.type());注意到,Mat::zeros采用Matlab風(fēng)格的初始化方式,用image.size()和image.type()來(lái)對(duì)Mat對(duì)象進(jìn)行0初始化。4.現(xiàn)在,為了執(zhí)行運(yùn)算,我們要訪問(wèn)圖像的每一個(gè)像素。因?yàn)槭菍?duì)RGB圖像進(jìn)行運(yùn)算,每個(gè)像素有三個(gè)值(R、G、B),所以我們要分別訪問(wèn)它們。下面是訪問(wèn)像素的代碼片段:for(inty=0;y<image.rows;y++){
for(intx=0;x<image.cols;x++)
{
for(intc=0;c<3;c++)
{
new_image.at<Vec3b>(y,x)[c]=saturate_cast<uchar>(alpha*(image.at<Vec3b>(y,x)[c])+beta);
}
}}注意以下兩點(diǎn):為了訪問(wèn)圖像的每一個(gè)像素,我們使用這一語(yǔ)法:image.at<Vec3b>(y,x)[c]其中,y是像素所在的行,x是像素所在的列,c是R、G、B(0、1、2)之一。因?yàn)榈倪\(yùn)算結(jié)果可能超出像素取值范圍,還可能是非整數(shù)(如果是浮點(diǎn)數(shù)的話),所以我們要用saturate_cast對(duì)結(jié)果進(jìn)行轉(zhuǎn)換,以確保它為有效值。5.最后,用傳統(tǒng)方法創(chuàng)建窗口并顯示圖像。namedWindow("OriginalImage",1);namedWindow("NewImage",1);
imshow("OriginalImage",image);imshow("NewImage",new_image);
waitKey(0);Note我們可以不用for循環(huán)來(lái)訪問(wèn)每個(gè)像素,而是直接采用下面這個(gè)命令:image.convertTo(new_image,-1,alpha,beta);這里的convertTo將執(zhí)行我們想做的new_image=a*image+beta。然而,我們想展現(xiàn)訪問(wèn)每一個(gè)像素的過(guò)程,所以選用了for循環(huán)的方式。實(shí)際上,這兩種方式都能返回同樣的結(jié)果。結(jié)果\o"Permalinktothisheadline"·運(yùn)行代碼,取參數(shù)和$./BasicLin
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 江蘇省鎮(zhèn)江市丹徒區(qū)高中政治 第九課 唯物辯證法的實(shí)質(zhì)與核心教案 新人教版必修4
- 二年級(jí)品德與生活上冊(cè) 誠(chéng)實(shí)故事會(huì)教案2 北師大版
- 2024秋八年級(jí)物理上冊(cè) 第4章 光的折射 透鏡 第一節(jié) 光的折射教案2(新版)蘇科版
- 2024年秋九年級(jí)歷史上冊(cè) 第2單元 古代歐洲文明 第4課 希臘城邦和亞歷山大帝國(guó)教案 新人教版
- 2024-2025學(xué)年高中英語(yǔ) Module 5 Newspapers and Magazines教案1 外研版必修2
- 2024年五年級(jí)語(yǔ)文上冊(cè) 第四單元 13 少年中國(guó)說(shuō)(節(jié)選)配套教案 新人教版
- 2023六年級(jí)數(shù)學(xué)下冊(cè) 第4單元 比例 2正比例和反比例練習(xí)課(正比例和反比例)教案 新人教版
- 換熱站管理制度
- 自建房屋外包合同(2篇)
- 設(shè)計(jì)師求職簡(jiǎn)歷幻燈片模板
- 菜籽油銷售方案
- 車站愛心驛站活動(dòng)方案
- 少年中國(guó)說(shuō)英文版
- 防洪堤與攔河壩鋼筋工程施工方案及關(guān)鍵性技術(shù)措施
- 100個(gè)紅色經(jīng)典故事【十八篇】
- 5G網(wǎng)絡(luò)安全架構(gòu)設(shè)計(jì)
- 2024電力人工智能樣本增廣技術(shù)架構(gòu)要求
- 特種設(shè)備安全法全文
- 2024年國(guó)家能源集團(tuán)公司招聘筆試參考題庫(kù)含答案解析
- 幼兒園的小小科學(xué)家實(shí)驗(yàn)室主題班會(huì)課件
- 變電運(yùn)維管理規(guī)定(試行)第3分冊(cè)組合電器運(yùn)維細(xì)則
評(píng)論
0/150
提交評(píng)論