OPENCV用戶手冊之圖像處理(網絡資料蒐集整理)

使用擴展 Sobel 算子計算一階、二階、三階或混合圖像差分

void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );

 src 

輸入圖像. 
dst 
輸出圖像. 
xorder 
x? 方向上的差分階數 
yorder 
y? 方向上的差分階數
aperture_size 
擴展 Sobel 核的大小,必須是 1, 3, 5 或 7。 除了尺寸爲 1, 其它情況下, aperture_size ×aperture_size 可分離內核將用來計算差分。對 aperture_size=1的情況, 使用 3x1 或 1x3 內核 (不進行高斯平滑操作)。有一個特殊變量? CV_SCHARR (=-1),對應 3x3 Scharr 濾波器,可以給出比 3x3 Sobel 濾波更精確的結果。Scharr 濾波器係數是:
| -3 0  3|
|-10 0 10|
| -3 0  3|
x-方向 以及轉置矩陣對 y-方向。

函數 cvSobel 通過對圖像用相應的內核進行卷積操作來計算圖像差分:

dst(x,y) = dxorder+yodersrc/dxxorder•dyyorder |(x,y)

Sobel 算子結合 Gaussian 平滑和微分,以提高計算結果對噪聲的抵抗能力。通常情況,函數調用採用如下參數 (xorder=1, yorder=0, aperture_size=3) 或 (xorder=0, yorder=1, aperture_size=3) 來計算一階 x- 或 y- 方向的圖像差分。第一種情況對應:

  |-1  0  1|
  |-2  0  2|
  |-1  0  1|

核。第二種對應

  |-1 -2 -1|
  | 0  0  0|
  | 1  2  1|
or
  | 1  2  1|
  | 0  0  0|
  |-1 -2 -1|

核,它依賴於圖像原點的定義 (origin 來自IplImage 結構的定義)。不進行圖像尺度變換。所以輸出圖像通常比輸入圖像大。爲防止溢出,當輸入圖像是 8 位的,要求輸出圖像是 16 位的。產生的圖像可以用函數 cvConvertScale 或 cvConvertScaleAbs 轉換爲 8 位的。除了 8-比特 圖像,函數也接受 32-位 浮點數圖像。所有輸入和輸出圖像都必須是單通道,且圖像大小或ROI尺寸一致。


計算圖像的 Laplacian?

void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 );

 src 

輸入圖像. 
dst 
輸出圖像. 
aperture_size 
核大小 (與 cvSobel 中定義一樣).

函數 cvLaplace 計算輸入圖像的 Laplacian,方法是對用 sobel 算子計算的二階 x- 和 y- 差分求和:

dst(x,y) = d2src/dx2 + d2src/dy2

aperture_size=1 則給出最快計算結果,相當於對圖像採用如下內核做卷積:

|0  1  0|
|1 -4  1|
|0  1  0|

類似於 cvSobel 函數,也不作圖像的尺度變換,而且支持輸入、輸出圖像類型一致。


採用 Canny 算法做邊緣檢測

void cvCanny( const CvArr* image, CvArr* edges, double threshold1,
              double threshold2, int aperture_size=3 );

 image 

輸入圖像. 
edges 
輸出的邊緣圖像 
threshold1 
第一個閾值 
threshold2 
第二個閾值 
aperture_size 
Sobel 算子內核大小 (見 cvSobel).

函數 cvCanny 採用 CANNY 算法發現輸入圖像的邊緣而且在輸出圖像中標識這些邊緣。小的閾值 threshold1 用來控制邊緣連接,大的閾值用來控制強邊緣的初始分割。


計算特徵圖,用於角點檢測

void cvPreCornerDetect( const CvArr* image, CvArr* corners, int aperture_size=3 );

 image 

輸入圖像. 
corners 
保存角點座標的數組 
aperture_size 
Sobel 算子的核大小(見cvSobel).

函數 cvPreCornerDetect 計算函數 Dx2Dyy+Dy2Dxx - 2DxDyDxy 其中 D? 表示一階圖像差分,D?? 表示二階圖像差分。 角點被認爲是函數的局部最大值:

// assuming that the image is 浮點數
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 );
cvSubS( corners, dilated_corners, corners );
cvCmpS( corners, 0, corner_mask, CV_CMP_GE );
cvReleaseImage( &corners );
cvReleaseImage( &dilated_corners );

計算圖像塊的特徵值和特徵向量,用於角點檢測

void cvCornerEigenValsAndVecs( const CvArr* image, CvArr* eigenvv,
                               int block_size, int aperture_size=3 );

 image 

輸入圖像. 
eigenvv 
保存結果的數組。必須比輸入圖像寬 6 倍。
block_size 
鄰域大小 (見討論).
aperture_size 
Sobel 算子的核尺寸(見 cvSobel).

