版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
仿射變換詳解warpAffine今天遇到一個問題是關(guān)于仿射變換的,但是由于沒有將仿射變換的具體原理型明白,看別人的代碼看的很費(fèi)解,最后終于在師兄的幫助下將原理弄明白了,我覺得最重要的是理解仿射變換可以看成是幾種簡單變換的復(fù)合實(shí)現(xiàn),具體實(shí)現(xiàn)形式即將幾種簡單變換的變換矩陣M相乘,這樣就很容易理解啦
定義:仿射變換的功能是從二維坐標(biāo)到二維坐標(biāo)之間的線性變換,且保持二維圖形的“平直性”和“平行性”。仿射變換可以通過一系列的原子變換的復(fù)合來實(shí)現(xiàn),包括平移,縮放,翻轉(zhuǎn),旋轉(zhuǎn)和剪切。這類變換可以用一個3*3的矩陣M來表示,其最后一行為(0,0,1)。該變換矩陣將原坐標(biāo)為(x,y)變換為新坐標(biāo)(x',y'),即\o"OpenCV知識庫"OpenCV中相應(yīng)的函數(shù)是:void
warpAffine(InputArray
src,OutputArray
dst,InputArray
M,Size
dsize,int
flags=INTER_LINEAR,int
borderMode=BORDER_CONSTANT,constScalar&
borderValue=Scalar())\o"Permalinktothisdefinition"?Parameters:src
–inputimage.dst
–outputimagethathasthesize
dsize
andthesametypeas
src
.M
–
transformationmatrix,最重要的東東了,本文中著重講M的構(gòu)造dsize
–sizeoftheoutputimage.ansformation(
).borderMode
–pixelextrapolationmethod(see
\o"intborderInterpolate(intp,intlen,intborderType)"borderInterpolate());when
borderMode=BORDER_TRANSPARENT
,itmeansthatthepixelsinthedestinationimagecorrespondingtothe“outliers”inthesourceimagearenotmodifiedbythefunction.borderValue
–valueusedincaseofaconstantborder;bydefault,itis0.
下面介紹一些典型的仿射變換:(1)平移,將每一點(diǎn)移到到(x+t,y+t),變換矩陣為(2)縮放變換
將每一點(diǎn)的橫坐標(biāo)放大或縮小sx倍,縱坐標(biāo)放大(縮小)到sy倍,變換矩陣為(3)旋轉(zhuǎn)變換原點(diǎn):目標(biāo)圖形圍繞原點(diǎn)順時針旋轉(zhuǎn)Θ弧度,變換矩陣為(4)旋轉(zhuǎn)變換
:目標(biāo)圖形以(x,y)為軸心順時針旋轉(zhuǎn)θ弧度,變換矩陣為
相當(dāng)于兩次平移與一次原點(diǎn)旋轉(zhuǎn)變換的復(fù)合,即先將軸心(x,y)移到到原點(diǎn),然后做旋轉(zhuǎn)變換,最后將圖片的左上角置為圖片的原點(diǎn),即有的人可能會說為什么這么復(fù)雜呢,那是因?yàn)樵趏pencv的圖像處理中,所有對圖像的處理都是從原點(diǎn)進(jìn)行的,而圖像的原點(diǎn)默認(rèn)為圖像的左上角,而我們對圖像作旋轉(zhuǎn)處理時一般以圖像的中點(diǎn)為軸心,因此就需要做如下處理
如果你覺得這樣很麻煩,可以使用opencv中自帶的Mat
getRotationMatrix2D(Point2fcenter,doubleangle,doublescale)函數(shù)獲得變換矩陣M,center:旋轉(zhuǎn)中心angle:旋轉(zhuǎn)弧度,一定要將角度轉(zhuǎn)換成弧度scale:縮放尺度它得到的矩陣是:
其中α=scale*cos(angle),β=scale
*sing(angle)
,(center.x,center.y)表示旋轉(zhuǎn)軸心但是不得不說opencv的文檔以及相關(guān)書籍中都把這個矩陣寫錯了,如下:建議大家自己通過下式驗(yàn)證一下,即首先將軸心(x,y)移到原點(diǎn),然后做旋轉(zhuǎn)平綻放變換,最后再將圖像的左上角轉(zhuǎn)換為原點(diǎn)沒有去研究該函數(shù)的源碼,不曉得源碼中到底怎么寫的,但是在別人的博客中看到這個函數(shù)貌似需要修正
opencv中還有一個函數(shù):Mat
getAffineTransform(InputArray
src,InputArray
dst)\o"Permalinktothisdefinition"?它通過三組點(diǎn)對就可以獲得它們之間的仿射變換,如果我們在一組圖像變換中知道變換后的三組點(diǎn),那么我們就可以利用該函數(shù)求得變換矩陣,然后對整張圖片進(jìn)行仿射變換還有一種與仿射變換經(jīng)?;煜淖儞Q為透視變換,透視變換需要四組點(diǎn)對才能確定變換矩陣,由于仿射變換保持“平直性”與“平行性”,因此只需要三組點(diǎn)對,而透視變換沒有這種約束,故需要四組點(diǎn)對
warpPerspective函數(shù)主要作用:對圖像進(jìn)行透視變換,就是變形函數(shù)的調(diào)用形式:C++:
void
warpPerspective(InputArray
src,OutputArray
dst,InputArray
M,Size
dsize,int
flags=INTER_LINEAR,int
borderMode=BORDER_CONSTANT,constScalar&
borderValue=Scalar())參數(shù)詳解:InputArray
src:輸入的圖像OutputArray
dst:輸出的圖像InputArray
M:透視變換的矩陣Size
dsize:輸出圖像的大小int
flags=INTER_LINEAR:輸出圖像的插值方法,combinationofinterpolationmethods(INTER_LINEAR
or
INTER_NEAREST)andtheoptionalflagWARP_INVERSE_MAP,thatsets
M
astheinversetransformation(
)int
borderMode=BORDER_CONSTANT:圖像邊界的處理方式constScalar&
borderValue=Scalar():邊界的顏色設(shè)置,一般默認(rèn)是0函數(shù)原理:透視變換(PerspectiveTransformation)是將圖片投影到一個新的視平面(ViewingPlane),也稱作投影映射(ProjectiveMapping)。通用的變換公式為:u,v是原始圖片左邊,對應(yīng)得到變換后的圖片坐標(biāo)x,y,其中。
變換矩陣可以拆成4部分,表示線性變換,比如scaling,shearing和ratotion。用于平移,產(chǎn)生透視變換。所以可以理解成仿射等是透視變換的特殊形式。經(jīng)過透視變換之后的圖片通常不是平行四邊形(除非映射視平面和原來平面平行的情況)。重寫之前的變換公式可以得到:所以,已知變換對應(yīng)的幾個點(diǎn)就可以求取變換公式。反之,特定的變換公式也能新的變換后的圖片。簡單的看一個正方形到四邊形的變換:
變換的4組對應(yīng)點(diǎn)可以表示成:根據(jù)變換公式得到:定義幾個輔助變量:都為0時變換平面與原來是平行的,可以得到:不為0時,得到:求解出的變換矩陣就可以將一個正方形變換到四邊形。反之,四邊形變換到正方形也是一樣的。于是,我們通過兩次變換:四邊形變換到正方形+正方形變換到四邊形就可以將任意一個四邊形變換到另一個四邊形。
opencv代碼:[cpp]
\o"viewplain"viewplain\o"copy"copy#include<cv.h>
#include<highgui.h>
#pragma
comment(lib,
"cv.lib")
#pragma
comment(lib,
"cxcore.lib")
#pragma
comment(lib,
"highgui.lib")
int
main()
{
CvPoint2D32f
srcTri[4],
dstTri[4];
CvMat*
warp_mat
=
cvCreateMat
(3,
3,
CV_32FC1);
IplImage*
src
=
NULL;
IplImage*
dst
=
NULL;
src
=
cvLoadImage
("test.png",
1);
dst
=
cvCloneImage
(src);
dst->origin
=
src->origin;
cvZero
(dst);
srcTri[0].x
=
0;
srcTri[0].y
=
0;
srcTri[1].x
=
src->width
-
1;
srcTri[1].y
=
0;
srcTri[2].x
=
0;
srcTri[2].y
=
src->height
-
1;
srcTri[3].x
=
src->width
-
1;
srcTri[3].y
=
src->height
-
1;
dstTri[0].x
=
src->width
*
0.05;
dstTri[0].y
=
src->height
*
0.33;
dstTri[1].x
=
src->width
*
0.9;
dstTri[1].y
=
src->height
*
0.25;
dstTri[2].x
=
src->width
*
0.2;
dstTri[2].y
=
src->height
*
0.7;
dstTri[3].x
=
src->width
*
0.8;
dstTri[3].y
=
src->height
*
0.9;
cvGetPerspectiveTransform
(srcTri,
dstTri,
warp_mat);
cvWarpPerspective
(src,
dst,
warp_mat);
cvNamedWindow("src",
1);
cvShowImage("src",
src);
cvNamedWindow
("Affine_Transform",
1);
cvShowImage
("Affine_Transform",
dst);
cvWaitKey
(0);
cvReleaseImage
(&src);
cvReleaseImage
(&dst);
cvReleaseMat
(&warp_mat);
return
0;
}
今天遇到一個問題是關(guān)于仿射變換的,但是由于沒有將仿射變換的具體原理型明白,看別人的代碼看的很費(fèi)解,最后終于在師兄的幫助下將原理弄明白了,我覺得最重要的是理解仿射變換可以看成是幾種簡單變換的復(fù)合實(shí)現(xiàn),具體實(shí)現(xiàn)形式即將幾種簡單變換的變換矩陣M相乘,這樣就很容易理解啦
定義:仿射變換的功能是從二維坐標(biāo)到二維坐標(biāo)之間的線性變換,且保持二維圖形的“平直性”和“平行性”。仿射變換可以通過一系列的原子變換的復(fù)合來實(shí)現(xiàn),包括平移,縮放,翻轉(zhuǎn),旋轉(zhuǎn)和剪切。這類變換可以用一個3*3的矩陣M來表示,其最后一行為(0,0,1)。該變換矩陣將原坐標(biāo)為(x,y)變換為新坐標(biāo)(x',y'),即opencv中相應(yīng)的函數(shù)是:void
warpAffine(InputArray
src,OutputArray
dst,InputArray
M,Size
dsize,int
flags=INTER_LINEAR,int
borderMode=BORDER_CONSTANT,constScalar&
borderValue=Scalar())\o"Permalinktothisdefinition"?Parameters:src
–inputimage.dst
–outputimagethathasthesize
dsize
andthesametypeas
src
.M
–
transformationmatrix,最重要的東東了,本文中著重講M的構(gòu)造dsize
–sizeoftheoutputimage.flags
–combinationofinterpolationmethods(see
\o"voidresize(InputArraysrc,OutputArraydst,Sizedsize,doublefx,doublefy,intinterpolation)"resize()
)andtheoptionalflag
WARP_INVERSE_MAP
thatmeansthat
M
istheinversetransformation(
).borderMode
–pixelextrapolationmethod(see
\o"intborderInterpolate(intp,intlen,intborderType)"borderInterpolate());when
borderMode=BORDER_TRANSPARENT
,itmeansthatthepixelsinthedestinationimagecorrespondingtothe“outliers”inthesourceimagearenotmodifiedbythefunction.borderValue
–valueusedincaseofaconstantborder;bydefault,itis0.
下面介紹一些典型的仿射變換:(1)平移,將每一點(diǎn)移到到(x+t,y+t),變換矩陣為(2)縮放變換
將每一點(diǎn)的橫坐標(biāo)放大或縮小sx倍,縱坐標(biāo)放大(縮?。┑絪y倍,變換矩陣為(3)旋轉(zhuǎn)變換原點(diǎn):目標(biāo)圖形圍繞原點(diǎn)順時針旋轉(zhuǎn)Θ弧度,變換矩陣為(4)旋轉(zhuǎn)變換
:目標(biāo)圖形以(x,y)為軸心順時針旋轉(zhuǎn)θ弧度,變換矩陣為
相當(dāng)于兩次平移與一次原點(diǎn)旋轉(zhuǎn)變換的復(fù)合,即先將軸心(x,y)移到到原點(diǎn),然后做旋轉(zhuǎn)變換,最后將圖片的左上角置為圖片的原點(diǎn),即有的人可能會說為什么這么復(fù)雜呢,那是因?yàn)樵趏pencv的圖像處理中,所有對圖像的處理都是從原點(diǎn)進(jìn)行的,而圖像的原點(diǎn)默認(rèn)為圖像的左上角,而我們對圖像作旋轉(zhuǎn)處理時一般以圖像的中點(diǎn)為軸心,因此就需要做如下處理
如果你覺得這樣很麻煩,可以使用opencv中自帶的Mat
getRotationMatrix2D(Point2fcenter,doubleangle,doublescale)函數(shù)獲得變換矩陣M,center:旋轉(zhuǎn)中心angle:旋轉(zhuǎn)弧度,一定要將角度轉(zhuǎn)換成弧度scale:縮放尺度它得到的矩陣是:
opencv中還有一個函數(shù):Mat
getAffineTransform(InputArray
src,InputArray
dst)\o"Permalinktothisdefinition"?它通過三組點(diǎn)對就可以獲得它們之間的仿射變換,如果我們在一組圖像變換中知道變換后的三組點(diǎn),那么我們就可以利用該函數(shù)求得變換矩陣,然后對整張圖片進(jìn)行仿射變換還有一種與仿射變換經(jīng)?;煜淖儞Q為透視變換,透視變換需要四組點(diǎn)對才能確定變換矩陣,由于仿射變換保持“平直性”與“平行性”,因此只需要三組點(diǎn)對,而透視變換沒有這種約束,故需要四組點(diǎn)對
本文將openCV中的RANSAC代碼全部挑選出來,進(jìn)行分析和講解,以便大家更好的理解RANSAC\o"算法與數(shù)據(jù)結(jié)構(gòu)知識庫"算法。代碼我都試過,可以直接運(yùn)行。在計(jì)算機(jī)視覺和圖像處理等很多領(lǐng)域,都需要用到RANSAC算法。openCV中也有封裝好的RANSAC算法,以便于人們使用。關(guān)于RANSAC算法的一些應(yīng)用,可以看我的另一篇博客:利用SIFT和RANSAC算法(openCV框架)實(shí)現(xiàn)物體的檢測與定位,并求出變換矩陣(findFundamentalMat和findHomography的比較)但是前幾天師弟在使用openCV自帶的RANSAC算法時,發(fā)現(xiàn)實(shí)驗(yàn)的運(yùn)行時間并不會隨著輸入數(shù)據(jù)的增加而增加,感覺和理論上的不太相符。所以我就花了點(diǎn)時間,把openCV中關(guān)于RANSAC的源代碼全部復(fù)制出來研究了一下。以便我們更加清晰的了解RANSAC算法的實(shí)際運(yùn)行過程。首先看兩個類?//模型估計(jì)的基類,提供了估計(jì)矩陣的各種虛函數(shù)//置信度設(shè)為0。99循環(huán)次數(shù)設(shè)置為了2000classCvModelEstimator2{public:
CvModelEstimator2(int_modelPoints,CvSize_modelSize,int_maxBasicSolutions);
virtual~CvModelEstimator2();
virtualintrunKernel(constCvMat*m1,constCvMat*m2,CvMat*model)=0;
//virtualboolrunLMeDS(constCvMat*m1,constCvMat*m2,CvMat*model,
//CvMat*mask,doubleconfidence=0.99,intmaxIters=2000);
virtualboolrunRANSAC(constCvMat*m1,constCvMat*m2,CvMat*model,
CvMat*mask,doublethreshold,
doubleconfidence=0.99,intmaxIters=2000);
virtualboolrefine(constCvMat*,constCvMat*,CvMat*,int){returntrue;}
//virtualvoidsetSeed(int64seed);
protected:
virtualvoidcomputeReprojError(constCvMat*m1,constCvMat*m2,
constCvMat*model,CvMat*error)=0;
virtualintfindInliers(constCvMat*m1,constCvMat*m2,
constCvMat*model,CvMat*error,
CvMat*mask,doublethreshold);
virtualboolgetSubset(constCvMat*m1,constCvMat*m2,
CvMat*ms1,CvMat*ms2,intmaxAttempts=1000);
virtualboolcheckSubset(constCvMat*ms1,intcount);
CvRNGrng;
intmodelPoints;
CvSizemodelSize;
intmaxBasicSolutions;
boolcheckPartialSubsets;};//單應(yīng)矩陣估計(jì)的子類classCvHomographyEstimator:publicCvModelEstimator2{public:
CvHomographyEstimator(intmodelPoints);
virtualintrunKernel(constCvMat*m1,constCvMat*m2,CvMat*model);
virtualboolrefine(constCvMat*m1,constCvMat*m2,
CvMat*model,intmaxIters);
protected:
virtualvoidcomputeReprojError(constCvMat*m1,constCvMat*m2,
constCvMat*model,CvMat*error);};上面的兩個類中,CvModelEstimator2是一個基類,從名字就可以看出,這個類是用來估計(jì)模型的??梢钥吹嚼锩嫣峁┝嗽S多虛函數(shù),這些函數(shù)有許多,比如runRANSAC是利用RANSAC方法計(jì)算單應(yīng)矩陣,而runLMeDS是利用LMeDS方法計(jì)算單應(yīng)矩陣,我們這里僅僅講解RANSAC方法,所以其他不需要的內(nèi)容我就直接注釋掉了CvHomographyEstimator繼承自CvModelEstimator2,同樣的,從名字也就可以看出,這個類使用來估計(jì)單應(yīng)矩陣的。接下來是兩個類的構(gòu)造函數(shù)和析構(gòu)函數(shù),這個沒啥好說的了,基本都是默認(rèn)的。?4本范例的代碼主要都是
學(xué)習(xí)OpenCV——通過KeyPoints進(jìn)行目標(biāo)定位這篇博客提供的,然后在它的基礎(chǔ)上稍加修改,檢測keypoints點(diǎn)的檢測器是SURF,獲取描述子也是用到SURF來描述,而用到的匹配器是FlannBased,匹配的方式是Knn方式,最后通過findHomography尋找單映射矩陣,perspectiveTransform獲得最終的目標(biāo),在這個過程中還通過單映射矩陣來進(jìn)一步去除偽匹配,這里只是貼出代碼和代碼解析,至于原理還沒弄得特別明白,希望接下來可以繼續(xù)學(xué)習(xí),學(xué)懂了\o"算法與數(shù)據(jù)結(jié)構(gòu)知識庫"算法原理再來補(bǔ)充。1、代碼實(shí)現(xiàn)[cpp]
\o"viewplain"viewplain
\o"copy"copy
<span
style="font-size:18px;">#include
"stdafx.h"
#include
"opencv2/opencv.hpp"
#include
<vector>
#include
<iostream>
using
namespace
cv;
using
namespace
std;
Mat
src,frameImg;
int
width;
int
height;
vector<Point>
srcCorner(4);
vector<Point>
dstCorner(4);
static
bool
createDetectorDescriptorMatcher(
const
string&
detectorType,
const
string&
descriptorType,
const
string&
matcherType,
Ptr<FeatureDetector>&
featureDetector,
Ptr<DescriptorExtractor>&
descriptorExtractor,
Ptr<DescriptorMatcher>&
descriptorMatcher
)
{
cout
<<
"<
Creating
feature
detector,
descriptor
extractor
and
descriptor
matcher
..."
<<
endl;
if
(detectorType=="SIFT"||detectorType=="SURF")
initModule_nonfree();
featureDetector
=
FeatureDetector::create(
detectorType
);
descriptorExtractor
=
DescriptorExtractor::create(
descriptorType
);
descriptorMatcher
=
DescriptorMatcher::create(
matcherType
);
cout
<<
">"
<<
endl;
bool
isCreated
=
!(
featureDetector.empty()
||
descriptorExtractor.empty()
||
descriptorMatcher.empty()
);
if(
!isCreated
)
cout
<<
"Can
not
create
feature
detector
or
descriptor
extractor
or
descriptor
matcher
of
given
types."
<<
endl
<<
">"
<<
endl;
return
isCreated;
}
bool
refineMatchesWithHomography(const
std::vector<cv::KeyPoint>&
queryKeypoints,
const
std::vector<cv::KeyPoint>&
trainKeypoints,
float
reprojectionThreshold,
std::vector<cv::DMatch>&
matches,
cv::Mat&
homography
)
{
const
int
minNumberMatchesAllowed
=
4;
if
(matches.size()
<
minNumberMatchesAllowed)
return
false;
//
Prepare
data
for
cv::findHomography
std::vector<cv::Point2f>
queryPoints(matches.size());
std::vector<cv::Point2f>
trainPoints(matches.size());
for
(size_t
i
=
0;
i
<
matches.size();
i++)
{
queryPoints[i]
=
queryKeypoints[matches[i].queryIdx].pt;
trainPoints[i]
=
trainKeypoints[matches[i].trainIdx].pt;
}
//
Find
homography
matrix
and
get
inliers
mask
std::vector<unsigned
char>
inliersMask(matches.size());
homography
=
cv::findHomography(queryPoints,
trainPoints,
CV_FM_RANSAC,
reprojectionThreshold,
inliersMask);
std::vector<cv::DMatch>
inliers;
for
(size_t
i=0;
i<inliersMask.size();
i++)
{
if
(inliersMask[i])
inliers.push_back(matches[i]);
}
matches.swap(inliers);
Mat
homoShow;
drawMatches(src,queryKeypoints,frameImg,trainKeypoints,matches,homoShow,Scalar::all(-1),CV_RGB(255,255,255),Mat(),2);
imshow("homoShow",homoShow);
return
matches.size()
>
minNumberMatchesAllowed;
}
bool
matchingDescriptor(const
vector<KeyPoint>&
queryKeyPoints,const
vector<KeyPoint>&
trainKeyPoints,
const
Mat&
queryDescriptors,const
Mat&
trainDescriptors,
Ptr<DescriptorMatcher>&
descriptorMatcher,
bool
enableRatioTest
=
true)
{
vector<vector<DMatch>>
m_knnMatches;
vector<DMatch>m_Matches;
if
(enableRatioTest)
{
cout<<"KNN
Matching"<<endl;
const
float
minRatio
=
1.f
/
1.5f;
descriptorMatcher->knnMatch(queryDescriptors,trainDescriptors,m_knnMatches,2);
for
(size_t
i=0;
i<m_knnMatches.size();
i++)
{
const
cv::DMatch&
bestMatch
=
m_knnMatches[i][0];
const
cv::DMatch&
betterMatch
=
m_knnMatches[i][1];
float
distanceRatio
=
bestMatch.distance
/
betterMatch.distance;
if
(distanceRatio
<
minRatio)
{
m_Matches.push_back(bestMatch);
}
}
}
else
{
cout<<"Cross-Check"<<endl;
Ptr<cv::DescriptorMatcher>
BFMatcher(new
cv::BFMatcher(cv::NORM_HAMMING,
true));
BFMatcher->match(queryDescriptors,trainDescriptors,
m_Matches
);
}
Mat
homo;
float
homographyReprojectionThreshold
=
1.0;
bool
homographyFound
=
refineMatchesWithHomography(
queryKeyPoints,trainKeyPoints,homographyReprojectionThreshold,m_Matches,homo);
if
(!homographyFound)
return
false;
else
{
if
(m_Matches.size()>10)
{
std::vector<Point2f>
obj_corners(4);
obj_corners[0]
=
cvPoint(0,0);
obj_corners[1]
=
cvPoint(
src.cols,
0
);
obj_corners[2]
=
cvPoint(
src.cols,
src.rows
);
obj_corners[3]
=
cvPoint(
0,
src.rows
);
std::vector<Point2f>
scene_ers(4);
perspectiveTransform(
obj_corners,
scene_corners,
homo);
line(frameImg,scene_corners[0],scene_corners[1],CV_RGB(255,0,0),2);
line(frameImg,scene_corners[1],scene_corners[2],CV_RGB(255,0,0),2);
line(frameImg,scene_corners[2],scene_corners[3],CV_RGB(255,0,0),2);
line(frameImg,scene_corners[3],scene_corners[0],CV_RGB(255,0,0),2);
return
true;
}
return
true;
}
}
int
main()
{
string
filename
=
"box.png";
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 工程建設(shè)監(jiān)督管理合同范例
- 住建部供貨合同范例
- 開鎖加盟協(xié)議合同范例
- 托管收房合同范例
- 廣州包間酒吧轉(zhuǎn)讓合同范例
- 2024年鄂爾多斯辦理客運(yùn)從業(yè)資格證版試題
- 2024年朔州2024年道路旅客運(yùn)輸從業(yè)資格證模擬試題
- 2024年巢湖經(jīng)營性道路旅客運(yùn)輸駕駛員從業(yè)資格考試題庫
- 2024年武漢c1客運(yùn)資格證模擬考試題及答案
- 2024年汕頭c1客運(yùn)從業(yè)資格證怎么考
- 高二之路-我們的挑戰(zhàn)與成長
- 蘇教版小學(xué)科學(xué)五年級下冊 1 大腦(市一等獎)
- 同先輩比我們身上少了什么
- 大面積高荷載SOG預(yù)應(yīng)力無縫地坪施工工法
- 社會網(wǎng)絡(luò)分析:大數(shù)據(jù)揭示社交網(wǎng)絡(luò)結(jié)構(gòu)與趨勢
- 抗癌必修課胰腺癌
- 充電樁采購安裝投標(biāo)方案(技術(shù)方案)
- 《帶狀皰疹》課件
- 旅游定制師行業(yè)分析
- 法律資料特種設(shè)備法律法規(guī)與事故案例培訓(xùn)
- 成立分公司計(jì)劃書
評論
0/150
提交評論