今天介紹圖和標(biāo)定camera。首先是用到的opencv函數(shù)。后面附上源碼。
FindChessboardCorners 尋找棋盤圖的內(nèi)角點(diǎn)位置
int cvFindChessboardCorners( const void*image, CvSize pattern_size,
CvPoint2D32f* corners,int* corner_count=NULL,
int flags=CV_CALIB_CB_ADAPTIVE_THRESH );
image
輸入的棋盤圖,必須是8位的灰度或者彩色圖像。
pattern_size
棋盤圖中每行和每列角點(diǎn)的個數(shù)。
corners
檢測到的角點(diǎn)
corner_count
輸出,角點(diǎn)的個數(shù)。如果不是NULL,函數(shù)將檢測到的角點(diǎn)的個數(shù)存儲于此變量。
flags
各種操作標(biāo)志,可以是0或者下面值的組合:
CV_CALIB_CB_ADAPTIVE_THRESH - 使用自適應(yīng)閾值(通過平均圖像亮度計(jì)算得到)將圖像轉(zhuǎn)換為黑白圖,而不是一個固定的閾值。
CV_CALIB_CB_NORMALIZE_IMAGE - 在利用固定閾值或者自適應(yīng)的閾值進(jìn)行二值化之前,先使用cvNormalizeHist來均衡化圖像亮度。
CV_CALIB_CB_FILTER_QUADS - 使用其他的準(zhǔn)則(如輪廓面積,周長,方形形狀)來去除在輪廓檢測階段檢測到的錯誤方塊。
函數(shù)cvFindChessboardCorners試圖確定輸入圖像是否是棋盤模式,并確定角點(diǎn)的位置。如果所有角點(diǎn)都被檢測到切它們都被以一定順序排布(一行一行地,每行從左到右),函數(shù)返回非零值,否則在函數(shù)不能發(fā)現(xiàn)所有角點(diǎn)或者記錄它們地情況下,函數(shù)返回0。例如一個正常地棋盤圖右8x8個方塊和7x7個內(nèi)角點(diǎn),內(nèi)角點(diǎn)是黑色方塊相互聯(lián)通地位置。這個函數(shù)檢測到地坐標(biāo)只是一個大約地值,如果要精確地確定它們的位置,可以使用函數(shù)cvFindCornerSubPix。
FindCornerSubPix 尋找棋盤圖的內(nèi)角點(diǎn)位置
精確角點(diǎn)位置
void cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners,
int count, CvSize win, CvSize zero_zone,
CvTermCriteria criteria );
image
輸入圖像.
corners
輸入角點(diǎn)的初始坐標(biāo),也存儲精確的輸出坐標(biāo)
count
角點(diǎn)數(shù)目
win
搜索窗口的一半尺寸。如果win=(5,5) 那么使用 52+1 × 52+1 = 11 × 11 大小的搜索窗口
zero_zone
死區(qū)的一半尺寸,死區(qū)為不對搜索區(qū)的中央位置做求和運(yùn)算的區(qū)域。它是用來避免自相關(guān)矩陣出現(xiàn)的某些可能的奇異性。當(dāng)值為 (-1,-1) 表示沒有死區(qū)。
criteria
求角點(diǎn)的迭代過程的終止條件。即角點(diǎn)位置的確定,要么迭代數(shù)大于某個設(shè)定值,或者是精確度達(dá)到某個設(shè)定值。 criteria 可以是最大迭代數(shù)目,或者是設(shè)定的精確度,也可以是它們的組合。
函數(shù)cvFindCornerSubPix通過迭代來發(fā)現(xiàn)具有子象素精度的角點(diǎn)位置,或如圖所示的放射鞍點(diǎn)(radial saddle points)。
子象素級角點(diǎn)定位的實(shí)現(xiàn)是基于對向量正交性的觀測而實(shí)現(xiàn)的,即從中央點(diǎn)q到其鄰域點(diǎn)p 的向量和p點(diǎn)處的圖像梯度正交(服從圖像和測量噪聲)。考慮以下的表達(dá)式:
εi=DIpiT·(q-pi)
其中,DIpi表示在q的一個鄰域點(diǎn)pi處的圖像梯度,q的值通過最小化εi得到。通過將εi設(shè)為0,可以建立系統(tǒng)方程如下:
sumi(DIpi·DIpiT)·q - sumi(DIpi·DIpiT·pi) = 0
其中q的鄰域(搜索窗)中的梯度被累加。調(diào)用第一個梯度參數(shù)G和第二個梯度參數(shù)b,得到:
q=G-1·b
該算法將搜索窗的中心設(shè)為新的中心q,然后迭代,直到找到低于某個閾值點(diǎn)的中心位置。
DrawChessBoardCorners 繪制檢測到的棋盤角點(diǎn)
void cvDrawChessboardCorners( CvArr* image,CvSize pattern_size,CvPoint2D32f*corners,
int count,int pattern_was_found );
image
結(jié)果圖像,必須是8位彩色圖像。
pattern_size
每行和每列地內(nèi)角點(diǎn)數(shù)目。
corners
檢測到地角點(diǎn)數(shù)組。
count
角點(diǎn)數(shù)目。
pattern_was_found
指示完整地棋盤被發(fā)現(xiàn)(≠0)還是沒有發(fā)現(xiàn)(=0)??梢詡鬏攃vFindChessboardCorners函數(shù)的返回值。
當(dāng)棋盤沒有完全檢測出時,函數(shù)cvDrawChessboardCorners以紅色圓圈繪制檢測到的棋盤角點(diǎn);如果整個棋盤都檢測到,則用直線連接所有的角點(diǎn)。
CalibrateCamera2利用定標(biāo)來計(jì)算攝像機(jī)的內(nèi)參數(shù)和外參數(shù)
void cvCalibrateCamera2 ( const CvMat* object_points,
constCvMat* image_points,const CvMat* point_counts,
CvSizeimage_size, CvMat* intrinsic_matrix,
CvMat*distortion_coeffs, CvMat* rotation_vectors=NULL,
CvMat*translation_vectors=NULL, int flags=0 );
object_points
定標(biāo)點(diǎn)的世界坐標(biāo),為3xN或者Nx3的矩陣,這里N是所有視圖中點(diǎn)的總數(shù)。
image_points
定標(biāo)點(diǎn)的圖像坐標(biāo),為2xN或者Nx2的矩陣,這里N是所有視圖中點(diǎn)的總數(shù)。
point_counts
向量,指定不同視圖里點(diǎn)的數(shù)目,1xM或者M(jìn)x1向量,M是視圖數(shù)目。
image_size
圖像大小,只用在初始化內(nèi)參數(shù)時。
intrinsic_matrix
輸出內(nèi)參矩陣(A) ,如果指定CV_CALIB_USE_INTRINSIC_GUESS和(或)CV_CALIB_FIX_ASPECT_RATION,fx、 fy、 cx和cy部分或者全部必須被初始化。
distortion_coeffs
輸出大小為4x1或者1x4的向量,里面為形變參數(shù)[k1, k2, p1, p2]。
rotation_vectors
輸出大小為3xM或者M(jìn)x3的矩陣,里面為旋轉(zhuǎn)向量(旋轉(zhuǎn)矩陣的緊湊表示方式,具體參考函數(shù)cvRodrigues2)
translation_vectors
輸出大小為3xM或Mx3的矩陣,里面為平移向量。
flags
不同的標(biāo)志,可以是0,或者下面值的組合:
· CV_CALIB_USE_INTRINSIC_GUESS- 內(nèi)參數(shù)矩陣包含fx,fy,cx和cy的初始值。否則,(cx,cy)被初始化到圖像中心(這兒用到圖像大?。咕嘤米钚∑椒讲罘绞接?jì)算得到。注意,如果內(nèi)部參數(shù)已知,沒有必要使用這個函數(shù),使用cvFindExtrinsicCameraParams2則可。
· CV_CALIB_FIX_PRINCIPAL_POINT- 主點(diǎn)在全局優(yōu)化過程中不變,一直在中心位置或者在其他指定的位置(當(dāng)CV_CALIB_USE_INTRINSIC_GUESS設(shè)置的時候)。
· CV_CALIB_FIX_ASPECT_RATIO- 優(yōu)化過程中認(rèn)為fx和fy中只有一個獨(dú)立變量,保持比例fx/fy不變,fx/fy的值跟內(nèi)參數(shù)矩陣初始化時的值一樣。在這種情況下, (fx, fy)的實(shí)際初始值或者從輸入內(nèi)存矩陣中讀?。ó?dāng)CV_CALIB_USE_INTRINSIC_GUESS被指定時),或者采用估計(jì)值(后者情況中fx和fy可能被設(shè)置為任意值,只有比值被使用)。
· CV_CALIB_ZERO_TANGENT_DIST– 切向形變參數(shù)(p1, p2)被設(shè)置為0,其值在優(yōu)化過程中保持為0。
函數(shù)cvCalibrateCamera2從每個視圖中估計(jì)相機(jī)的內(nèi)參數(shù)和外參數(shù)。3維物體上的點(diǎn)和它們對應(yīng)的在每個視圖的2維投影必須被指定。這些可以通過使用一個已知幾何形狀切具有容易檢測的特征點(diǎn)的物體來實(shí)現(xiàn)。這樣的一個物體被稱作定標(biāo)設(shè)備或者定標(biāo)模式,OpenCV有內(nèi)建的把棋盤當(dāng)作定標(biāo)設(shè)備方法(參考cvFindChessboardCorners)。目前,傳入初始化的內(nèi)參數(shù)(當(dāng)CV_CALIB_USE_INTRINSIC_GUESS被設(shè)置時)只支持平面定標(biāo)設(shè)備(物體點(diǎn)的Z坐標(biāo)必須時全0或者全1)。不過3維定標(biāo)設(shè)備依然可以用在提供初始內(nèi)參數(shù)矩陣情況。在內(nèi)參數(shù)和外參數(shù)矩陣的初始值都計(jì)算出之后,它們會被優(yōu)化用來減小反投影誤差(圖像上的實(shí)際坐標(biāo)跟cvProjectPoints2計(jì)算出的圖像坐標(biāo)的差的平方和)。
Undistort2校正圖像因相機(jī)鏡頭引起的變形
void cvUndistort2( const CvArr* src, CvArr* dst,
const CvMat* intrinsic_matrix,
const CvMat* distortion_coeffs );
src
原始圖像(已經(jīng)變形的圖像)。
dst
結(jié)果圖像(已經(jīng)校正的圖像)。
intrinsic_matrix
相機(jī)內(nèi)參數(shù)矩陣,格式為 。
distortion_coeffs
四個變形系數(shù)組成的向量,大小為4x1或者1x4,格式為[k1,k2,p1,p2]。
函數(shù)cvUndistort2對圖像進(jìn)行變換來抵消徑向和切向鏡頭變形。相機(jī)參數(shù)和變形參數(shù)可以通過函數(shù)cvCalibrateCamera2取得。使用本節(jié)開始時提到的公式,對每個輸出圖像像素計(jì)算其在輸入圖像中的位置,然后輸出圖像的像素值通過雙線性插值來計(jì)算。如果圖像得分辨率跟定標(biāo)時用得圖像分辨率不一樣,fx、fy、cx和cy需要相應(yīng)調(diào)整,因?yàn)樾巫儾]有變化。
FindExtrinsicCameraParams2計(jì)算指定視圖的攝像機(jī)外參數(shù)
void cvFindExtrinsicCameraParams2 ( const CvMat*object_points,
const CvMat*image_points,
const CvMat*intrinsic_matrix,
const CvMat*distortion_coeffs,
CvMat*rotation_vector,
CvMat*translation_vector );
object_points
定標(biāo)點(diǎn)的坐標(biāo),為3xN或者Nx3的矩陣,這里N是視圖中的個數(shù)。
image_points
定標(biāo)點(diǎn)在圖像內(nèi)的坐標(biāo),為2xN或者Nx2的矩陣,這里N是視圖中的個數(shù)。
intrinsic_matrix
內(nèi)參矩陣(A) 。
distortion_coeffs
大小為4x1或者1x4的向量,里面為形變參數(shù)[k1,k2,p1,p2]。如果是NULL,所有的形變系數(shù)都為0。
rotation_vector
輸出大小為3x1或者1x3的矩陣,里面為旋轉(zhuǎn)向量(旋轉(zhuǎn)矩陣的緊湊表示方式,具體參考函數(shù)cvRodrigues2)。
translation_vector
大小為3x1或1x3的矩陣,里面為平移向量。
函數(shù)cvFindExtrinsicCameraParams2使用已知的內(nèi)參數(shù)和某個視圖的外參數(shù)來估計(jì)相機(jī)的外參數(shù)。3維物體上的點(diǎn)坐標(biāo)和相應(yīng)的2維投影必須被指定。這個函數(shù)也可以用來最小化反投影誤差。
GoodFeaturesToTrack 確定圖像的強(qiáng)角點(diǎn)
void cvGoodFeaturesToTrack( const CvArrimage, CvArr eig_image, CvArr* temp_image,
CvPoint2D32f* corners, int* corner_count,
double quality_level, double min_distance,
const CvArr* mask=NULL );
image
輸入圖像,8-位或浮點(diǎn)32-比特,單通道
eig_image
臨時浮點(diǎn)32-位圖像,尺寸與輸入圖像一致
temp_image
另外一個臨時圖像,格式與尺寸與 eig_image 一致
corners
輸出參數(shù),檢測到的角點(diǎn)
corner_count
輸出參數(shù),檢測到的角點(diǎn)數(shù)目
quality_level
最大最小特征值的乘法因子。定義可接受圖像角點(diǎn)的最小質(zhì)量因子。
min_distance
限制因子。得到的角點(diǎn)的最小距離。使用 Euclidian 距離
mask
ROI:感興趣區(qū)域。函數(shù)在ROI中計(jì)算角點(diǎn),如果 mask 為 NULL,則選擇整個圖像。
函數(shù)cvGoodFeaturesToTrack 在圖像中尋找具有大特征值的角點(diǎn)。該函數(shù),首先用cvCornerMinEigenVal 計(jì)算輸入圖像的每一個象素點(diǎn)的最小特征值,并將結(jié)果存儲到變量 eig_image 中。然后進(jìn)行非最大值抑制(僅保留3x3鄰域中的局部最大值)。下一步將最小特征值小于 quality_level?max(eig_image(x,y)) 排除掉。最后,函數(shù)確保所有發(fā)現(xiàn)的角點(diǎn)之間具有足夠的距離,(最強(qiáng)的角點(diǎn)第一個保留,然后檢查新的角點(diǎn)與已有角點(diǎn)之間的距離大于 min_distance )。
#include <cv.h>
#include <highgui.h>
#include <iostream>
using namespace std;
void PrintMat(CvMat*);
void FputMat(FILE *,CvMat *);
int main(int argc ,char * argv[])
{
/*讀入圖像*/
CvSize image_size;
int n_board=4;//圖像數(shù)目
int sn_board=0;//成功找到角點(diǎn)的圖像數(shù)目
int board_w=6;
int board_h=9;
int board_n=board_h*board_w;//每幅圖像的角點(diǎn)數(shù)
CvSize patter_size=cvSize(board_w,board_h);//每幅圖像的角點(diǎn)數(shù)
CvPoint2D32f * corners=new CvPoint2D32f[board_n];//一幅圖像的角點(diǎn)數(shù)組
CvMat * object_points= cvCreateMat(board_n*n_board,3,CV_32FC1);
CvMat * image_points=cvCreateMat(board_n*n_board,2,CV_32FC1);
CvMat * point_counts=cvCreateMat(n_board,1,CV_32SC1);
for(int i=1;i<=n_board;i++)
{
/*讀入圖像*/
char path[100]="E:\\TestCase\\CalibrationTest\\picture\\picture";
char num[10];
itoa(i,num,10);
strcat(num,".jpg");
IplImage *SourceImg=cvLoadImage(strcat(path,num),CV_LOAD_IMAGE_COLOR);
image_size=cvGetSize(SourceImg);//圖像的大小
IplImage *SourceImgGray=cvCreateImage(image_size,IPL_DEPTH_8U,1);
cvCvtColor(SourceImg,SourceImgGray,CV_BGR2GRAY);
cvNamedWindow("MyCalib",CV_WINDOW_AUTOSIZE);
cvShowImage("MyCalib",SourceImg);
cvWaitKey(NULL);
/*提取角點(diǎn)精確到亞像素*/
int corner_count;
if(0==cvFindChessboardCorners(SourceImgGray,patter_size,corners,&corner_count,CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_FILTER_QUADS))
{ cout<<"......無法找出第"<<i<<"幅圖的角點(diǎn)"<<endl;
cvWaitKey(NULL);
cvReleaseImage(&SourceImgGray);
cvReleaseImage(&SourceImg);
continue;
//return -1;
}
else
{// find specific locations of corners---yvonne
cvFindCornerSubPix(SourceImgGray,corners,corner_count,cvSize(11,11),cvSize(-1,-1),cvTermCriteria(
CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));//CvSize win 和matlab標(biāo)定工具箱類似
cvDrawChessboardCorners(SourceImg,patter_size,corners,corner_count,1);
cvShowImage("MyCalib",SourceImg);
cvSaveImage("E:\\TestCase\\CalibrationTest\\picture\\picture.jpg",SourceImg);
}
cvWaitKey(0);
for (int j=0;j<board_n;j++)
{
CV_MAT_ELEM(*image_points,float,sn_board*board_n+j,0)=corners[j].x;
CV_MAT_ELEM(*image_points,float,sn_board*board_n+j,1)=corners[j].y;
CV_MAT_ELEM(*object_points,float,sn_board*board_n+j,0)=float(j/board_w);
CV_MAT_ELEM(*object_points,float,sn_board*board_n+j,1)=float(j%board_w);
CV_MAT_ELEM(*object_points,float,sn_board*board_n+j,2)=0.0f;
CV_MAT_ELEM(*point_counts,int,sn_board,0)=board_n;
}
sn_board++;
cvReleaseImage(&SourceImgGray);
cvReleaseImage(&SourceImg);
cout<<"......成功找出第"<<i<<"幅圖的角點(diǎn)"<<endl;
}
cout<<"......一共成功獲得"<<sn_board<<"幅圖像的角點(diǎn)"<<"......無法獲得"<<n_board-sn_board<<"幅圖像的角點(diǎn)"<<endl;
//重新賦值
CvMat * object_points0= cvCreateMat(board_n*sn_board,3,CV_32FC1);
CvMat * image_points0=cvCreateMat(board_n*sn_board,2,CV_32FC1);
CvMat * point_counts0=cvCreateMat(sn_board,1,CV_32SC1);
for (int i=0;i<sn_board*board_n;i++)
{
CV_MAT_ELEM(*image_points0,float,i,0)=CV_MAT_ELEM(*image_points,float,i,0);
CV_MAT_ELEM(*image_points0,float,i,1)=CV_MAT_ELEM(*image_points,float,i,1);
CV_MAT_ELEM(*object_points0,float,i,0)=CV_MAT_ELEM(*object_points,float,i,0);
CV_MAT_ELEM(*object_points0,float,i,1)=CV_MAT_ELEM(*object_points,float,i,1);
CV_MAT_ELEM(*object_points0,float,i,2)=0.0f; //z=0
}
for (int i=0;i<sn_board;i++)
{
CV_MAT_ELEM(*point_counts0,int,i,0)=CV_MAT_ELEM(*point_counts,int,i,0);
}
cvReleaseMat(&object_points);
cvReleaseMat(&point_counts);
cvReleaseMat(&image_points);
/*攝像機(jī)標(biāo)定并求得內(nèi)部參數(shù)*/
CvMat * camera_matrix=cvCreateMat(3,3,CV_32FC1);
CvMat * distortion_coeffs=cvCreateMat(1,4,CV_32FC1);
CvMat * rotation_vectors=cvCreateMat(sn_board,3,CV_32FC1);
CvMat * translation_vectors=cvCreateMat(sn_board,3,CV_32FC1);
int flags=0;
cvCalibrateCamera2(object_points0,image_points0,point_counts0,image_size,camera_matrix
//,distortion_coeffs,NULL,NULL,flags);
,distortion_coeffs,rotation_vectors,translation_vectors,0);
//輸出結(jié)果
printf("/*****攝像機(jī)內(nèi)部參數(shù)*****/\n");
PrintMat(camera_matrix);
printf("/*****畸變參數(shù)k1,k2,p1,p2*****/\n");
PrintMat(distortion_coeffs);
cvWaitKey(0);
//保存數(shù)據(jù)
printf("/*****保存內(nèi)部參數(shù)與畸變參數(shù)*****/\n");
cvSave("camera_matrix1111.xml",camera_matrix);
cvSave("distortion_coeffs.xml",distortion_coeffs);
FILE *fp=NULL;
if ((fp=fopen("E:\\TestCase\\CalibrationTest\\camera_matrix.txt","w"))==NULL)
{
printf("無法打開文件!");
exit(1);
}
FputMat(fp,camera_matrix);
fclose(fp);
if ((fp=fopen("E:\\TestCase\\CalibrationTest\\distortion_coeffs.txt","w"))==NULL)
{
printf("無法打開文件!");
exit(1);
}
FputMat(fp,distortion_coeffs);
fclose(fp);
//誤差分析
CvMat * object_points2=cvCreateMat(board_n,3,CV_32FC1);
CvMat * image_points2=cvCreateMat(board_n,2,CV_32FC1);
CvMat * rotation_vectors2=cvCreateMat(1,3,CV_32FC1);
CvMat * translation_vectors2=cvCreateMat(1,3,CV_32FC1);
CvMat * Err=cvCreateMat(sn_board*board_n,2,CV_32FC1);
for(int k=0;k<sn_board;k++)
{
for (int i=0;i<board_n;i++)//取一幅圖的數(shù)據(jù)
{
CV_MAT_ELEM(*object_points2,float,i,0)=CV_MAT_ELEM(*object_points0,float,k*board_n+i,0);
CV_MAT_ELEM(*object_points2,float,i,1)=CV_MAT_ELEM(*object_points0,float,k*board_n+i,1);
CV_MAT_ELEM(*object_points2,float,i,2)=0.0f;
}
for (int i=0;i<3;i++)
{
CV_MAT_ELEM(*rotation_vectors2,float,0,i)=CV_MAT_ELEM(*rotation_vectors,float,k,i);
CV_MAT_ELEM(*translation_vectors2,float,0,i)=CV_MAT_ELEM(*translation_vectors,float,k,i);
}
cvProjectPoints2(object_points2,rotation_vectors2,translation_vectors2,camera_matrix,
distortion_coeffs,image_points2);
for (int i=0;i<board_n;i++)
{
CV_MAT_ELEM(*Err,float,k*board_n+i,0)=CV_MAT_ELEM(*image_points0,float,k*board_n+i,0)-CV_MAT_ELEM(*image_points2,float,i,0);
CV_MAT_ELEM(*Err,float,k*board_n+i,1)=CV_MAT_ELEM(*image_points0,float,k*board_n+i,1)-CV_MAT_ELEM(*image_points2,float,i,1);
}
}
//PrintMat(Err);
CvMat * Err_abs=cvCreateMat(board_n*sn_board,2,CV_32FC1);
cvAbs(Err,Err_abs);
CvScalar Dmean;
CvScalar Ddev;
cvAvgSdv(Err_abs,&Dmean,&Ddev);
printf("/*****反投影誤差分析*****/\n");
cout<<"......絕對值誤差矩陣的平均值:"<<endl;
cout<<Dmean.val[0]<<endl;
cout<<"......絕對值誤差矩陣的標(biāo)準(zhǔn)差:"<<endl;
cout<<Ddev.val[0]<<endl;
cout<<"......保存誤差矩陣"<<endl;
cvSave("err.xml",Err);
if ((fp=fopen("E:\\TestCase\\CalibrationTest\\err.txt","w"))==NULL)
{
printf("無法打開文件!");
exit(1);
}
FputMat(fp,Err);
fclose(fp);
cvReleaseMat (&object_points2);
cvReleaseMat (&image_points2);
cvReleaseMat (&rotation_vectors2);
cvReleaseMat (&translation_vectors2);
cvReleaseMat (&Err);
cvReleaseMat (&Err_abs);
//釋放總變量
cvWaitKey(NULL);
cvReleaseMat(&object_points0);
cvReleaseMat(&point_counts0);
cvReleaseMat(&image_points0);
cvReleaseMat(&camera_matrix);
cvReleaseMat(&distortion_coeffs);
cvReleaseMat(&rotation_vectors);
cvReleaseMat(&translation_vectors);
delete [] corners;
cvDestroyWindow("MyCalib");
}
void PrintMat(CvMat* arry)
{
for (int i=0;i<arry->rows;i++)
{
for (int j=0;j<arry->cols;j++)
{
printf("%f",CV_MAT_ELEM(*arry,float,i,j));
if(j<arry->cols-1)
printf(",");
}
printf("\n");
}
}
void FputMat(FILE * fp,CvMat * arry)
{
for (int i=0;i<arry->rows;i++)
{
for (int j=0;j<arry->cols;j++)
{
fprintf(fp,"%f",CV_MAT_ELEM(*arry,float,i,j));
if(j<arry->cols-1)
fprintf(fp,",");
}
fprintf(fp,"\n");
}
}