對每個象素,函數 cvCornerEigenValsAndVecs 考慮 block_size ×block_size 大小的鄰域 S(p),然後在鄰域上計算差分的相關矩陣:

    | sumS(p)(dI/dx)2   sumS(p)(dI/dx•dI/dy)|
M = |                                 |
    | sumS(p)(dI/dx•dI/dy)  sumS(p)(dI/dy)2 |

然後它計算矩陣的特徵值和特徵向量,並且按如下方式1, λ2, x1, y1, x2, y2)存儲這些值到輸出圖像中,其中

λ1, λ2 -M 的特徵值,沒有排序
(x1, y1) - 特徵向量,對 λ1
(x2, y2) - 特徵向量,對 λ2


計算梯度矩陣的最小特徵值,用於角點檢測

void cvCornerMinEigenVal( const CvArr* image, CvArr* eigenval, int block_size, int aperture_size=3 );

 image 

輸入圖像. 
eigenval 
保存最小特徵值的圖像. 與輸入圖像大小一致
block_size 
鄰域大小 (見討論 cvCornerEigenValsAndVecs). 
aperture_size 
Sobel 算子的核尺寸(見 cvSobel). 當輸入圖像是浮點數格式時,該參數表示用來計算差分的浮點濾波器的個數.

函數 cvCornerMinEigenVal 與 cvCornerEigenValsAndVecs 類似,但是它僅僅計算和存儲每個象素點差分相關矩陣的最小特徵值,即前一個函數的 min(λ1, λ2)


精確角點位置

void cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners,
                         int count, CvSize win, CvSize zero_zone,
                         CvTermCriteria criteria );

 image 

輸入圖像. 
corners 
輸入角點的初始座標,也存儲精確的輸出座標 
count 
角點數目 
win 
搜索窗口的一半尺寸。如果 win=(5,5) 那麼使用 5*2+1 × 5*2+1 = 11 × 11 大小的搜索窗口
zero_zone 
死區的一半尺寸,死區爲不對搜索區的中央位置做求和運算的區域。它是用來避免自相關矩陣出現的某些可能的奇異性。當值爲 (-1,-1) 表示沒有死區。
criteria 
求角點的迭代過程的終止條件。即角點位置的確定,要麼迭代數大於某個設定值,或者是精確度達到某個設定值。 criteria 可以是最大迭代數目,也可以是精確度

函數 cvFindCornerSubPix 通過迭代來發現具有子象素精度的角點位置,或如圖所示的放射鞍點(radial saddle points)。

 Sub-pixel accurate corner locator is based on the observation that every vector from the centerq to a pointp located within a neighborhood ofq is orthogonal to the image gradient atp subject to image and measurement noise. Consider the expression:

εi=DIpiT•(q-pi)

where DIpi is the image gradient at the one of the pointspi in a neighborhood ofq. The value of q is to be found such that εi is minimized. A system of equations may be set up withεi' set to zero:

sumi(DIpi•DIpiT)•q - sumi(DIpi•DIpiT•pi) = 0

where the gradients are summed within a neighborhood ("search window") of q. Calling the first gradient term G and the second gradient termb gives:

q=G-1•b

The algorithm sets the center of the neighborhood window at this new center q and then iterates until the center keeps within a set threshold.


確定圖像的強角點

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 

輸入圖像,8-位或浮點32-比特,單通道
eig_image 
臨時浮點32-位圖像,大小與輸入圖像一致
temp_image 
另外一個臨時圖像,格式與尺寸與 eig_image 一致
corners 
輸出參數,檢測到的角點 
corner_count 
輸出參數,檢測到的角點數目 
quality_level 
最大最小特徵值的乘法因子。定義可接受圖像角點的最小質量因子。 
min_distance 
限制因子。得到的角點的最小距離。使用 Euclidian 距離
mask 
ROI:感興趣區域。函數在ROI中計算角點,如果 mask 爲 NULL,則選擇整個圖像。

函數 cvGoodFeaturesToTrack 在圖像中尋找具有大特徵值的角點。該函數,首先用cvCornerMinEigenVal 計算輸入圖像的每一個象素點的最小特徵值,並將結果存儲到變量eig_image 中。然後進行非最大值壓縮(僅保留3x3鄰域中的局部最大值)。下一步將最小特徵值小於quality_level•max(eig_image(x,y)) 排除掉。最後,函數確保所有發現的角點之間具有足夠的距離,(最強的角點第一個保留,然後檢查新的角點與已有角點之間的距離大於min_distance )。

 

初始化線段迭代器

int cvInitLineIterator( const CvArr* image, CvPoint pt1, CvPoint pt2,
                        CvLineIterator* line_iterator, int connectivity=8 );

 image 

帶線段的圖像. 
pt1 
線段起始點 
pt2 
線段結束點 
line_iterator 
指向線段迭代器結構的指針 
connectivity 
被掃描線段的連通數,4 或 8.

