opencv处理函数记录_转自opencv中文网站
Cv圖像處理
Wikipedia,自由的百科全書
注意:本章描述圖像處理和分析的一些函數。大多數函數都是針對兩維象素數組的,這里,我們稱這些數組為“圖像”,但是它們不一定非得是IplImage 結構,也可以是CvMat或者CvMatND結構。
目錄[隱藏]
|
梯度、邊緣和角點
[ 編輯]Sobel
使用擴展 Sobel 算子計算一階、二階、三階或混合圖像差分
void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 ); src函數 cvSobel 通過對圖像用相應的內核進行卷積操作來計算圖像差分:
由于Sobel 算子結合了 Gaussian 平滑和微分,所以,其結果或多或少對噪聲有一定的魯棒性。通常情況,函數調用采用如下參數 (xorder=1, yorder=0, aperture_size=3) 或 (xorder=0, yorder=1, aperture_size=3) 來計算一階 x- 或 y- 方向的圖像差分。第一種情況對應:
核。
第二種對應:
或者
核的選則依賴于圖像原點的定義 (origin 來自 IplImage 結構的定義)。由于該函數不進行圖像尺度變換,所以和輸入圖像(數組)相比,輸出圖像(數組)的元素通常具有更大的絕對數值(譯者注:即像素的位深)。為防止溢出,當輸入圖像是 8 位的,要求輸出圖像是 16 位的。當然可以用函數 cvConvertScale 或 cvConvertScaleAbs 把運算結果(dst)轉換為 8 位的。除了8-位圖像,函數也接受 32-位 浮點數圖像。所有輸入和輸出圖像都必須是單通道的,并且具有相同的圖像尺寸或者ROI尺寸。
[ 編輯]Laplace
計算圖像的 Laplacian 變換
void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 ); src函數 cvLaplace 計算輸入圖像的 Laplacian變換,方法是先用 sobel 算子計算二階 x- 和 y- 差分,再求和:
對 aperture_size=1 則給出最快計算結果,相當于對圖像采用如下內核做卷積:
類似于 cvSobel 函數,該函數也不作圖像的尺度變換,所支持的輸入、輸出圖像類型的組合和cvSobel一致。
[ 編輯]Canny
采用 Canny 算法做邊緣檢測
void cvCanny( const CvArr* image, CvArr* edges, double threshold1,double threshold2, int aperture_size=3 ); image函數 cvCanny 采用 CANNY 算法發現輸入圖像的邊緣而且在輸出圖像中標識這些邊緣。threshold1和threshold2 當中的小閾值用來控制邊緣連接,大的閾值用來控制強邊緣的初始分割。
- 注意事項:cvCanny只接受單通道圖像作為輸入。
- 外部鏈接:經典的canny自調整閾值算法的一個opencv的實現見在OpenCV中自適應確定canny算法的分割門限
PreCornerDetect
計算用于角點檢測的特征圖,
void cvPreCornerDetect( const CvArr* image, CvArr* corners, int aperture_size=3 ); image函數 cvPreCornerDetect 計算函數 其中 表示一階圖像差分, 表示二階圖像差分。 角點被認為是函數的局部最大值:
// 假設圖像格式為浮點數 IplImage* corners = cvCloneImage(image); IplImage* dilated_corners = cvCloneImage(image); IplImage* corner_mask = cvCreateImage( cvGetSize(image), 8, 1 ); cvPreCornerDetect( image, corners, 3 ); cvDilate( corners, dilated_corners, 0, 1 ); cvSub( corners, dilated_corners, corners ); cvCmpS( corners, 0, corner_mask, CV_CMP_GE ); cvReleaseImage( &corners ); cvReleaseImage( &dilated_corners ); [ 編輯]CornerEigenValsAndVecs
計算圖像塊的特征值和特征向量,用于角點檢測
void cvCornerEigenValsAndVecs( const CvArr* image, CvArr* eigenvv,int block_size, int aperture_size=3 ); image對每個象素,函數 cvCornerEigenValsAndVecs 考慮 block_size × block_size 大小的鄰域 S(p),然后在鄰域上計算圖像差分的相關矩陣:
然后它計算矩陣的特征值和特征向量,并且按如下方式(λ1, λ2, x1, y1, x2, y2)存儲這些值到輸出圖像中,其中
CornerMinEigenVal
計算梯度矩陣的最小特征值,用于角點檢測
void cvCornerMinEigenVal( const CvArr* image, CvArr* eigenval, int block_size, int aperture_size=3 ); image函數 cvCornerMinEigenVal 與 cvCornerEigenValsAndVecs 類似,但是它僅僅計算和存儲每個象素點差分相關矩陣的最小特征值,即前一個函數的 min(λ1, λ2)
[ 編輯]CornerHarris
哈里斯(Harris)角點檢測
void cvCornerHarris( const CvArr* image, CvArr* harris_responce, int block_size, int aperture_size=3, double k=0.04 ); image保存到輸出圖像中。輸入圖像中的角點在輸出圖像中由局部最大值表示。
[ 編輯]FindCornerSubPix
精確角點位置
void cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners,int count, CvSize win, CvSize zero_zone,CvTermCriteria criteria ); image函數 cvFindCornerSubPix 通過迭代來發現具有子象素精度的角點位置,或如圖所示的放射鞍點(radial saddle points)。
子象素級角點定位的實現是基于對向量正交性的觀測而實現的,即從中央點q到其鄰域點p 的向量和p點處的圖像梯度正交(服從圖像和測量噪聲)。考慮以下的表達式:
εi=DIpiT?(q-pi)其中,DIpi表示在q的一個鄰域點pi處的圖像梯度,q的值通過最小化εi得到。通過將εi設為0,可以建立系統方程如下:
sumi(DIpi?DIpiT)?q - sumi(DIpi?DIpiT?pi) = 0其中q的鄰域(搜索窗)中的梯度被累加。調用第一個梯度參數G和第二個梯度參數b,得到:
q=G-1?b該算法將搜索窗的中心設為新的中心q,然后迭代,直到找到低于某個閾值點的中心位置。
[ 編輯]GoodFeaturesToTrack
確定圖像的強角點
void cvGoodFeaturesToTrack( const CvArr* image, CvArr* eig_image, CvArr* temp_image,CvPoint2D32f* corners, int* corner_count,double quality_level, double min_distance,const CvArr* mask=NULL ); image函數 cvGoodFeaturesToTrack 在圖像中尋找具有大特征值的角點。該函數,首先用cvCornerMinEigenVal 計算輸入圖像的每一個象素點的最小特征值,并將結果存儲到變量 eig_image 中。然后進行非最大值抑制(僅保留3x3鄰域中的局部最大值)。下一步將最小特征值小于 quality_level?max(eig_image(x,y)) 排除掉。最后,函數確保所有發現的角點之間具有足夠的距離,(最強的角點第一個保留,然后檢查新的角點與已有角點之間的距離大于 min_distance )。
[ 編輯]采樣、插值和幾何變換
[ 編輯]InitLineIterator
初始化線段迭代器
int cvInitLineIterator( const CvArr* image, CvPoint pt1, CvPoint pt2,CvLineIterator* line_iterator, int connectivity=8 ); image函數 cvInitLineIterator 初始化線段迭代器,并返回兩點之間的象素點數目。兩個點必須在圖像內。當迭代器初始化后,連接兩點的光柵線上所有點,都可以連續通過調用 CV_NEXT_LINE_POINT 來得到。線段上的點是使用 4-連通或8-連通利用 Bresenham 算法逐點計算的。
例子:使用線段迭代器計算彩色線上象素值的和
CvScalar sum_line_pixels( IplImage* image, CvPoint pt1, CvPoint pt2 ) {CvLineIterator iterator;int blue_sum = 0, green_sum = 0, red_sum = 0;int count = cvInitLineIterator( image, pt1, pt2, &iterator, 8 );for( int i = 0; i < count; i++ ){blue_sum += iterator.ptr[0];green_sum += iterator.ptr[1];red_sum += iterator.ptr[2];CV_NEXT_LINE_POINT(iterator);/* print the pixel coordinates: demonstrates how to calculate the coordinates */{int offset, x, y;/* assume that ROI is not set, otherwise need to take it into account. */offset = iterator.ptr - (uchar*)(image->imageData);y = offset/image->widthStep;x = (offset - y*image->widthStep)/(3*sizeof(uchar) /* size of pixel */);printf("(%d,%d)\n", x, y );}}return cvScalar( blue_sum, green_sum, red_sum ); } [ 編輯]SampleLine
將圖像上某一光柵線上的像素數據讀入緩沖區
int cvSampleLine( const CvArr* image, CvPoint pt1, CvPoint pt2,void* buffer, int connectivity=8 ); image函數 cvSampleLine 實現了線段迭代器的一個特殊應用。它讀取由 pt1 和 pt2 兩點確定的線段上的所有圖像點,包括終點,并存儲到緩存中。
[ 編輯]GetRectSubPix
從圖像中提取象素矩形,使用子象素精度
void cvGetRectSubPix( const CvArr* src, CvArr* dst, CvPoint2D32f center ); src函數 cvGetRectSubPix 從圖像 src 中提取矩形:
dst(x, y) = src(x + center.x - (width(dst)-1)*0.5, y + center.y - (height(dst)-1)*0.5)其中非整數象素點坐標采用雙線性插值提取。對多通道圖像,每個通道獨立單獨完成提取。盡管函數要求矩形的中心一定要在輸入圖像之中,但是有可能出現矩形的一部分超出圖像邊界的情況,這時,該函數復制邊界的模識(hunnish:即用于矩形相交的圖像邊界線段的象素來代替矩形超越部分的象素)。
[ 編輯]GetQuadrangleSubPix
提取象素四邊形,使用子象素精度
void cvGetQuadrangleSubPix( const CvArr* src, CvArr* dst, const CvMat* map_matrix ); src函數 cvGetQuadrangleSubPix 以子象素精度從圖像 src 中提取四邊形,使用子象素精度,并且將結果存儲于 dst ,計算公式是:
dst(x + width(dst) / 2,y + height(dst) / 2) = src(A11x + A12y + b1,A21x + A22y + b2)
其中 A和 b 均來自映射矩陣(譯者注:A, b為幾何形變參數) ,映射矩陣為:
其中在非整數坐標 的象素點值通過雙線性變換得到。當函數需要圖像邊界外的像素點時,使用重復邊界模式(replication border mode)恢復出所需的值。多通道圖像的每一個通道都單獨計算。
例子:使用 cvGetQuadrangleSubPix 進行圖像旋轉
#include "cv.h" #include "highgui.h" #include "math.h"int main( int argc, char** argv ) {IplImage* src;/* the first command line parameter must be image file name */if( argc==2 && (src = cvLoadImage(argv[1], -1))!=0){IplImage* dst = cvCloneImage( src );int delta = 1;int angle = 0;cvNamedWindow( "src", 1 );cvShowImage( "src", src );for(;;){float m[6];double factor = (cos(angle*CV_PI/180.) + 1.1)*3;CvMat M = cvMat( 2, 3, CV_32F, m );int w = src->width;int h = src->height;m[0] = (float)(factor*cos(-angle*2*CV_PI/180.));m[1] = (float)(factor*sin(-angle*2*CV_PI/180.));m[2] = w*0.5f;m[3] = -m[1];m[4] = m[0];m[5] = h*0.5f;cvGetQuadrangleSubPix( src, dst, &M, 1, cvScalarAll(0));cvNamedWindow( "dst", 1 );cvShowImage( "dst", dst );if( cvWaitKey(5) == 27 )break;angle = (angle + delta) % 360;}}return 0; } [ 編輯]Resize
圖像大小變換
void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR ); src- CV_INTER_NN - 最近鄰插值,
- CV_INTER_LINEAR - 雙線性插值 (缺省使用)
- CV_INTER_AREA - 使用象素關系重采樣。當圖像縮小時候,該方法可以避免波紋出現。當圖像放大時,類似于 CV_INTER_NN 方法..
- CV_INTER_CUBIC - 立方插值.
函數 cvResize 將圖像 src 改變尺寸得到與 dst 同樣大小。若設定 ROI,函數將按常規支持 ROI.
[ 編輯]WarpAffine
對圖像做仿射變換
void cvWarpAffine( const CvArr* src, CvArr* dst, const CvMat* map_matrix,int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,CvScalar fillval=cvScalarAll(0) ); src- CV_WARP_FILL_OUTLIERS - 填充所有輸出圖像的象素。如果部分象素落在輸入圖像的邊界外,那么它們的值設定為 fillval.
- CV_WARP_INVERSE_MAP - 指定 map_matrix 是輸出圖像到輸入圖像的反變換,因此可以直接用來做象素插值。否則, 函數從 map_matrix 得到反變換。
函數 cvWarpAffine 利用下面指定的矩陣變換輸入圖像:
- 如果沒有指定 CV_WARP_INVERSE_MAP , ,
- 否則,
函數與 cvGetQuadrangleSubPix 類似,但是不完全相同。 cvWarpAffine 要求輸入和輸出圖像具有同樣的數據類型,有更大的資源開銷(因此對小圖像不太合適)而且輸出圖像的部分可以保留不變。而 cvGetQuadrangleSubPix 可以精確地從8位圖像中提取四邊形到浮點數緩存區中,具有比較小的系統開銷,而且總是全部改變輸出圖像的內容。
要變換稀疏矩陣,使用 cxcore 中的函數 cvTransform 。
[ 編輯]GetAffineTransform
由三個不共線點計算仿射變換
CvMat* cvGetAffineTransform( const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* map_matrix ); src函數cvGetAffineTransform計算滿足以下關系的仿射變換矩陣:
2DRotationMatrix
計算二維旋轉的仿射變換矩陣
CvMat* cv2DRotationMatrix( CvPoint2D32f center, double angle,double scale, CvMat* map_matrix ); center函數 cv2DRotationMatrix 計算矩陣:
[ α β | (1-α)*center.x - β*center.y ] [ -β α | β*center.x + (1-α)*center.y ]where α=scale*cos(angle), β=scale*sin(angle)該變換并不改變原始旋轉中心點的坐標,如果這不是操作目的,則可以通過調整平移量改變其坐標(譯者注:通過簡單的推導可知,仿射變換的實現是首先將旋轉中心置為坐標原點,再進行旋轉和尺度變換,最后重新將坐標原點設定為輸入圖像的左上角,這里的平移量是center.x, center.y).
[ 編輯]WarpPerspective
對圖像進行透視變換
void cvWarpPerspective( const CvArr* src, CvArr* dst, const CvMat* map_matrix,int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,CvScalar fillval=cvScalarAll(0) ); src- CV_WARP_FILL_OUTLIERS - 填充所有縮小圖像的象素。如果部分象素落在輸入圖像的邊界外,那么它們的值設定為 fillval.
- CV_WARP_INVERSE_MAP - 指定 matrix 是輸出圖像到輸入圖像的反變換,因此可以直接用來做象素插值。否則, 函數從 map_matrix 得到反變換。
函數 cvWarpPerspective 利用下面指定矩陣變換輸入圖像:
- 如果沒有指定 CV_WARP_INVERSE_MAP , ,
- 否則,
要變換稀疏矩陣,使用 cxcore 中的函數 cvTransform 。
[ 編輯]WarpPerspectiveQMatrix
用4個對應點計算透視變換矩陣
CvMat* cvWarpPerspectiveQMatrix( const CvPoint2D32f* src,const CvPoint2D32f* dst,CvMat* map_matrix ); src函數 cvWarpPerspectiveQMatrix 計算透視變換矩陣,使得:
(tix'i,tiy'i,ti)T=matrix?(xi,yi,1)T其中 dst(i)=(x'i,y'i), src(i)=(xi,yi), i=0..3.
[ 編輯]GetPerspectiveTransform
由四邊形的4個點計算透射變換
CvMat* cvGetPerspectiveTransform( const CvPoint2D32f* src, const CvPoint2D32f* dst,CvMat* map_matrix );#define cvWarpPerspectiveQMatrix cvGetPerspectiveTransform src函數cvGetPerspectiveTransform計算滿足以下關系的透射變換矩陣:
Remap
對圖像進行普通幾何變換
void cvRemap( const CvArr* src, CvArr* dst,const CvArr* mapx, const CvArr* mapy,int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,CvScalar fillval=cvScalarAll(0) ); src- CV_WARP_FILL_OUTLIERS - 填充邊界外的像素. 如果輸出圖像的部分象素落在變換后的邊界外,那么它們的值設定為 fillval。
函數 cvRemap 利用下面指定的矩陣變換輸入圖像:
dst(x,y)<-src(mapx(x,y),mapy(x,y))與其它幾何變換類似,可以使用一些插值方法(由用戶指定,譯者注:同cvResize)來計算非整數坐標的像素值。
[ 編輯]LogPolar
把圖像映射到極指數空間
void cvLogPolar( const CvArr* src, CvArr* dst,CvPoint2D32f center, double M,int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS ); src- CV_WARP_FILL_OUTLIERS -填充輸出圖像所有像素,如果這些點有和外點對應的,則置零。
- CV_WARP_INVERSE_MAP - 表示矩陣由輸出圖像到輸入圖像的逆變換,并且因此可以直接用于像素插值。否則,函數從map_matrix中尋找逆變換。
函數cvLogPolar用以下變換變換輸入圖像:
正變換 (CV_WARP_INVERSE_MAP 未置位):
dst(phi,rho)<-src(x,y)逆變換 (CV_WARP_INVERSE_MAP 置位):
dst(x,y)<-src(phi,rho),這里,
rho=M+log(sqrt(x2+y2)) phi=atan(y/x)此函數模仿人類視網膜中央凹視力,并且對于目標跟蹤等可用于快速尺度和旋轉變換不變模板匹配。
Example. Log-polar transformation.
#include <cv.h> #include <highgui.h>int main(int argc, char** argv) {IplImage* src;if(argc == 2 && ((src=cvLoadImage(argv[1],1)) != 0 )){IplImage* dst = cvCreateImage( cvSize(256,256), 8, 3 );IplImage* src2 = cvCreateImage( cvGetSize(src), 8, 3 );cvLogPolar( src, dst, cvPoint2D32f(src->width/2,src->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );cvLogPolar( dst, src2, cvPoint2D32f(src->width/2,src->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS+CV_WARP_INVERSE_MAP );cvNamedWindow( "log-polar", 1 );cvShowImage( "log-polar", dst );cvNamedWindow( "inverse log-polar", 1 );cvShowImage( "inverse log-polar", src2 );cvWaitKey();}return 0; }And this is what the program displays when opencv/samples/c/fruits.jpg is passed to it
[ 編輯]形態學操作
[ 編輯]CreateStructuringElementEx
創建結構元素
IplConvKernel* cvCreateStructuringElementEx( int cols, int rows, int anchor_x, int anchor_y,int shape, int* values=NULL ); cols- CV_SHAPE_RECT, 長方形元素;
- CV_SHAPE_CROSS, 交錯元素 a cross-shaped element;
- CV_SHAPE_ELLIPSE, 橢圓元素;
- CV_SHAPE_CUSTOM, 用戶自定義元素。這種情況下參數 values 定義了 mask,即象素的那個鄰域必須考慮。
函數 cv CreateStructuringElementEx 分配和填充結構 IplConvKernel, 它可作為形態操作中的結構元素。
[ 編輯]ReleaseStructuringElement
刪除結構元素
void cvReleaseStructuringElement( IplConvKernel** element ); element函數 cvReleaseStructuringElement 釋放結構 IplConvKernel 。如果 *element 為 NULL, 則函數不作用。
[ 編輯]Erode
使用任意結構元素腐蝕圖像
void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 ); src函數 cvErode 對輸入圖像使用指定的結構元素進行腐蝕,該結構元素決定每個具有最小值象素點的鄰域形狀:
dst=erode(src,element): dst(x,y)=min((x',y') in element))src(x+x',y+y')函數可能是本地操作,不需另外開辟存儲空間的意思。腐蝕可以重復進行 (iterations) 次. 對彩色圖像,每個彩色通道單獨處理。
[ 編輯]Dilate
使用任意結構元素膨脹圖像
void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 ); src函數 cvDilate 對輸入圖像使用指定的結構元進行膨脹,該結構決定每個具有最小值象素點的鄰域形狀:
dst=dilate(src,element): dst(x,y)=max((x',y') in element))src(x+x',y+y')函數支持(in-place)模式。膨脹可以重復進行 (iterations) 次. 對彩色圖像,每個彩色通道單獨處理。
[ 編輯]MorphologyEx
高級形態學變換
void cvMorphologyEx( const CvArr* src, CvArr* dst, CvArr* temp,IplConvKernel* element, int operation, int iterations=1 ); src函數 cvMorphologyEx 在膨脹和腐蝕基本操作的基礎上,完成一些高級的形態變換:
開運算臨時圖像 temp 在形態梯度以及對“頂帽”和“黑帽”操作時的 in-place 模式下需要。
[ 編輯]濾波器與色彩空間變換
[ 編輯]Smooth
各種方法的圖像平滑
void cvSmooth( const CvArr* src, CvArr* dst,int smoothtype=CV_GAUSSIAN,int param1=3, int param2=0, double param3=0, double param4=0 ); src- CV_BLUR_NO_SCALE (簡單不帶尺度變換的模糊) - 對每個象素的 param1×param2 領域求和。如果鄰域大小是變化的,可以事先利用函數 cvIntegral 計算積分圖像。
- CV_BLUR (simple blur) - 對每個象素param1×param2鄰域 求和并做尺度變換 1/(param1?param2).
- CV_GAUSSIAN (gaussian blur) - 對圖像進行核大小為 param1×param2 的高斯卷積
- CV_MEDIAN (median blur) - 對圖像進行核大小為param1×param1 的中值濾波 (i.e. 鄰域是方的).
- CV_BILATERAL (雙向濾波) - 應用雙向 3x3 濾波,彩色 sigma=param1,空間 sigma=param2. 關于雙向濾波,可參考 http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
對小的卷積核 (3×3 to 7×7) 使用如上公式所示的標準 sigma 速度會快。如果 param3 不為零,而 param1 和 param2 為零,則核大小有 sigma 計算 (以保證足夠精確的操作).
函數 cvSmooth 可使用上面任何一種方法平滑圖像。每一種方法都有自己的特點以及局限。
沒有縮放的圖像平滑僅支持單通道圖像,并且支持8位到16位的轉換(與cvSobel和cvaplace相似)和32位浮點數到32位浮點數的變換格式。
簡單模糊和高斯模糊支持 1- 或 3-通道, 8-比特 和 32-比特 浮點圖像。這兩種方法可以(in-place)方式處理圖像。
中值和雙向濾波工作于 1- 或 3-通道, 8-位圖像,但是不能以 in-place 方式處理圖像.
中值濾波法對消除椒鹽噪音非常有效,在光學測量條紋圖象的相位分析處理方法中有特殊作用,但在條紋中心分析方法中作用不大。中值濾波在圖像處理中,常用于用來保護邊緣信息,是經典的平滑噪聲的方法
中值濾波原理中值濾波是基于排序統計理論的一種能有效抑制噪聲的非線性信號處理技術,中值濾波的基本原理是把數字圖像或數字序列中一點的值用該點的一個拎域中各點值的中值代替,讓周圍的像素值接近的值,從而消除孤立的噪聲點。方法是去某種結構的二維滑動模板,將板內像素按照像素值的大小進行排序,生成單調上升(或下降)的為二維數據序列。二維中值濾波輸出為g(x,y)=med{f(x-k,y-l),(k,l∈W)} ,其中,f(x,y),g(x,y)分別為原始圖像和處理后圖像。W為二維模板,通常為2*2,3*3區域,也可以是不同的的形狀,如線狀,圓形,十字形,圓環形等。
高斯濾波高斯濾波實質上是一種信號的濾波器,其用途是信號的平滑處理,我們知道數字圖像用于后期應用,其噪聲是最大的問題,由于誤差會累計傳遞等原因,很多圖像處理教材會在很早的時候介紹Gauss濾波器,用于得到信噪比SNR較高的圖像(反應真實信號)。于此相關的有Gauss-Lapplace變換,其實就是為了得到較好的圖像邊緣,先對圖像做Gauss平滑濾波,剔除噪聲,然后求二階導矢,用二階導的過零點確定邊緣,在計算時也是頻域乘積=>空域卷積。
濾波器就是建立的一個數學模型,通過這個模型來將圖像數據進行能量轉化,能量低的就排除掉,噪聲就是屬于低能量部分
其實編程運算的話就是一個模板運算,拿圖像的八連通區域來說,中間點的像素值就等于八連通區的像素值的均值,這樣達到平滑的效果
若使用理想濾波器,會在圖像中產生振鈴現象。采用高斯濾波器的話,系統函數是平滑的,避免了振鈴現象。
[ 編輯]Filter2D
對圖像做卷積
void cvFilter2D( const CvArr* src, CvArr* dst,const CvMat* kernel,CvPoint anchor=cvPoint(-1,-1)); src函數 cvFilter2D 對圖像進行線性濾波,支持 In-place 操作。當核運算部分超出輸入圖像時,函數從最近鄰的圖像內部象素插值得到邊界外面的象素值。
[ 編輯]CopyMakeBorder
復制圖像并且制作邊界。
void cvCopyMakeBorder( const CvArr* src, CvArr* dst, CvPoint offset,int bordertype, CvScalar value=cvScalarAll(0) ); src函數cvCopyMakeBorder拷貝輸入2維陣列到輸出陣列的內部并且在拷貝區域的周圍制作一個指定類型的邊界。函數可以用來模擬和嵌入在指定算法實現中的邊界不同的類型。例如:和opencv中大多數其他濾波函數一樣,一些形態學函數內部使用復制邊界類型,但是用戶可能需要零邊界或者填充為1或255的邊界。
[ 編輯]Integral
計算積分圖像
void cvIntegral( const CvArr* image, CvArr* sum, CvArr* sqsum=NULL, CvArr* tilted_sum=NULL ); image函數 cvIntegral 計算一次或高次積分圖像:
| sum(X,Y) = | ∑ | image(x,y) |
| ? | x < X,y < Y | ? |
| sqsum(X,Y) = | ∑ | image(x,y)2 |
| ? | x < X,y < Y | ? |
| tilted_sum(X,Y) = | ∑ | image(x,y) |
| ? | y < Y, | x ? X | < y | ? |
利用積分圖像,可以計算在某象素的上-右方的或者旋轉的矩形區域中進行求和、求均值以及標準方差的計算,并且保證運算的復雜度為O(1)。例如:
因此可以在變化的窗口內做快速平滑或窗口相關等操作。
[ 編輯]CvtColor
色彩空間轉換
void cvCvtColor( const CvArr* src, CvArr* dst, int code ); src函數 cvCvtColor 將輸入圖像從一個色彩空間轉換為另外一個色彩空間。函數忽略 IplImage 頭中定義的 colorModel 和 channelSeq 域,所以輸入圖像的色彩空間應該正確指定 (包括通道的順序,對RGB空間而言,BGR 意味著布局為 B0 G0 R0 B1 G1 R1 ... 層疊的 24-位格式,而 RGB 意味著布局為 R0 G0 B0 R1 G1 B1 ... 層疊的24-位格式. 函數做如下變換:
RGB 空間內部的變換,如增加/刪除 alpha 通道,反相通道順序,到16位 RGB彩色或者15位RGB彩色的正逆轉換(Rx5:Gx6:Rx5),以及到灰度圖像的正逆轉換,使用:
RGB[A]->Gray: Y=0.212671*R + 0.715160*G + 0.072169*B + 0*A Gray->RGB[A]: R=Y G=Y B=Y A=0所有可能的圖像色彩空間的相互變換公式列舉如下:
RGB<=>XYZ (CV_BGR2XYZ, CV_RGB2XYZ, CV_XYZ2BGR, CV_XYZ2RGB):
|X| |0.412411 0.357585 0.180454| |R| |Y| = |0.212649 0.715169 0.072182|*|G| |Z| |0.019332 0.119195 0.950390| |B||R| | 3.240479 -1.53715 -0.498535| |X| |G| = |-0.969256 1.875991 0.041556|*|Y| |B| | 0.055648 -0.204043 1.057311| |Z|RGB<=>YCrCb (CV_BGR2YCrCb, CV_RGB2YCrCb, CV_YCrCb2BGR, CV_YCrCb2RGB)
Y=0.299*R + 0.587*G + 0.114*B Cr=(R-Y)*0.713 + 128 Cb=(B-Y)*0.564 + 128R=Y + 1.403*(Cr - 128) G=Y - 0.344*(Cr - 128) - 0.714*(Cb - 128) B=Y + 1.773*(Cb - 128)RGB=>HSV (CV_BGR2HSV,CV_RGB2HSV)
V=max(R,G,B) S=(V-min(R,G,B))*255/V if V!=0, 0 otherwise(G - B)*60/S, if V=R H= 180+(B - R)*60/S, if V=G240+(R - G)*60/S, if V=Bif H<0 then H=H+360使用上面從 0° 到 360° 變化的公式計算色調(hue)值,確保它們被 2 除后能適用于8位。RGB=>Lab (CV_BGR2Lab, CV_RGB2Lab)
|X| |0.433910 0.376220 0.189860| |R/255| |Y| = |0.212649 0.715169 0.072182|*|G/255| |Z| |0.017756 0.109478 0.872915| |B/255|L = 116*Y1/3 for Y>0.008856 L = 903.3*Y for Y<=0.008856a = 500*(f(X)-f(Y)) b = 200*(f(Y)-f(Z)) where f(t)=t1/3 for t>0.008856f(t)=7.787*t+16/116 for t<=0.008856上面的公式可以參考 http://www.cica.indiana.edu/cica/faq/color_spaces/color.spaces.htmlRGB=>HLS (CV_BGR2HLS, CV_RGB2HLS)
HSL 表示 hue(色相)、saturation(飽和度)、lightness(亮度)。有的地方也稱為HSI,其中I表示intensity(強度)
轉換公式見http://zh.wikipedia.org/wiki/HSL_%E8%89%B2%E5%BD%A9%E7%A9%BA%E9%97%B4
Bayer=>RGB (CV_BayerBG2BGR, CV_BayerGB2BGR, CV_BayerRG2BGR, CV_BayerGR2BGR, CV_BayerBG2RGB, CV_BayerRG2BGR, CV_BayerGB2RGB, CV_BayerGR2BGR, CV_BayerRG2RGB, CV_BayerBG2BGR, CV_BayerGR2RGB, CV_BayerGB2BGR)
Bayer 模式被廣泛應用于 CCD 和 CMOS 攝像頭. 它允許從一個單獨平面中得到彩色圖像,該平面中的 R/G/B 象素點被安排如下:
| R | G | R | G | R |
| G | B | G | B | G |
| R | G | R | G | R |
| G | B | G | B | G |
| R | G | R | G | R |
| G | B | G | B | G |
對像素輸出的RGB份量由該像素的1、2或者4鄰域中具有相同顏色的點插值得到。以上的模式可以通過向左或者向上平移一個像素點來作一些修改。轉換常量CV_BayerC1C22{RGB|RGB}中的兩個字母C1和C2表示特定的模式類型:顏色份量分別來自于第二行,第二和第三列。比如說,上述的模式具有很流行的"BG"類型。
[ 編輯]Threshold
對數組元素進行固定閾值操作
void cvThreshold( const CvArr* src, CvArr* dst, double threshold,double max_value, int threshold_type ); src函數 cvThreshold 對單通道數組應用固定閾值操作。該函數的典型應用是對灰度圖像進行閾值操作得到二值圖像。(cvCmpS 也可以達到此目的) 或者是去掉噪聲,例如過濾很小或很大象素值的圖像點。本函數支持的對圖像取閾值的方法由 threshold_type 確定:
threshold_type=CV_THRESH_BINARY: dst(x,y) = max_value, if src(x,y)>threshold0, otherwisethreshold_type=CV_THRESH_BINARY_INV: dst(x,y) = 0, if src(x,y)>thresholdmax_value, otherwisethreshold_type=CV_THRESH_TRUNC: dst(x,y) = threshold, if src(x,y)>thresholdsrc(x,y), otherwisethreshold_type=CV_THRESH_TOZERO: dst(x,y) = src(x,y), if (x,y)>threshold0, otherwisethreshold_type=CV_THRESH_TOZERO_INV: dst(x,y) = 0, if src(x,y)>thresholdsrc(x,y), otherwise下面是圖形化的閾值描述:
[ 編輯]AdaptiveThreshold
自適應閾值方法
void cvAdaptiveThreshold( const CvArr* src, CvArr* dst, double max_value,int adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C,int threshold_type=CV_THRESH_BINARY,int block_size=3, double param1=5 ); src- CV_THRESH_BINARY,
- CV_THRESH_BINARY_INV
函數 cvAdaptiveThreshold 將灰度圖像變換到二值圖像,采用下面公式:
threshold_type=CV_THRESH_BINARY: dst(x,y) = max_value, if src(x,y)>T(x,y)0, otherwisethreshold_type=CV_THRESH_BINARY_INV: dst(x,y) = 0, if src(x,y)>T(x,y)max_value, otherwise其中 TI 是為每一個象素點單獨計算的閾值
對方法 CV_ADAPTIVE_THRESH_MEAN_C,先求出塊中的均值,再減掉param1。
對方法 CV_ADAPTIVE_THRESH_GAUSSIAN_C ,先求出塊中的加權和(gaussian), 再減掉param1。
[ 編輯]金字塔及其應用
[ 編輯]PyrDown
圖像的下采樣
void cvPyrDown( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 ); src函數 cvPyrDown 使用 Gaussian 金字塔分解對輸入圖像向下采樣。首先它對輸入圖像用指定濾波器進行卷積,然后通過拒絕偶數的行與列來下采樣圖像。
[ 編輯]PyrUp
圖像的上采樣
void cvPyrUp( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 ); src函數 cvPyrUp 使用Gaussian 金字塔分解對輸入圖像向上采樣。首先通過在圖像中插入 0 偶數行和偶數列,然后對得到的圖像用指定的濾波器進行高斯卷積,其中濾波器乘以4做插值。所以輸出圖像是輸入圖像的 4 倍大小。(hunnish: 原理不清楚,尚待探討)
連接部件
[ 編輯]CvConnectedComp
連接部件
typedef struct CvConnectedComp {double area; /* 連通域的面積 */float value; /* 分割域的灰度縮放值 */CvRect rect; /* 分割域的 ROI */ } CvConnectedComp; [ 編輯]FloodFill
用指定顏色填充一個連接域
void cvFloodFill( CvArr* image, CvPoint seed_point, CvScalar new_val,CvScalar lo_diff=cvScalarAll(0), CvScalar up_diff=cvScalarAll(0),CvConnectedComp* comp=NULL, int flags=4, CvArr* mask=NULL ); #define CV_FLOODFILL_FIXED_RANGE (1 << 16) #define CV_FLOODFILL_MASK_ONLY (1 << 17) image- CV_FLOODFILL_FIXED_RANGE - 如果設置,則考慮當前象素與種子象素之間的差,否則考慮當前象素與其相鄰象素的差。(范圍是浮點數).
- CV_FLOODFILL_MASK_ONLY - 如果設置,函數不填充原始圖像 (忽略 new_val), 但填充掩模圖像 (這種情況下 MASK 必須是非空的).
函數 cvFloodFill 用指定顏色,從種子點開始填充一個連通域。連通性由象素值的接近程度來衡量。在點 (x, y) 的象素被認為是屬于重新繪制的區域,如果:
其中 src(x',y') 是象素鄰域點的值。也就是說,為了被加入到連通域中,一個象素的彩色/亮度應該足夠接近于:
- 它的鄰域象素的彩色/亮度值,當該鄰域點已經被認為屬于浮動范圍情況下的連通域。
- 固定范圍情況下的種子點的彩色/亮度值
FindContours
在二值圖像中尋找輪廓
int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,int header_size=sizeof(CvContour), int mode=CV_RETR_LIST,int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) ); image- CV_RETR_EXTERNAL - 只提取最外層的輪廓
- CV_RETR_LIST - 提取所有輪廓,并且放置在 list 中
- CV_RETR_CCOMP - 提取所有輪廓,并且將其組織為兩層的 hierarchy: 頂層為連通域的外圍邊界,次層為洞的內層邊界。
- CV_RETR_TREE - 提取所有輪廓,并且重構嵌套輪廓的全部 hierarchy
- CV_CHAIN_CODE - Freeman 鏈碼的輸出輪廓. 其它方法輸出多邊形(定點序列).
- CV_CHAIN_APPROX_NONE - 將所有點由鏈碼形式翻譯(轉化)為點序列形式
- CV_CHAIN_APPROX_SIMPLE - 壓縮水平、垂直和對角分割,即函數只保留末端的象素點;
- CV_CHAIN_APPROX_TC89_L1,
- CV_CHAIN_APPROX_TC89_KCOS - 應用 Teh-Chin 鏈逼近算法. CV_LINK_RUNS - 通過連接為 1 的水平碎片使用完全不同的輪廓提取算法。僅有 CV_RETR_LIST 提取模式可以在本方法中應用.
函數 cvFindContours 從二值圖像中提取輪廓,并且返回提取輪廓的數目。指針 first_contour 的內容由函數填寫。它包含第一個最外層輪廓的指針,如果指針為 NULL,則沒有檢測到輪廓(比如圖像是全黑的)。其它輪廓可以從 first_contour 利用 h_next 和 v_next 鏈接訪問到。 在 cvDrawContours 的樣例顯示如何使用輪廓來進行連通域的檢測。輪廓也可以用來做形狀分析和對象識別 - 見CVPR2001 教程中的 squares 樣例。該教程可以在 SourceForge 網站上找到。
[ 編輯]StartFindContours
初始化輪廓的掃描過程
CvContourScanner cvStartFindContours( CvArr* image, CvMemStorage* storage,int header_size=sizeof(CvContour),int mode=CV_RETR_LIST,int method=CV_CHAIN_APPROX_SIMPLE,CvPoint offset=cvPoint(0,0) ); image函數 cvStartFindContours 初始化并且返回輪廓掃描器的指針。掃描器在 cvFindNextContour 使用以提取其馀的輪廓。
[ 編輯]FindNextContour
Finds next contour in the image
CvSeq* cvFindNextContour( CvContourScanner scanner ); scanner函數 cvFindNextContour 確定和提取圖像的下一個輪廓,并且返回它的指針。若沒有更多的輪廓,則函數返回 NULL.
[ 編輯]SubstituteContour
替換提取的輪廓
void cvSubstituteContour( CvContourScanner scanner, CvSeq* new_contour ); scanner函數 cvSubstituteContour 把用戶自定義的輪廓替換前一次的函數 cvFindNextContour 調用所提取的輪廓,該輪廓以用戶定義的模式存儲在邊緣掃描狀態之中。輪廓,根據提取狀態,被插入到生成的結構,List,二層 hierarchy, 或 tree 中。如果參數 new_contour=NULL, 則提取的輪廓不被包含入生成結構中,它的所有后代以后也不會被加入到接口中。
[ 編輯]EndFindContours
結束掃描過程
CvSeq* cvEndFindContours( CvContourScanner* scanner ); scanner函數 cvEndFindContours 結束掃描過程,并且返回最高層的第一個輪廓的指針。
PyrSegmentation
用金字塔實現圖像分割
void cvPyrSegmentation( IplImage* src, IplImage* dst,CvMemStorage* storage, CvSeq** comp,int level, double threshold1, double threshold2 ); src函數 cvPyrSegmentation 實現了金字塔方法的圖像分割。金字塔建立到 level 指定的最大層數。如果 p(c(a),c(b))<threshold1,則在層 i 的象素點 a 和它的相鄰層的父親象素 b 之間的連接被建立起來,
定義好連接部件后,它們被加入到某些簇中。如果p(c(A),c(B))<threshold2,則任何兩個分割 A 和 B 屬于同一簇。
如果輸入圖像只有一個通道,那么
p(c1,c2)=|c1-c2|.如果輸入圖像有單個通道(紅、綠、蘭),那幺
p(c1,c2)=0,3·(c1r-c2r)+0,59·(c1g-c2g)+0,11·(c1b-c2b) .每一個簇可以有多個連接部件。 圖像 src 和 dst 應該是 8-比特、單通道 或 3-通道圖像,且大小一樣
[ 編輯]PyrMeanShiftFiltering
Does meanshift image segmentation
void cvPyrMeanShiftFiltering( const CvArr* src, CvArr* dst,double sp, double sr, int max_level=1,CvTermCriteria termcrit=cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,5,1)); srcThe function cvPyrMeanShiftFiltering implements the filtering stage of meanshift segmentation, that is, the output of the function is the filtered "posterized" image with color gradients and fine-grain texture flattened. At every pixel (X,Y) of the input image (or down-sized input image, see below) the function executes meanshift iterations, that is, the pixel (X,Y) neighborhood in the joint space-color hyperspace is considered:
{(x,y): X-sp≤x≤X+sp && Y-sp≤y≤Y+sp && ||(R,G,B)-(r,g,b)|| ≤ sr},where (R,G,B) and (r,g,b) are the vectors of color components at (X,Y) and (x,y), respectively (though, the algorithm does not depend on the color space used, so any 3-component color space can be used instead). Over the neighborhood the average spatial value (X',Y') and average color vector (R',G',B') are found and they act as the neighborhood center on the next iteration: (X,Y)~(X',Y'), (R,G,B)~(R',G',B').After the iterations over, the color components of the initial pixel (that is, the pixel from where the iterations started) are set to the final value (average color at the last iteration): I(X,Y) <- (R*,G*,B*).Then max_level>0, the gaussian pyramid of max_level+1 levels is built, and the above procedure is run on the smallest layer. After that, the results are propagated to the larger layer and the iterations are run again only on those pixels where the layer colors differ much (>sr) from the lower-resolution layer, that is, the boundaries of the color regions are clarified. Note, that the results will be actually different from the ones obtained by running the meanshift procedure on the whole original image (i.e. when max_level==0).
[ 編輯]Watershed
做分水嶺圖像分割
void cvWatershed( const CvArr* image, CvArr* markers ); image函數cvWatershed實現在[Meyer92]描述的變量分水嶺,基于非參數標記的分割算法中的一種。在把圖像傳給函數之前,用戶需要用正指標大致勾畫出圖像標記的感興趣區域。比如,每一個區域都表示成一個或者多個像素值1,2,3的互聯部分。這些部分將作為將來圖像區域的種子。標記中所有的其他像素,他們和勾畫出的區域關系不明并且應由算法定義,應當被置0。這個函數的輸出則是標記區域所有像素被置為某個種子部分的值,或者在區域邊界則置-1。
注:每兩個相鄰區域也不是必須有一個分水嶺邊界(-1像素)分開,例如在初始標記圖像里有這樣相切的部分。opencv例程文件夾里面有函數的視覺效果演示和用戶例程。見watershed.cpp。
[ 編輯]圖像與輪廓矩
[ 編輯]Moments
計算多邊形和光柵形狀的最高達三階的所有矩
void cvMoments( const CvArr* arr, CvMoments* moments, int binary=0 ); arr函數 cvMoments 計算最高達三階的空間和中心矩,并且將結果存在結構 moments 中。矩用來計算形狀的重心,面積,主軸和其它的形狀特征,如 7 Hu 不變量等。
[ 編輯]GetSpatialMoment
從矩狀態結構中提取空間矩
double cvGetSpatialMoment( CvMoments* moments, int x_order, int y_order ); moments函數 cvGetSpatialMoment 提取空間矩,當圖像矩被定義為:
Mx_order,y_order=sumx,y(I(x,y)?xx_order?yy_order)其中 I(x,y) 是象素點 (x, y) 的亮度值.
[ 編輯]GetCentralMoment
從矩狀態結構中提取中心矩
double cvGetCentralMoment( CvMoments* moments, int x_order, int y_order ); moments函數 cvGetCentralMoment 提取中心矩,其中圖像矩的定義是:
μx_order,y_order=sumx,y(I(x,y)?(x-xc)x_order?(y-yc)y_order),其中 xc=M10/M00, yc=M01/M00 - 重心坐標
[ 編輯]GetNormalizedCentralMoment
從矩狀態結構中提取歸一化的中心矩
double cvGetNormalizedCentralMoment( CvMoments* moments, int x_order, int y_order ); moments函數 cvGetNormalizedCentralMoment 提取歸一化中心矩:
ηx_order,y_order= μx_order,y_order/M00((y_order+x_order)/2+1) [ 編輯]GetHuMoments
計算 7 Hu 不變量
void cvGetHuMoments( CvMoments* moments, CvHuMoments* hu_moments ); moments函數 cvGetHuMoments 計算 7 個 Hu 不變量,它們的定義是:
h1=η20+η02h2=(η20-η02)2+4η112h3=(η30-3η12)2+ (3η21-η03)2h4=(η30+η12)2+ (η21+η03)2h5=(η30-3η12)(η30+η12)[(η30+η12)2-3(η21+η03)2]+(3η21-η03)(η21+η03)[3(η30+η12)2-(η21+η03)2]h6=(η20-η02)[(η30+η12)2- (η21+η03)2]+4η11(η30+η12)(η21+η03)h7=(3η21-η03)(η21+η03)[3(η30+η12)2-(η21+η03)2]-(η30-3η12)(η21+η03)[3(η30+η12)2-(η21+η03)2]這些值被證明為對圖像縮放、旋轉和反射的不變量。對反射,第7個除外,因為它的符號會因為反射而改變。
[ 編輯]特殊圖像變換
[ 編輯]HoughLines
利用 Hough 變換在二值圖像中找到直線
CvSeq* cvHoughLines2( CvArr* image, void* line_storage, int method,double rho, double theta, int threshold,double param1=0, double param2=0 ); image- CV_HOUGH_STANDARD - 傳統或標準 Hough 變換. 每一個線段由兩個浮點數 (ρ, θ) 表示,其中 ρ 是直線與原點 (0,0) 之間的距離,θ 線段與 x-軸之間的夾角。因此,矩陣類型必須是 CV_32FC2 type.
- CV_HOUGH_PROBABILISTIC - 概率 Hough 變換(如果圖像包含一些長的線性分割,則效率更高). 它返回線段分割而不是整個線段。每個分割用起點和終點來表示,所以矩陣(或創建的序列)類型是 CV_32SC4.
- CV_HOUGH_MULTI_SCALE - 傳統 Hough 變換的多尺度變種。線段的編碼方式與 CV_HOUGH_STANDARD 的一致。
- 對傳統 Hough 變換,不使用(0).
- 對概率 Hough 變換,它是最小線段長度.
- 對多尺度 Hough 變換,它是距離精度 rho 的分母 (大致的距離精度是 rho 而精確的應該是 rho / param1 ).
- 對傳統 Hough 變換,不使用 (0).
- 對概率 Hough 變換,這個參數表示在同一條直線上進行碎線段連接的最大間隔值(gap), 即當同一條直線上的兩條碎線段之間的間隔小于param2時,將其合二為一。
- 對多尺度 Hough 變換,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精確的角度應該是 theta / param2).
函數 cvHoughLines2 實現了用于線段檢測的不同 Hough 變換方法.Example. 用 Hough transform 檢測線段
/* This is a standalone program. Pass an image name as a first parameterof the program.Switch between standard and probabilistic Hough transformby changing "#if 1" to "#if 0" and back */ #include <cv.h> #include <highgui.h> #include <math.h>int main(int argc, char** argv) {IplImage* src;//if( argc == 2 && (src=cvLoadImage(argv[1], 0))!= 0) // if use 0, it will convert src to gray image,then call cvCvtColor function will throw an exception at opencv2.3if( argc == 2 && (src=cvLoadImge(argv[1])) != 0 ) {IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );CvMemStorage* storage = cvCreateMemStorage(0);CvSeq* lines = 0;int i;IplImage* src1=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);cvCvtColor(src, src1, CV_BGR2GRAY); cvCanny( src1, dst, 50, 200, 3 );cvCvtColor( dst, color_dst, CV_GRAY2BGR ); #if 1lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 150, 0, 0 );for( i = 0; i < lines->total; i++ ){float* line = (float*)cvGetSeqElem(lines,i);float rho = line[0];float theta = line[1];CvPoint pt1, pt2;double a = cos(theta), b = sin(theta);if( fabs(a) < 0.001 ){pt1.x = pt2.x = cvRound(rho);pt1.y = 0;pt2.y = color_dst->height;}else if( fabs(b) < 0.001 ){pt1.y = pt2.y = cvRound(rho);pt1.x = 0;pt2.x = color_dst->width;}else{pt1.x = 0;pt1.y = cvRound(rho/b);pt2.x = cvRound(rho/a);pt2.y = 0;}cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, 8 );} #elselines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 80, 30, 10 );for( i = 0; i < lines->total; i++ ){CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 );} #endifcvNamedWindow( "Source", 1 );cvShowImage( "Source", src );cvNamedWindow( "Hough", 1 );cvShowImage( "Hough", color_dst );cvWaitKey(0);} }這是函數所用的樣本圖像:
下面是程序的輸出,采用概率 Hough transform ("#if 0" 的部分):
[ 編輯]HoughCircles
利用 Hough 變換在灰度圖像中找圓
CvSeq* cvHoughCircles( CvArr* image, void* circle_storage,int method, double dp, double min_dist,double param1=100, double param2=100,int min_radius=0, int max_radius=0 ); image. 每個圓由三個浮點數表示:圓心坐標(x,y)和半徑.
methodResolution of the accumulator used to detect centers of the circles. For example, if it is 1, the accumulator will have the same resolution as the input image, if it is 2 - accumulator will have twice smaller width and height, etc.
min_distMinimum distance between centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed.
param1The first method-specific parameter. In case of CV_HOUGH_GRADIENT it is the higher threshold of the two passed to Canny edge detector (the lower one will be twice smaller).
param2The second method-specific parameter. In case of CV_HOUGH_GRADIENT it is accumulator threshold at the center detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first.
min_radiusMinimal radius of the circles to search for.
max_radiusMaximal radius of the circles to search for. By default the maximal radius is set to max(image_width, image_height).
The function cvHoughCircles finds circles in grayscale image using some modification of Hough transform.
Example. Detecting circles with Hough transform.
#include <cv.h> #include <highgui.h> #include <math.h>int main(int argc, char** argv) {IplImage* img;if( argc == 2 && (img=cvLoadImage(argv[1], 1))!= 0){IplImage* gray = cvCreateImage( cvGetSize(img), 8, 1 );CvMemStorage* storage = cvCreateMemStorage(0);cvCvtColor( img, gray, CV_BGR2GRAY );cvSmooth( gray, gray, CV_GAUSSIAN, 9, 9 ); // smooth it, otherwise a lot of false circles may be detectedCvSeq* circles = cvHoughCircles( gray, storage, CV_HOUGH_GRADIENT, 2, gray->height/4, 200, 100 );int i;for( i = 0; i < circles->total; i++ ){float* p = (float*)cvGetSeqElem( circles, i );cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 3, CV_RGB(0,255,0), -1, 8, 0 );cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), cvRound(p[2]), CV_RGB(255,0,0), 3, 8, 0 );}cvNamedWindow( "circles", 1 );cvShowImage( "circles", img );}return 0; } [ 編輯]DistTransform
計算輸入圖像的所有非零元素對其最近零元素的距離
void cvDistTransform( const CvArr* src, CvArr* dst, int distance_type=CV_DIST_L2,int mask_size=3, const float* mask=NULL ); src函數 cvDistTransform 二值圖像每一個象素點到它最鄰近零象素點的距離。對零象素,函數設置 0 距離,對其它象素,它尋找由基本位移(水平、垂直、對角線或knight's move,最后一項對 5×5 mask 有用)構成的最短路徑。 全部的距離被認為是基本距離的和。由于距離函數是對稱的,所有水平和垂直位移具有同樣的代價 (表示為 a ), 所有的對角位移具有同樣的代價 (表示為 b), 所有的 knight's 移動具有同樣的代價 (表示為 c). 對類型 CV_DIST_C 和 CV_DIST_L1,距離的計算是精確的,而類型 CV_DIST_L2 (歐式距離) 距離的計算有某些相對誤差 (5×5 mask 給出更精確的結果), OpenCV 使用 [Borgefors86] 推薦的值:
下面用戶自定義距離的的距離域示例 (黑點 (0) 在白色方塊中間):用戶自定義 3×3 mask (a=1, b=1.5)
| 4.5 | 4 | 3.5 | 3 | 3.5 | 4 | 4.5 |
| 4 | 3 | 2.5 | 2 | 2.5 | 3 | 4 |
| 3.5 | 2.5 | 1.5 | 1 | 1.5 | 2.5 | 3.5 |
| 3 | 2 | 1 | 0 | 1 | 2 | 3 |
| 3.5 | 2.5 | 1.5 | 1 | 1.5 | 2.5 | 3.5 |
| 4 | 3 | 2.5 | 2 | 2.5 | 3 | 4 |
| 4.5 | 4 | 3.5 | 3 | 3.5 | 4 | 4.5 |
用戶自定義 5×5 mask (a=1, b=1.5, c=2)
| 4.5 | 3.5 | 3 | 3 | 3 | 3.5 | 4.5 |
| 3.5 | 3 | 2 | 2 | 2 | 3 | 3.5 |
| 3 | 2 | 1.5 | 1 | 1.5 | 2 | 3 |
| 3 | 2 | 1 | 0 | 1 | 2 | 3 |
| 3 | 2 | 1.5 | 1 | 1.5 | 2 | 3 |
| 3.5 | 3 | 2 | 2 | 2 | 3 | 3.5 |
| 4 | 3.5 | 3 | 3 | 3 | 3.5 | 4 |
典型的使用快速粗略距離估計 CV_DIST_L2, 3×3 mask , 如果要更精確的距離估計,使用 CV_DIST_L2, 5×5 mask。
When the output parameter labels is not NULL, for every non-zero pixel the function also finds the nearest connected component consisting of zero pixels. The connected components themselves are found as contours in the beginning of the function.
In this mode the processing time is still O(N), where N is the number of pixels. Thus, the function provides a very fast way to compute approximate Voronoi diagram for the binary image.
[ 編輯]Inpaint
修復圖像中選擇區域。
void cvInpaint( const CvArr* src, const CvArr* mask, CvArr* dst,int flags, double inpaintRadius ); src函數cvInpaint從選擇圖像區域邊界的像素重建該區域。函數可以用來去除掃描相片的灰塵或者刮傷,或者從靜態圖像或者視頻中去除不需要的物體。
[ 編輯]直方圖
[ 編輯]CvHistogram
多維直方圖
typedef struct CvHistogram {int type;CvArr* bins;float thresh[CV_MAX_DIM][2]; /* for uniform histograms */float** thresh2; /* for non-uniform histograms */CvMatND mat; /* embedded matrix header for array histograms */ } CvHistogram;bins : 用于存放直方圖每個灰度級數目的數組指針,數組在cvCreateHist 的時候創建,其維數由cvCreateHist 確定(一般以一維比較常見)
[ 編輯]CreateHist
創建直方圖
CvHistogram* cvCreateHist( int dims, int* sizes, int type,float** ranges=NULL, int uniform=1 ); dims函數 cvCreateHist 創建一個指定尺寸的直方圖,并且返回創建的直方圖的指針。 如果數組的 ranges 是 0, 則直方塊的范圍必須由函數 cvSetHistBinRanges 稍后指定。雖然 cvCalcHist 和 cvCalcBackProject 可以處理 8-比特圖像而無需設置任何直方塊的范圍,但它們都被假設等分 0..255 之間的空間。
[ 編輯]SetHistBinRanges
設置直方塊的區間
void cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform=1 );hist
ranges
uniform
函數 cvSetHistBinRanges 是一個獨立的函數,完成直方塊的區間設置。更多詳細的關于參數 ranges 和 uniform 的描述,請參考函數 cvCalcHist , 該函數也可以初始化區間。直方塊的區間的設置必須在計算直方圖之前,或 在計算直方圖的反射圖之前。
[ 編輯]ReleaseHist
釋放直方圖結構
void cvReleaseHist( CvHistogram** hist ); hist函數 cvReleaseHist 釋放直方圖 (頭和數據). 指向直方圖的指針被函數所清空。如果 *hist 指針已經為 NULL, 則函數不做任何事情。
[ 編輯]ClearHist
清除直方圖
void cvClearHist( CvHistogram* hist ); hist函數 cvClearHist 當直方圖是稠密數組時將所有直方塊設置為 0,當直方圖是稀疏數組時,除去所有的直方塊。
[ 編輯]MakeHistHeaderForArray
從數組中創建直方圖
CvHistogram* cvMakeHistHeaderForArray( int dims, int* sizes, CvHistogram* hist,float* data, float** ranges=NULL, int uniform=1 ); dims函數 cvMakeHistHeaderForArray 初始化直方圖,其中頭和直方塊為用戶所分配。以后不需要調用 cvReleaseHist 只有稠密直方圖可以采用這種方法,函數返回 hist.
[ 編輯]QueryHistValue_1D
查詢直方塊的值
#define cvQueryHistValue_1D( hist, idx0 ) \cvGetReal1D( (hist)->bins, (idx0) ) #define cvQueryHistValue_2D( hist, idx0, idx1 ) \cvGetReal2D( (hist)->bins, (idx0), (idx1) ) #define cvQueryHistValue_3D( hist, idx0, idx1, idx2 ) \cvGetReal3D( (hist)->bins, (idx0), (idx1), (idx2) ) #define cvQueryHistValue_nD( hist, idx ) \cvGetRealND( (hist)->bins, (idx) ) hist宏 cvQueryHistValue_*D 返回 1D, 2D, 3D 或 N-D 直方圖的指定直方塊的值。對稀疏直方圖,如果方塊在直方圖中不存在,函數返回 0, 而且不創建新的直方塊。
[ 編輯]GetHistValue_1D
返回直方塊的指針
#define cvGetHistValue_1D( hist, idx0 ) \((float*)(cvPtr1D( (hist)->bins, (idx0), 0 )) #define cvGetHistValue_2D( hist, idx0, idx1 ) \((float*)(cvPtr2D( (hist)->bins, (idx0), (idx1), 0 )) #define cvGetHistValue_3D( hist, idx0, idx1, idx2 ) \((float*)(cvPtr3D( (hist)->bins, (idx0), (idx1), (idx2), 0 )) #define cvGetHistValue_nD( hist, idx ) \((float*)(cvPtrND( (hist)->bins, (idx), 0 )) hist宏 cvGetHistValue_*D 返回 1D, 2D, 3D 或 N-D 直方圖的指定直方塊的指針。對稀疏直方圖,函數創建一個新的直方塊,且設置其為 0,除非它已經存在。
[ 編輯]GetMinMaxHistValue
發現最大和最小直方塊
void cvGetMinMaxHistValue( const CvHistogram* hist,float* min_value, float* max_value,int* min_idx=NULL, int* max_idx=NULL ); hist函數 cvGetMinMaxHistValue 發現最大和最小直方塊以及它們的位置。任何輸出變量都是可選的。在具有同樣值幾個極值中,返回具有最小下標索引(以字母排列順序定)的那一個。
[ 編輯]NormalizeHist
歸一化直方圖
void cvNormalizeHist( CvHistogram* hist, double factor ); hist函數 cvNormalizeHist 通過縮放來歸一化直方塊,使得所有塊的和等于 factor.
[ 編輯]ThreshHist
對直方圖取閾值
void cvThreshHist( CvHistogram* hist, double threshold ); hist函數 cvThreshHist 清除那些小于指定閾值得直方塊
[ 編輯]CompareHist
比較兩個稠密直方圖
double cvCompareHist( const CvHistogram* hist1, const CvHistogram* hist2, int method ); hist1- CV_COMP_CORREL
- CV_COMP_CHISQR
- CV_COMP_INTERSECT
- CV_COMP_BHATTACHARYYA
- Correlation (method=CV_COMP_CORREL):
- Chi-square(method=CV_COMP_CHISQR):
- 交叉 (method=CV_COMP_INTERSECT):
| d(H1,H2) = | ∑ | min(H1(i),H2(i)) |
| ? | i | ? |
- Bhattacharyya 距離 (method=CV_COMP_BHATTACHARYYA):
函數返回 d(H1,H2) 的值。
注意:Bhattacharyya 距離只能應用到規一化后的直方圖。
為了比較稀疏直方圖或更一般的加權稀疏點集(譯者注:直方圖匹配是圖像檢索中的常用方法),考慮使用函數 cvCalcEMD 。
[ 編輯]CopyHist
拷貝直方圖
void cvCopyHist( const CvHistogram* src, CvHistogram** dst ); src函數 cvCopyHist 對直方圖作拷貝。如果第二個直方圖指針 *dst 是 NULL, 則創建一個與 src 同樣大小的直方圖。否則,兩個直方圖必須大小和類型一致。然后函數將輸入的直方塊的值復制到輸出的直方圖中,并且設置取值范圍與 src 的一致。
[ 編輯]CalcHist
計算圖像image(s) 的直方圖
void cvCalcHist( IplImage** image, CvHistogram* hist,int accumulate=0, const CvArr* mask=NULL ); image函數 cvCalcHist 計算一張或多張單通道圖像的直方圖(譯者注:若要計算多通道,可像以下例子那樣用多個單通道圖來表示)。 用來增加直方塊的數組元素可從相應輸入圖像的同樣位置提取。Sample. 計算和顯示彩色圖像的 2D 色調-飽和度圖像
#include <cv.h> #include <highgui.h>int main( int argc, char** argv ) {IplImage* src;if( argc == 2 && (src=cvLoadImage(argv[1], 1))!= 0){IplImage* h_plane = cvCreateImage( cvGetSize(src), 8, 1 );IplImage* s_plane = cvCreateImage( cvGetSize(src), 8, 1 );IplImage* v_plane = cvCreateImage( cvGetSize(src), 8, 1 );IplImage* planes[] = { h_plane, s_plane };IplImage* hsv = cvCreateImage( cvGetSize(src), 8, 3 );int h_bins = 30, s_bins = 32;int hist_size[] = {h_bins, s_bins};/* hue varies from 0 (~0°red) to 180 (~360°red again) */float h_ranges[] = { 0, 180 }; /* saturation varies from 0 (black-gray-white) to 255 (pure spectrum color) */float s_ranges[] = { 0, 255 };float* ranges[] = { h_ranges, s_ranges };int scale = 10;IplImage* hist_img = cvCreateImage( cvSize(h_bins*scale,s_bins*scale), 8, 3 );CvHistogram* hist;float max_value = 0;int h, s;cvCvtColor( src, hsv, CV_BGR2HSV );cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, 1 );cvCalcHist( planes, hist, 0, 0 );cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );cvZero( hist_img );for( h = 0; h < h_bins; h++ ){for( s = 0; s < s_bins; s++ ){float bin_val = cvQueryHistValue_2D( hist, h, s );int intensity = cvRound(bin_val*255/max_value);cvRectangle( hist_img, cvPoint( h*scale, s*scale ),cvPoint( (h+1)*scale - 1, (s+1)*scale - 1),CV_RGB(intensity,intensity,intensity), /* graw a grayscale histogram.if you have idea how to do itnicer let us know */CV_FILLED );}}cvNamedWindow( "Source", 1 );cvShowImage( "Source", src );cvNamedWindow( "H-S Histogram", 1 );cvShowImage( "H-S Histogram", hist_img );cvWaitKey(0);} } [ 編輯]CalcBackProject
計算反向投影
void cvCalcBackProject( IplImage** image, CvArr* back_project, const CvHistogram* hist ); image函數 cvCalcBackProject 計算直方圖的反向投影. 對于所有輸入的單通道圖像同一位置的象素數組,該函數根據相應的象素數組(RGB),放置其對應的直方塊的值到輸出圖像中。用統計學術語,輸出圖像象素點的值是觀測數組在某個分布(直方圖)下的概率。 例如,為了發現圖像中的紅色目標,可以這么做:
這是 Camshift 彩色目標跟蹤器中的一個逼進算法,除了第三步,CAMSHIFT 算法使用了上一次目標位置來定位反向投影中的目標。
[ 編輯]CalcBackProjectPatch
用直方圖比較來定位圖像中的模板
void cvCalcBackProjectPatch( IplImage** image, CvArr* dst,CvSize patch_size, CvHistogram* hist,int method, double factor ); image函數 cvCalcBackProjectPatch 通過輸入圖像補丁的直方圖和給定直方圖的比較,來計算反向投影。提取圖像在 ROI 中每一個位置的某種測量結果產生了數組 image. 這些結果可以是色調, x 差分, y 差分, Laplacian 濾波器, 有方向 Gabor 濾波器等中 的一個或多個。每種測量輸出都被劃歸為它自己的單獨圖像。 image 圖像數組是這些測量圖像的集合。一個多維直方圖 hist 從這些圖像數組中被采樣創建。最后直方圖被歸一化。直方圖 hist 的維數通常很大等于圖像數組 image 的元素個數。
在選擇的 ROI 中,每一個新的圖像被測量并且轉換為一個圖像數組。在以錨點為“補丁”中心的圖像 image 區域中計算直方圖 (如下圖所示)。用參數 norm_factor 來歸一化直方圖,使得它可以與 hist 互相比較。計算出的直方圖與直方圖模型互相比較, (hist 使用函數 cvCompareHist ,比較方法是 method=method). 輸出結果被放置到概率圖像 dst 補丁錨點的對應位置上。這個過程隨著補丁滑過整個 ROI 而重復進行。迭代直方圖的更新可以通過在原直方圖中減除“補丁”已復蓋的尾象素點或者加上新復蓋的象素點來實現,這種更新方式可以節省大量的操作,盡管目前在函數體中還沒有實現。
Back Project Calculation by Patches
[ 編輯]CalcProbDensity
兩個直方圖相除
void cvCalcProbDensity( const CvHistogram* hist1, const CvHistogram* hist2,CvHistogram* dst_hist, double scale=255 ); hist1函數 cvCalcProbDensity 從兩個直方圖中計算目標概率密度:
dist_hist(I)=0 if hist1(I)==0scale if hist1(I)!=0 && hist2(I)>hist1(I)hist2(I)*scale/hist1(I) if hist1(I)!=0 && hist2(I)<=hist1(I)所以輸出的直方塊小于尺度因子。
[ 編輯]EqualizeHist
灰度圖象直方圖均衡化
void cvEqualizeHist( const CvArr* src, CvArr* dst ); src函數 cvEqualizeHist 采用如下法則對輸入圖像進行直方圖均衡化:
該方法歸一化圖像亮度和增強對比度。
例:彩色圖像的直方圖均衡化
int i; IplImage *pImageChannel[4] = { 0, 0, 0, 0 }; pSrcImage = cvLoadImage( "test.jpg", 1 ) ; IplImage *pImage = cvCreateImage(cvGetSize(pSrcImage), pSrcImage->depth, pSrcImage->nChannels); if( pSrcImage ) {for( i = 0; i < pSrcImage->nChannels; i++ ){pImageChannel[i] = cvCreateImage( cvGetSize(pSrcImage), pSrcImage->depth, 1 );}// 信道分離cvSplit( pSrcImage, pImageChannel[0], pImageChannel[1],pImageChannel[2], pImageChannel[3] );for( i = 0; i < pImage->nChannels; i++ ){// 直方圖均衡化cvEqualizeHist( pImageChannel[i], pImageChannel[i] );}// 信道組合cvMerge( pImageChannel[0], pImageChannel[1], pImageChannel[2],pImageChannel[3], pImage );// ……圖像顯示代碼(略)// 釋放資源for( i = 0; i < pSrcImage->nChannels; i++ ){if ( pImageChannel[i] ){cvReleaseImage( &pImageChannel[i] );pImageChannel[i] = 0;}}cvReleaseImage( &pImage );pImage = 0; } [ 編輯]匹配
[ 編輯]MatchTemplate
在輸入的源圖像中與模板圖像作重疊比較
void cvMatchTemplate( const CvArr* image, const CvArr* templ,CvArr* result, int method ); image函數 cvMatchTemplate 與函數 cvCalcBackProjectPatch 類似。它滑動過整個圖像 image, 用指定方法比較 templ 與圖像尺寸為 w×h 的重疊區域,并且將比較結果存到 result 中。 下面是不同的比較方法,可以使用其中的一種 (I 表示圖像,T - 模板, R - 結果. 模板與圖像重疊區域 x'=0..w-1, y'=0..h-1 之間求和):
| R(x,y) = | ∑ | [T(x',y') ? I(x + x',y + y')]2 |
| ? | x',y' | ? |
函數完成比較后,通過使用cvMinMaxLoc找全局最小值CV_TM_SQDIFF*) 或者最大值 (CV_TM_CCORR* and CV_TM_CCOEFF*)。
[ 編輯]MatchShapes
比較兩個形狀
double cvMatchShapes( const void* object1, const void* object2,int method, double parameter=0 ); object1函數 cvMatchShapes 比較兩個形狀。 三個實現方法全部使用 Hu 矩 (見 cvGetHuMoments) (A ~ object1, B - object2):
其中
CalcEMD2
兩個加權點集之間計算最小工作距離
float cvCalcEMD2( const CvArr* signature1, const CvArr* signature2, int distance_type,CvDistanceFunction distance_func=NULL, const CvArr* cost_matrix=NULL,CvArr* flow=NULL, float* lower_bound=NULL, void* userdata=NULL ); typedef float (*CvDistanceFunction)(const float* f1, const float* f2, void* userdata); signature1函數 cvCalcEMD2 計算兩個加權點集之間的移動距離或距離下界。在 [RubnerSept98] 中所描述的其中一個應用就是圖像提取得多維直方圖比較。 EMD 是一個使用某種單純形算法(simplex algorithm)來解決的交通問題。其計算復雜度在最壞情況下是指數形式的,但是平均而言它的速度相當快。對實的準則,下邊界的計算可以更快(使用線性時間算法),且它可用來粗略確定兩個點集是否足夠遠以至無法聯系到同一個目標上。
取自" http://wiki.opencv.org.cn/index.php/Cv%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86"總結
以上是生活随笔為你收集整理的opencv处理函数记录_转自opencv中文网站的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GitHub星数1.3W!五分钟带你搞定
- 下一篇: 串的详细讲解