函數 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 );
    }

將光柵線讀入緩衝區

int cvSampleLine( const CvArr* image, CvPoint pt1, CvPoint pt2,
                  void* buffer, int connectivity=8 );

 image 

帶線段圖像 
pt1 
起點 
pt2 
終點 
buffer 
存儲線段點的緩存區,必須有足夠大小來存儲點 max( |pt2.x-pt1.x|+1, |pt2.y-pt1.y|+1 ) :8-連通情況下,以及 |pt2.x-pt1.x|+|pt2.y-pt1.y|+1 : 4-連通情況下.
connectivity 
The line connectivity, 4 or 8.

函數 cvSampleLine 實現了線段迭代器的一個特殊應用。它讀取由兩點 pt1 和 pt2 確定的線段上的所有圖像點,包括終點,並存儲到緩存中。


從圖像中提取象素矩形,使用子象素精度

void cvGetRectSubPix( const CvArr* src, CvArr* dst, CvPoint2D32f center );

 src 

輸入圖像. 
dst 
提取的矩形. 
center 
提取的象素矩形的中心,浮點數座標。中心必須位於圖像內部.

函數 cvGetRectSubPix 從圖像 src 中提取矩形:

dst(x, y) = src(x + center.x - (width(dst)-1)*0.5, y + center.y - (height(dst)-1)*0.5)

其中非整數象素點座標採用雙線性差值提取。對多通道圖像,每個通道獨立單獨完成提取。矩形中心必須位於圖像內部,而整個矩形可以部分不在圖像內。這種情況下,複製的邊界模識用來得到圖像邊界外的象素值(Hunnish:令人費解)


提取象素四邊形,使用子象素精度

void cvGetQuadrangleSubPix( const CvArr* src, CvArr* dst, const CvMat* map_matrix,
                            int fill_outliers=0, CvScalar fill_value=cvScalarAll(0) );

 src 

輸入圖像. 
dst 
提取的四邊形. 
map_matrix 
3 × 2 變換矩陣 [A|b] (見討論).
fill_outliers 
該標誌位指定是否對原始圖像邊界外面的象素點使用複製模式(fill_outliers=0)進行差值或者將其設置爲指定值(fill_outliers=1)。 
fill_value 
對原始圖像邊界外面的象素設定固定值,當 fill_outliers=1.

函數 cvGetQuadrangleSubPix 從圖像 src 中提取四邊形,使用子象素精度,並且將結果存儲於dst ,計算公式是:

dst(x+width(dst)/2, y+height(dst)/2)= src( A11x+A12y+b1, A21x+A22y+b2),

where A and b are taken from map_matrix
             | A11 A12  b1 |
map_matrix = |            |
             | A21 A22  b2 |

其中在非整數座標 A•(x,y)T+b 的象素點值通過雙線性變換得到。多通道圖像的每一個通道都單獨計算.

例子:使用 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;
}

圖像大小變換

void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR );

 src 

輸入圖像. 
dst 
輸出圖像. 
interpolation 
差值方法:
  • CV_INTER_NN - 最近鄰差值,
  • CV_INTER_LINEAR - 雙線性差值 (缺省使用)
  • CV_INTER_AREA - 使用象素關係重採樣。當圖像縮小時候,該方法可以避免波紋出現。當圖像放大是,類似於 CV_INTER_NN 方法..
  • CV_INTER_CUBIC - 立方差值.

函數 cvResize 將圖像 src 改變尺寸得到與dst 同樣大小。若設定 ROI,函數將按常規支持 ROI.


對圖像做仿射變換

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 

輸入圖像. 
dst 
輸出圖像. 
map_matrix 
2×3 變換矩陣
flags 
差值方法與開關選項:
  • CV_WARP_FILL_OUTLIERS - 填充所有縮小圖像的象素。如果部分象素落在輸入圖像的邊界外,那麼它們的值設定爲fillval.
  • CV_WARP_INVERSE_MAP - 指定 matrix 是輸出圖像到輸入圖像的反變換,因此可以直接用來做象素差值。否則, 函數從map_matrix 得到反變換。
fillval 
用來填充邊界外面的值

函數 cvWarpAffine 利用下面指定的矩陣變換輸入圖像:

dst(x',y')<-src(x,y)
如果沒有指定 CV_WARP_INVERSE_MAP , (x',y')T=map_matrix•(x,y,1)T+b ,
否則, (x, y)T=map_matrix•(x',y',1)T+b

函數與 cvGetQuadrangleSubPix 類似,但是不完全相同。 cvWarpAffine 要求輸入和輸出圖像具有同樣的數據類型,有更大的資源開銷(因此對大圖像不太合適)而且輸出圖像的部分可以保留不變。而 cvGetQuadrangleSubPix 可以精確地從8位圖像中提取四邊形到浮點數緩存區中,具有比較小的系統開銷,而且總是全部改變輸出圖像的內容。

要變換稀疏矩陣,使用 cxcore 中的函數 cvTransform 。


計算二維旋轉的仿射變換矩陣

CvMat* cv2DRotationMatrix( CvPoint2D32f center, double angle,
                           double scale, CvMat* map_matrix );

 center 

輸入圖像的旋轉中心 
angle 
旋轉角度(度)。正值表示逆時針旋轉(座標原點假設在左上角).
scale 
各項同性的尺度因子 
map_matrix 
輸出 2×3 矩陣的指針

函數 cv2DRotationMatrix 計算矩陣:

[  α  β  |  (1-α)*center.x - β*center.y ]
[ -β  α  |  β*center.x + (1-α)*center.y ]

where α=scale*cos(angle), β=scale*sin(angle)

該變換映射旋轉中心到它本身。如果這不是目的的話,應該調整平移(Hunnish: 這段話令人費解:The transformation maps the rotation center to itself. If this is not the purpose, the shift should be adjusted)


對圖像進行透視變換

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 

輸入圖像. 
dst 
輸出圖像. 
map_matrix 
3×3 變換矩陣
flags 
差值方法的開關選項:
  • CV_WARP_FILL_OUTLIERS - 填充所有縮小圖像的象素。如果部分象素落在輸入圖像的邊界外,那麼它們的值設定爲fillval.
  • CV_WARP_INVERSE_MAP - 指定 matrix 是輸出圖像到輸入圖像的反變換,因此可以直接用來做象素差值。否則, 函數從map_matrix 得到反變換。
fillval 
用來填充邊界外面的值

函數 cvWarpPerspective 利用下面指定矩陣變換輸入圖像:

dst(x',y')<-src(x,y)
若指定 CV_WARP_INVERSE_MAP, (tx',ty',t)T=map_matrix•(x,y,1)T+b
否則, (tx, ty, t)T=map_matrix•(x',y',1)T+b

要變換稀疏矩陣,使用 cxcore 中的函數 cvTransform 。


4個對應點計算透視變換矩陣

CvMat* cvWarpPerspectiveQMatrix( const CvPoint2D32f* src,
                                 const CvPoint2D32f* dst,
                                 CvMat* map_matrix );

 src 

輸入圖像的四邊形的4個點座標
dst 
輸出圖像的對應四邊形的4個點座標
map_matrix 
輸出的 3×3 矩陣

函數 cvWarpPerspectiveQMatrix 計算透視變換矩陣,使得:

(tix'i,tiy'i,ti)T=matrix•(xi,yi,1)T

where dst(i)=(x'i,y'i), src(i)=(xi,yi), i=0..3.

 

HUNNISH 注:

本翻譯是直接根據 OpenCV Beta 4.0 版本的用戶手冊翻譯的,原文件是:<opencv_directory>/doc/ref/opencvref_cv.htm, 可以從 SOURCEFORG 上面的OpenCV 項目下載。

翻譯中肯定有不少錯誤,另外也有些術語和原文語義理解不透導致翻譯不準確或者錯誤,也請有心人賜教。翻譯這些英文參考手冊的目的是想與國內 OPENCV 的愛好者一起提高 OPENCV 在計算機視覺、模式識別和圖像處理方面的實際應用水平。


創建結構元素

IplConvKernel* cvCreateStructuringElementEx( int cols, int rows, int anchor_x, int anchor_y,
                                             int shape, int* values=NULL );

 cols 

結構元素的列數目 
rows 
結構元素的行數目 
anchor_x 
錨點的相對水平偏移量 
anchor_y 
錨點的相對垂直便宜量 
shape 
結構元素的形狀,可以是下列值:
  • CV_SHAPE_RECT, 長方形元素;
  • CV_SHAPE_CROSS, 交錯元素 a cross-shaped element;
  • CV_SHAPE_ELLIPSE, 橢圓元素;
  • CV_SHAPE_CUSTOM, 用戶自定義元素。這種情況下參數 values 定義了 mask,即象素的那個鄰域必須考慮。
values 
指向結構元素的指針,它是一個平面數組,表示對元素矩陣逐行掃描。非零值的點表示該點屬於該元素。如果點爲 NULL,那麼所有值都被認爲是非零,即元素是一個長方形。該參數僅僅當形狀是CV_SHAPE_CUSTOM 時才予以考慮。

函數 cv CreateStructuringElementEx 分配和填充結構 IplConvKernel, 它可作爲形態操作中的結構元素。


刪除結構元素

void cvReleaseStructuringElement( IplConvKernel** element );

 element 

被刪除的結構元素的指針

函數 cvReleaseStructuringElement 釋放結構 IplConvKernel 。如果*elementNULL, 則函數不作用。


使用結構元素腐蝕圖像

void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );

 src 

輸入圖像. 
dst 
輸出圖像. 
element 
用於腐蝕的結構元素。若爲 NULL, 則使用 3×3 長方形的結構元素 
iterations 
腐蝕的次數

函數 cvErode 對輸入圖像使用指定的結構元素進行腐蝕,該結構決定每個具有最小值象素點的鄰域形狀:

dst=erode(src,element):  dst(x,y)=min((x',y') in element))src(x+x',y+y')

函數支持(in-place)模式。腐蝕可以重複進行 (iterations) 次. 對彩色圖像,每個彩色通道單獨處理。


使用結構元素膨脹圖像

void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );

 src 

輸入圖像. 
dst 
輸出圖像. 
element 
用於膨脹的結構元素。若爲 NULL, 則使用 3×3 長方形的結構元素 
iterations 
膨脹的次數

函數 cvErode 對輸入圖像使用指定的結構元素進行腐蝕,該結構決定每個具有最小值象素點的鄰域形狀:

函數 cvDilate 對輸入圖像使用指定的結構元素進行膨脹,該結構決定每個具有最小值象素點的鄰域形狀:

dst=dilate(src,element):  dst(x,y)=max((x',y') in element))src(x+x',y+y')

函數支持(in-place)模式。膨脹可以重複進行 (iterations) 次. 對彩色圖像,每個彩色通道單獨處理。


高級形態變換

void cvMorphologyEx( const CvArr* src, CvArr* dst, CvArr* temp,
                     IplConvKernel* element, int operation, int iterations=1 );

 src 

輸入圖像. 
dst 
輸出圖像. 
temp 
臨死圖像,某些情況下需要 
element 
結構元素 
operation 
形態操作的類型:
CV_MOP_OPEN - 開口
CV_MOP_CLOSE - 閉口
CV_MOP_GRADIENT - 形態梯度
CV_MOP_TOPHAT - "頂帽"
CV_MOP_BLACKHAT - "黑帽"
iterations 
膨脹和腐蝕次數.

函數 cvMorphologyEx 在膨脹和腐蝕基本操作的基礎上,完成一些高級的形態變換:

開口:
dst=open(src,element)=dilate(erode(src,element),element)

閉口:
dst=close(src,element)=erode(dilate(src,element),element)

形態梯度
dst=morph_grad(src,element)=dilate(src,element)-erode(src,element)

"頂帽":
dst=tophat(src,element)=src-open(src,element)

"黑帽":
dst=blackhat(src,element)=close(src,element)-src

臨時圖像 temp 在形態梯度以及對“頂帽”和“黑帽”操作時的 in-place 模式下需要。


各種方法的圖像平滑

void cvSmooth( const CvArr* src, CvArr* dst,
               int smoothtype=CV_GAUSSIAN,
               int param1=3, int param2=0, double param3=0 );

 src 

輸入圖像. 
dst 
輸出圖像. 
smoothtype 
平滑方法:
  • CV_BLUR_NO_SCALE (簡單不帶尺度變換的模糊) - 對每個象素領域 param1×param2 求和。如果鄰域大小是變化的,可以事先利用函數cvIntegral 計算積分圖像。
  • CV_BLUR (simple blur) - 對每個象素鄰域 param1×param2 求和並做尺度變換 1/(param1param2).
  • 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
param1 
平滑操作的第一個參數. 
param2 
平滑操作的第二個參數. param2 爲零對應簡單的尺度變換和高斯模糊。 
param3 
對應高斯參數的 Gaussian sigma (標準差). 如果爲零,這由下面的核尺寸計算:
              sigma = (n/2 - 1)*0.3 + 0.8, 其中 n=param1 對應水平核,
                                                n=param2 對應垂直核.
              
對小的卷積核 (3×3 to 7×7) 使用標準 sigma 速度會快。如果 param3 不爲零,而 param1param2 爲零,則核大小有 sigma 計算 (以保證足夠精確的操作).

函數 cvSmooth 可使用上面任何一種方法平滑圖像。每一種方法都有自己的特點以及侷限。

沒有縮放的圖像平滑僅支持單通道圖像,並且支持8位、16位、32位和32位浮點格式。

簡單模糊和高斯模糊支持 1- 或 3-通道, 8-比特 和 32-比特 浮點圖像。這兩種方法可以(in-place)方式處理圖像。

中值和雙向濾波工作於 1- 或 3-通道, 8-位圖像,但是不能以 in-place 方式處理圖像.


對圖像做卷積

void cvFilter2D( const CvArr* src, CvArr* dst,
                 const CvMat* kernel,
                 CvPoint anchor=cvPoint(-1,-1));
#define cvConvolve2D cvFilter2D

 src 

輸入圖像. 
dst 
輸出圖像. 
kernel 
卷積核, 單通道浮點矩陣. 如果想要應用不同的核於不同的通道,先用 cvSplit 函數分解圖像到單個色彩通道上,然後單獨處理。 
anchor 
核的錨點表示一個被濾波的點在覈內的位置。 錨點應該處於核內部。缺省值 (-1,-1) 表示錨點在覈中心。

函數 cvFilter2D 對圖像進行線性濾波,支持 In-place 操作。當開孔部分位於圖像外面時,函數從最近鄰的圖像內部象素差值得到邊界外面的象素值。


計算積分圖像

void cvIntegral( const CvArr* image, CvArr* sum, CvArr* sqsum=NULL, CvArr* tilted_sum=NULL );

 image 

輸入圖像, W×H, 單通道,8位或浮點 (32f 或 64f). 
sum 
積分圖像, W+1×H+1, 單通道,32位整數或 double 精度的浮點數(64f). 
sqsum 
對象素值平方的積分圖像,W+1×H+1, 單通道,32位整數或 double 精度的浮點數 (64f). 
tilted_sum 
旋轉45度的積分圖像,單通道,32位整數或 double 精度的浮點數 (64f).

函數 cvIntegral 計算一次或高次積分圖像:

sum(X,Y)=sumx<X,y<Yimage(x,y)

sqsum(X,Y)=sumx<X,y<Yimage(x,y)2

tilted_sum(X,Y)=sumy<Y,abs(x-X)<yimage(x,y)

利用積分圖像,可以方便得到某個區域象素點的和、均值、標準方差或在 0(1) 的選擇角度。例如:


sumx1<=x<x2,y1<=y<y2image(x,y)=sum(x2,y2)-sum(x1,y2)-sum(x2,y1)+sum(x1,x1)

因此可以在變化的窗口內做快速平滑或窗口相關。


色彩空間轉換

void cvCvtColor( const CvArr* src, CvArr* dst, int code );

 src 

輸入的 8-比特 或浮點圖像. 
dst 
輸出的 8-比特 或浮點圖像. 
code 
色彩空間轉換,通過定義 CV_<src_color_space>2<dst_color_space> 常數 (見下面).

函數 cvCvtColor 將輸入圖像從一個色彩空間轉換爲另外一個色彩空間。函數忽略 IplImage 頭中定義的 colorModelchannelSeq 域,所以輸入圖像的色彩空間應該正確指定 (包括通道的順序,對RGB空間而言,BGR 意味着 24-位格式,其排列爲 B0 G0 R0 B1 G1 R1 ... 層疊,而 RGB 意味着 24-位格式,其排列爲 R0 G0 B0 R1 G1 B1 ... 層疊). 函數做如下變換:

  • RGB 空間內部的變換,如增加/刪除 alpha 通道,反相通道順序,16位  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 + 128
    
    R=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=G
       240+(R - G)*60/S,  if V=B
    
    if 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.008856
    
    a = 500*(f(X)-f(Y))
    b = 200*(f(Y)-f(Z))
    where f(t)=t1/3              for t>0.008856
          f(t)=7.787*t+16/116   for t<=0.008856
    
    上面的公式可以參考 http://www.cica.indiana.edu/cica/faq/color_spaces/color.spaces.html

  • 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

     

    The output RGB components of a pixel are interpolated from 1, 2 or 4 neighbors of the pixel having the same color. There are several modifications of the above pattern that can be achieved by shifting the pattern one pixel left and/or one pixel up. The two letters C1 and C2 in the conversion constants CV_BayerC1C22{BGR|RGB} indicate the particular pattern type - these are components from the second row, second and third columns, respectively. For example, the above pattern has very popular "BG" type.


對數組元素進行固定閾值操作

void cvThreshold( const CvArr* src, CvArr* dst, double threshold,
                  double max_value, int threshold_type );

 src 

原始數組 (單通道, 8-比特 of 32-比特 浮點數). 
dst 
輸出數組,必須與 src 的類型一致,或者爲 8-比特. 
threshold 
閾值 
max_value 
使用 CV_THRESH_BINARYCV_THRESH_BINARY_INV 的最大值. 
threshold_type 
閾值類型 (見討論)

函數 cvThreshold 對單通道數組應用固定閾值操作。典型的是對灰度圖像進行閾值操作得到二值圖像。(cvCmpS 也可以達到此目的) 或者是去掉噪聲,例如過濾很小或很大象素值的圖像點。有好幾種對圖像取閾值的方法,本函數支持的方法由threshold_type 確定:

threshold_type=CV_THRESH_BINARY:
dst(x,y) = max_value, if src(x,y)>threshold
           0, otherwise

threshold_type=CV_THRESH_BINARY_INV:
dst(x,y) = 0, if src(x,y)>threshold
           max_value, otherwise

threshold_type=CV_THRESH_TRUNC:
dst(x,y) = threshold, if src(x,y)>threshold
           src(x,y), otherwise

threshold_type=CV_THRESH_TOZERO:
dst(x,y) = src(x,y), if (x,y)>threshold
           0, otherwise

threshold_type=CV_THRESH_TOZERO_INV:
dst(x,y) = 0, if src(x,y)>threshold
           src(x,y), otherwise


自適應閾值方法

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 

輸入圖像. 
dst 
輸出圖像. 
max_value 
使用 CV_THRESH_BINARYCV_THRESH_BINARY_INV 的最大值. 
adaptive_method 
自適應閾值算法使用:CV_ADAPTIVE_THRESH_MEAN_CCV_ADAPTIVE_THRESH_GAUSSIAN_C (見討論). 
threshold_type 
取閾值類型:必須是下者之一
  • CV_THRESH_BINARY,
  • CV_THRESH_BINARY_INV
block_size 
用來計算閾值的象素鄰域大小: 3, 5, 7, ... 
param1 
與方法有關的參數。對方法 CV_ADAPTIVE_THRESH_MEAN_CCV_ADAPTIVE_THRESH_GAUSSIAN_C, 它是一個從均值或加權均值提取的常數(見討論), 儘管它可以是負數。

函數 cvAdaptiveThreshold 將灰度圖像變換到二值圖像,採用下面公式:

threshold_type=CV_THRESH_BINARY:
dst(x,y) = max_value, if src(x,y)>T(x,y)
           0, otherwise

threshold_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,它是 block_size × block_size 塊中的象素點,被參數 param1 所減,得到的均值,

對方法 CV_ADAPTIVE_THRESH_GAUSSIAN_C 它是 block_size × block_size 塊中的象素點,被參數 param1 所減,得到的加權和(gaussian)。

 CamShift算法

採用 CAMSHIFT 算法快速跟蹤和檢測運動目標的 C/C++ 源代碼,OPENCV BETA 4.0 版本在其 SAMPLE 中給出了這個例子。算法的簡單描述如下(英文):

This application demonstrates a fast, simple color tracking algorithm that can be used to track faces, hands . The CAMSHIFT algorithm is a modification of the Meanshift algorithm which is a robust statistical method of finding the mode (top) of a probability distribution. Both CAMSHIFT and Meanshift algorithms exist in the library. While it is a very fast and simple method of tracking, because CAMSHIFT tracks the center and size of the probability distribution of an object, it is only as good as the probability distribution that you produce for the object. Typically the probability distribution is derived from color via a histogram, although it could be produced from correlation, recognition scores or bolstered by frame differencing or motion detection schemes, or joint probabilities of different colors/motions etc.

In this application, we use only the most simplistic approach: A 1-D Hue histogram is sampled from the object in an HSV color space version of the image. To produce the probability image to track, histogram "back projection" (we replace image pixels by their histogram hue value) is used.

算法的詳細情況,請看論文:

http://www.assuredigit.com/incoming/camshift.pdf

 

CamShift算法,即"Continuously Apative Mean-Shift"算法,是一種運動跟蹤算法。它主要通過視頻圖像中運動物體的顏色信息來達到跟蹤的目的。把這個算法分解成三個部分:

  • Back Projection計算。
  • Mean Shift算法
  • CamShift算法

1 Back Projection計算
計算Back Projection的步驟是這樣的:

1. 計算被跟蹤目標的色彩直方圖。在各種色彩空間中,只有HSI空間(或與HSI類似的色彩空間)中的H分量可以表示顏色信息。所以在具體的計算過程中,首先將其他的色彩空間的值轉化到HSI空間,然後會其中的H分量做1D直方圖計算。

2. 根據獲得的色彩直方圖將原始圖像轉化成色彩概率分佈圖像,這個過程就被稱作"Back Projection"。

OpenCV中的直方圖函數中,包含Back Projection的函數,函數原型是:

   void cvCalcBackProject(IplImage** img, CvArr** backproject, const CvHistogram* hist);

傳遞給這個函數的參數有三個:

1. IplImage** img:存放原始圖像,輸入。

2. CvArr** backproject:存放Back Projection結果,輸出。

3. CvHistogram* hist:存放直方圖,輸入

下面就給出計算Back Projection的OpenCV代碼。

1.準備一張只包含被跟蹤目標的圖片,將色彩空間轉化到HSI空間,獲得其中的H分量:

  IplImage* target=cvLoadImage("target.bmp",-1);  //裝載圖片

  IplImage* target_hsv=cvCreateImage( cvGetSize(target), IPL_DEPTH_8U, 3 );

  IplImage* target_hue=cvCreateImage( cvGetSize(target), IPL_DEPTH_8U, 3 );

  cvCvtColor(target,target_hsv,CV_BGR2HSV);       //轉化到HSV空間

  cvSplit( target_hsv, target_hue, NULL, NULL, NULL );    //獲得H分量

2.計算H分量的直方圖,即1D直方圖:

  IplImage* h_plane=cvCreateImage( cvGetSize(target_hsv),IPL_DEPTH_8U,1 );

  int hist_size[]={255};          //將H分量的值量化到[0,255]

  float* ranges[]={ {0,360} };    //H分量的取值範圍是[0,360)

  CvHistogram* hist=cvCreateHist(1, hist_size, ranges, 1);

  cvCalcHist(&target_hue, hist, 0, NULL);

在這裏需要考慮H分量的取值範圍的問題,H分量的取值範圍是[0,360),這個取值範圍的值不能用一個byte來表示,爲了能用一個byte表示,需要將H值做適當的量化處理,在這裏我們將H分量的範圍量化到[0,255].

4.計算Back Projection:

  1. IplImage* rawImage;
  2. //----------------------------------------------
  3. //get from video frame,unsigned byte,one channel
  4. //----------------------------------------------
  5. IplImage* result=cvCreateImage(cvGetSize(rawImage),IPL_DEPTH_8U,1);
  6. cvCalcBackProject(&rawImage,result,hist);

5.結果:result即爲我們需要的.

2) Mean Shift算法

這裏來到了CamShift算法,OpenCV實現的第二部分,這一次重點討論Mean Shift算法。

在討論Mean Shift算法之前,首先討論在2D概率分佈圖像中,如何計算某個區域的重心(Mass Center)的問題,重心可以通過以下公式來計算:

1.計算區域內0階矩

  1. for(int i=0;i<height;i++)
  2. for(int j=0;j<width;j++)
  3. M00+=I(i,j)

2.區域內1階矩:

  1. for(int i=0;i<height;i++)
  2. for(int j=0;j<width;j++)
  3. {
  4. M10+=i*I(i,j);
  5. M01+=j*I(i,j);
  6. }

3.則Mass Center爲:

Xc=M10/M00; Yc=M01/M00

接下來,討論Mean Shift算法的具體步驟,Mean Shift算法可以分爲以下4步:

1.選擇窗的大小和初始位置.

2.計算此時窗口內的Mass Center.

3.調整窗口的中心到Mass Center.

4.重複2和3,直到窗口中心"會聚",即每次窗口移動的距離小於一定的閾值。

OpenCV中,提供Mean Shift算法的函數,函數的原型是:

int cvMeanShift(IplImage* imgprob,CvRect windowIn, CvTermCriteria criteria,CvConnectedComp* out);

需要的參數爲:

1.IplImage* imgprob:2D概率分佈圖像,傳入;

2.CvRect windowIn:初始的窗口,傳入;

3.CvTermCriteria criteria:停止迭代的標準,傳入;

4.CvConnectedComp* out:查詢結果,傳出。

(注:構造CvTermCriteria變量需要三個參數,一個是類型,另一個是迭代的最大次數,最後一個表示特定的閾值。例如可以這樣構造 criteria:criteria=cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,10,0.1)。)

返回的參數:

1.int:迭代的次數。

實現代碼:暫時缺

3) CamShift算法
1.原理

在瞭解了MeanShift算法以後,我們將MeanShift算法擴展到連續圖像序列(一般都是指視頻圖像序列),這樣就形成了CamShift 算法。CamShift算法的全稱是"Continuously Apaptive  Mean-SHIFT",它的基本思想是視頻圖像的所有幀作MeanShift運算,並將上一幀的結果(即Search  Window的中心和大小)作爲下一幀MeanShift算法的Search  Window的初始值,如此迭代下去,就可以實現對目標的跟蹤。整個算法的具體步驟分5步:

Step 1:將整個圖像設爲搜尋區域。

Step 2:初始話Search Window的大小和位置。

Step 3:計算Search Window內的彩色概率分佈,此區域的大小比Search Window要稍微大一點。

Step 4:運行MeanShift。獲得Search Window新的位置和大小。

Step 5:在下一幀視頻圖像中,用Step 3獲得的值初始化Search Window的位置和大小。跳轉到Step 3繼續運行。

2.實現

OpenCV中,有實現CamShift算法的函數,此函數的原型是:

  cvCamShift(IplImage* imgprob, CvRect windowIn,CvTermCriteria criteria,CvConnectedComp* out, CvBox2D* box=0);

其中:

   imgprob:色彩概率分佈圖像。

   windowIn:Search Window的初始值。

   Criteria:用來判斷搜尋是否停止的一個標準。

   out:保存運算結果,包括新的Search Window的位置和麪積。

   box:包含被跟蹤物體的最小矩形。

說明:

1.在OpenCV 4.0 beta的目錄中,有CamShift的例子。遺憾的是這個例子目標的跟蹤是半自動的,即需要人手工選定一個目標。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章