1. 程式人生 > >LBP小結:LBP及改進版本的原理和opencv實現原始碼

LBP小結:LBP及改進版本的原理和opencv實現原始碼

一、LBP特徵的背景介紹

LBP指區域性二值模式,英文全稱:Local Binary Pattern,是一種用來描述影象區域性特徵的運算元,LBP特徵具有灰度不變性和旋轉不變性等顯著優點。它是由T. Ojala, M.Pietikäinen, 和 D. Harwood [1][2]在1994年提出,由於LBP特徵計算簡單、效果較好,因此LBP特徵在計算機視覺的許多領域都得到了廣泛的應用,LBP特徵比較出名的應用是用在人臉識別和目標檢測中,在計算機視覺開源庫Opencv中有使用LBP特徵進行人臉識別的介面,也有用LBP特徵訓練目標檢測分類器的方法,Opencv實現了LBP特徵的計算,但沒有提供一個單獨的計算LBP特徵的介面。

二、LBP特徵的原理

1、原始LBP特徵描述及計算方法

原始的LBP運算元定義在畫素3*3的鄰域內,以鄰域中心畫素為閾值,相鄰的8個畫素的灰度值與鄰域中心的畫素值進行比較,若周圍畫素大於中心畫素值,則該畫素點的位置被標記為1,否則為0。這樣,3*3鄰域內的8個點經過比較可產生8位二進位制數,將這8位二進位制數依次排列形成一個二進位制數字,這個二進位制數字就是中心畫素的LBP值,LBP值共有28種可能,因此LBP值有256種。中心畫素的LBP值反映了該畫素周圍區域的紋理資訊。 
備註:計算LBP特徵的影象必須是灰度圖,如果是彩色圖,需要先轉換成灰度圖。 
上述過程用影象表示為: 
這裡寫圖片描述 
這裡寫圖片描述 
將上述過程用公式表示為: 
這裡寫圖片描述

 
(xc,yc)為中心畫素的座標,p為鄰域的第p個畫素,ip為鄰域畫素的灰度值,ic為中心畫素的灰度值,s(x)為符號函式

原始LBP特徵計算程式碼(Opencv下):

//原始LBP特徵計算
template <typename _tp>
void getOriginLBPFeature(InputArray _src,OutputArray _dst)
{
    Mat src = _src.getMat();
    _dst.create(src.rows-2,src.cols-2,CV_8UC1);
    Mat dst = _dst.getMat();
    dst.setTo
(0); for(int i=1;i<src.rows-1;i++) { for(int j=1;j<src.cols-1;j++) { _tp center = src.at<_tp>(i,j); unsigned char lbpCode = 0; lbpCode |= (src.at<_tp>(i-1,j-1) > center) << 7; lbpCode |= (src.at<_tp>(i-1,j ) > center) << 6; lbpCode |= (src.at<_tp>(i-1,j+1) > center) << 5; lbpCode |= (src.at<_tp>(i ,j+1) > center) << 4; lbpCode |= (src.at<_tp>(i+1,j+1) > center) << 3; lbpCode |= (src.at<_tp>(i+1,j ) > center) << 2; lbpCode |= (src.at<_tp>(i+1,j-1) > center) << 1; lbpCode |= (src.at<_tp>(i ,j-1) > center) << 0; dst.at<uchar>(i-1,j-1) = lbpCode; } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

測試結果: 
這裡寫圖片描述

2、LBP特徵的改進版本

在原始的LBP特徵提出以後,研究人員對LBP特徵進行了很多的改進,因此產生了許多LBP的改進版本。

2.1 圓形LBP特徵(Circular LBP or Extended LBP)

       由於原始LBP特徵使用的是固定鄰域內的灰度值,因此當影象的尺度發生變化時,LBP特徵的編碼將會發生錯誤,LBP特徵將不能正確的反映畫素點周圍的紋理資訊,因此研究人員對其進行了改進[3]。基本的 LBP 運算元的最大缺陷在於它只覆蓋了一個固定半徑範圍內的小區域,這顯然不能滿足不同尺寸和頻率紋理的需要。為了適應不同尺度的紋理特徵,並達到灰度和旋轉不變性的要求,Ojala 等對 LBP 運算元進行了改進,將 3×3 鄰域擴充套件到任意鄰域,並用圓形鄰域代替了正方形鄰域,改進後的 LBP 運算元允許在半徑為 R 的圓形鄰域內有任意多個畫素點。從而得到了諸如半徑為R的圓形區域內含有P個取樣點的LBP運算元: 
這裡寫圖片描述 
這種LBP特徵叫做Extended LBP,也叫Circular LBP。使用可變半徑的圓對近鄰畫素進行編碼,可以得到如下的近鄰: 
這裡寫圖片描述 
對於給定中心點(xc,yc),其鄰域畫素位置為(xp,yp)pP,其取樣點(xp,yp)用如下公式計算:

這裡寫圖片描述 
R是取樣半徑,p是第p個取樣點,P是取樣數目。由於計算的值可能不是整數,即計算出來的點不在影象上,我們使用計算出來的點的插值點。目的的插值方法有很多,Opencv使用的是雙線性插值,雙線性插值的公式如下: 
這裡寫圖片描述 
通過LBP特徵的定義可以看出,LBP特徵對光照變化是魯棒的,其效果如下圖所示: 
這裡寫圖片描述

//圓形LBP特徵計算,這種方法適於理解,但在效率上存在問題,宣告時預設neighbors=8
template <typename _tp>
void getCircularLBPFeature(InputArray _src,OutputArray _dst,int radius,int neighbors)
{
    Mat src = _src.getMat();
    //LBP特徵影象的行數和列數的計算要準確
    _dst.create(src.rows-2*radius,src.cols-2*radius,CV_8UC1);
    Mat dst = _dst.getMat();
    dst.setTo(0);
    //迴圈處理每個畫素
    for(int i=radius;i<src.rows-radius;i++)
    {
        for(int j=radius;j<src.cols-radius;j++)
        {
            //獲得中心畫素點的灰度值
            _tp center = src.at<_tp>(i,j);
            unsigned char lbpCode = 0;
            for(int k=0;k<neighbors;k++)
            {
                //根據公式計算第k個取樣點的座標,這個地方可以優化,不必每次都進行計算radius*cos,radius*sin
                float x = i + static_cast<float>(radius * \
                    cos(2.0 * CV_PI * k / neighbors));
                float y = j - static_cast<float>(radius * \
                    sin(2.0 * CV_PI * k / neighbors));
                //根據取整結果進行雙線性插值,得到第k個取樣點的灰度值

                //1.分別對x,y進行上下取整
                int x1 = static_cast<int>(floor(x));
                int x2 = static_cast<int>(ceil(x));
                int y1 = static_cast<int>(floor(y));
                int y2 = static_cast<int>(ceil(y));

                //2.計算四個點(x1,y1),(x1,y2),(x2,y1),(x2,y2)的權重
                //下面的權重計算方式有個問題,如果四個點都相等,則權重全為0,計算出來的插值為0
                //float w1 = (x2-x)*(y2-y); //(x1,y1)
                //float w2 = (x2-x)*(y-y1); //(x1,y2)
                //float w3 = (x-x1)*(y2-y); //(x2,y1)
                //float w4 = (x-x1)*(y-y1); //(x2,y2)

                //將座標對映到0-1之間
                float tx = x - x1;
                float ty = y - y1;
                //根據0-1之間的x,y的權重計算公式計算權重
                float w1 = (1-tx) * (1-ty);
                float w2 =    tx  * (1-ty);
                float w3 = (1-tx) *    ty;
                float w4 =    tx  *    ty;
                //3.根據雙線性插值公式計算第k個取樣點的灰度值
                float neighbor = src.at<_tp>(x1,y1) * w1 + src.at<_tp>(x1,y2) *w2 \
                    + src.at<_tp>(x2,y1) * w3 +src.at<_tp>(x2,y2) *w4;
                //通過比較獲得LBP值,並按順序排列起來
                lbpCode |= (neighbor>center) <<(neighbors-k-1);
            }
            dst.at<uchar>(i-radius,j-radius) = lbpCode;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
//圓形LBP特徵計算,效率優化版本,宣告時預設neighbors=8
template <typename _tp>
void getCircularLBPFeatureOptimization(InputArray _src,OutputArray _dst,int radius,int neighbors)
{
    Mat src = _src.getMat();
    //LBP特徵影象的行數和列數的計算要準確
    _dst.create(src.rows-2*radius,src.cols-2*radius,CV_8UC1);
    Mat dst = _dst.getMat();
    dst.setTo(0);
    for(int k=0;k<neighbors;k++)
    {
        //計算取樣點對於中心點座標的偏移量rx,ry
        float rx = static_cast<float>(radius * cos(2.0 * CV_PI * k / neighbors));
        float ry = -static_cast<float>(radius * sin(2.0 * CV_PI * k / neighbors));
        //為雙線性插值做準備
        //對取樣點偏移量分別進行上下取整
        int x1 = static_cast<int>(floor(rx));
        int x2 = static_cast<int>(ceil(rx));
        int y1 = static_cast<int>(floor(ry));
        int y2 = static_cast<int>(ceil(ry));
        //將座標偏移量對映到0-1之間
        float tx = rx - x1;
        float ty = ry - y1;
        //根據0-1之間的x,y的權重計算公式計算權重,權重與座標具體位置無關,與座標間的差值有關
        float w1 = (1-tx) * (1-ty);
        float w2 =    tx  * (1-ty);
        float w3 = (1-tx) *    ty;
        float w4 =    tx  *    ty;
        //迴圈處理每個畫素
        for(int i=radius;i<src.rows-radius;i++)
        {
            for(int j=radius;j<src.cols-radius;j++)
            {
                //獲得中心畫素點的灰度值
                _tp center = src.at<_tp>(i,j);
                //根據雙線性插值公式計算第k個取樣點的灰度值
                float neighbor = src.at<_tp>(i+x1,j+y1) * w1 + src.at<_tp>(i+x1,j+y2) *w2 \
                    + src.at<_tp>(i+x2,j+y1) * w3 +src.at<_tp>(i+x2,j+y2) *w4;
                //LBP特徵影象的每個鄰居的LBP值累加,累加通過與操作完成,對應的LBP值通過移位取得
                dst.at<uchar>(i-radius,j-radius) |= (neighbor>center) <<(neighbors-k-1);
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

測試結果: 
radius = 3,neighbors = 8 
這裡寫圖片描述 
第三幅影象為radius = 3,neighbors = 8,第四幅影象為radius = 1,neighbors = 8,從實驗結果可以看出,半徑越小,影象紋理越精細 
這裡寫圖片描述 
第三幅影象為radius = 3,neighbors = 8,第四幅影象為radius = 3,neighbors = 4,從實驗結果可以看出,鄰域數目越小,影象亮度越低,合理,因此4位的灰度值很小 
由於我程式碼的問題,不能使neighbors >8,可改進 
這裡寫圖片描述

2.2 旋轉不變LBP特徵

       從上面可以看出,上面的LBP特徵具有灰度不變性,但還不具備旋轉不變性,因此研究人員又在上面的基礎上進行了擴充套件,提出了具有旋轉不變性的LBP特徵。 
首先不斷的旋轉圓形鄰域內的LBP特徵,根據選擇得到一系列的LBP特徵值,從這些LBP特徵值選擇LBP特徵值最小的作為中心畫素點的LBP特徵。具體做法如下圖所示: 
這裡寫圖片描述 
如圖,通過對得到的LBP特徵進行旋轉,得到一系列的LBP特徵值,最終將特徵值最小的一個特徵模式作為中心畫素點的LBP特徵。

//旋轉不變圓形LBP特徵計算,宣告時預設neighbors=8
template <typename _tp>
void getRotationInvariantLBPFeature(InputArray _src,OutputArray _dst,int radius,int neighbors)
{
    Mat src = _src.getMat();
    //LBP特徵影象的行數和列數的計算要準確
    _dst.create(src.rows-2*radius,src.cols-2*radius,CV_8UC1);
    Mat dst = _dst.getMat();
    dst.setTo(0);
    for(int k=0;k<neighbors;k++)
    {
        //計算取樣點對於中心點座標的偏移量rx,ry
        float rx = static_cast<float>(radius * cos(2.0 * CV_PI * k / neighbors));
        float ry = -static_cast<float>(radius * sin(2.0 * CV_PI * k / neighbors));
        //為雙線性插值做準備
        //對取樣點偏移量分別進行上下取整
        int x1 = static_cast<int>(floor(rx));
        int x2 = static_cast<int>(ceil(rx));
        int y1 = static_cast<int>(floor(ry));
        int y2 = static_cast<int>(ceil(ry));
        //將座標偏移量對映到0-1之間
        float tx = rx - x1;
        float ty = ry - y1;
        //根據0-1之間的x,y的權重計算公式計算權重,權重與座標具體位置無關,與座標間的差值有關
        float w1 = (1-tx) * (1-ty);
        float w2 =    tx  * (1-ty);
        float w3 = (1-tx) *    ty;
        float w4 =    tx  *    ty;
        //迴圈處理每個畫素
        for(int i=radius;i<src.rows-radius;i++)
        {
            for(int j=radius;j<src.cols-radius;j++)
            {
                //獲得中心畫素點的灰度值
                _tp center = src.at<_tp>(i,j);
                //根據雙線性插值公式計算第k個取樣點的灰度值
                float neighbor = src.at<_tp>(i+x1,j+y1) * w1 + src.at<_tp>(i+x1,j+y2) *w2 \
                    + src.at<_tp>(i+x2,j+y1) * w3 +src.at<_tp>(i+x2,j+y2) *w4;
                //LBP特徵影象的每個鄰居的LBP值累加,累加通過與操作完成,對應的LBP值通過移位取得
                dst.at<uchar>(i-radius,j-radius) |= (neighbor>center) <<(neighbors-k-1);
            }
        }
    }
    //進行旋轉不變處理
    for(int i=0;i<dst.rows;i++)
    {
        for(int j=0;j<dst.cols;j++)
        {
            unsigned char currentValue = dst.at<uchar>(i,j);
            unsigned char minValue = currentValue;
            for(int k=1;k<neighbors;k++)
            {
    //迴圈左移
                unsigned char temp = (currentValue>>(neighbors-k)) | (currentValue<<k);
                if(temp < minValue)
                {
                    minValue = temp;
                }
            }
            dst.at<uchar>(i,j) = minValue;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

測試結果: 
radius = 3,neighbors = 8,最後一幅是旋轉不變LBP特徵 
這裡寫圖片描述

2.3 Uniform Pattern LBP特徵

       Uniform Pattern,也被稱為等價模式或均勻模式,由於一個LBP特徵有多種不同的二進位制形式,對於半徑為R的圓形區域內含有P個取樣點的LBP運算元將會產生2P種模式。很顯然,隨著鄰域集內取樣點數的增加,二進位制模式的種類是以指數形式增加的。例如:5×5鄰域內20個取樣點,有220=1,048,576種二進位制模式。這麼多的二進位制模式不利於紋理的提取、分類、識別及存取。例如,將LBP運算元用於紋理分類或人臉識別時,常採用LBP模式的統計直方圖來表達影象的資訊,而較多的模式種類將使得資料量過大,且直方圖過於稀疏。因此,需要對原始的LBP模式進行降維,使得資料量減少的情況下能最好的表示影象的資訊。 
    為了解決二進位制模式過多的問題,提高統計性,Ojala提出了採用一種“等價模式”(Uniform Pattern)來對LBP運算元的模式種類進行降維。Ojala等認為,在實際影象中,絕大多數LBP模式最多隻包含兩次從1到0或從0到1的跳變。因此,Ojala將“等價模式”定義為:當某個LBP所對應的迴圈二進位制數從0到1或從1到0最多有兩次跳變時,該LBP所對應的二進位制就稱為一個等價模式類。如00000000(0次跳變),00000111(只含一次從0到1的跳變),10001111(先由1跳到0,再由0跳到1,共兩次跳變)都是等價模式類。除等價模式類以外的模式都歸為另一類,稱為混合模式類,例如10010111(共四次跳變)。通過這樣的改進,二進位制模式的種類大大減少,而不會丟失任何資訊。模式數量由原來的2P種減少為 P ( P-1)+2種,其中P表示鄰域集內的取樣點數。對於3×3鄰域內8個取樣點來說,二進位制模式由原始的256種減少為58種,即:它把值分為59類,58個uniform pattern為一類,其它的所有值為第59類。這樣直方圖從原來的256維變成59維。這使得特徵向量的維數更少,並且可以減少高頻噪聲帶來的影響。 
    具體實現:取樣點數目為8個,即LBP特徵值有28種,共256個值,正好對應灰度影象的0-255,因此原始的LBP特徵影象是一幅正常的灰度影象,而等價模式LBP特徵,根據0-1跳變次數,將這256個LBP特徵值分為了59類,從跳變次數上劃分:跳變0次—2個,跳變1次—0個,跳變2次—56個,跳變3次—0個,跳變4次—140個,跳變5次—0個,跳變6次—56個,跳變7次—0個,跳變8次—2個。共9種跳變情況,將這256個值進行分配,跳變小於2次的為等價模式類,共58個,他們對應的值按照從小到大分別編碼為1—58,即它們在LBP特徵影象中的灰度值為1—58,而除了等價模式類之外的混合模式類被編碼為0,即它們在LBP特徵中的灰度值為0,因此等價模式LBP特徵影象整體偏暗。

//等價模式LBP特徵計算
template <typename _tp>
void getUniformPatternLBPFeature(InputArray _src,OutputArray _dst,int radius,int neighbors)
{
    Mat src = _src.getMat();
    //LBP特徵影象的行數和列數的計算要準確
    _dst.create(src.rows-2*radius,src.cols-2*radius,CV_8UC1);
    Mat dst = _dst.getMat();
    dst.setTo(0);
    //LBP特徵值對應影象灰度編碼表,直接預設取樣點為8位
    uchar temp = 1;
    uchar table[256] = {0};
    for(int i=0;i<256;i++)
    {
        if(getHopTimes(i)<3)
        {
            table[i] = temp;
            temp++;
        }
    }
    //是否進行UniformPattern編碼的標誌
    bool flag = false;
    //計算LBP特徵圖
    for(int k=0;k<neighbors;k++)
    {
        if(k==neighbors-1)
        {
            flag = true;
        }
        //計算取樣點對於中心點座標的偏移量rx,ry
        float rx = static_cast<float>(radius * cos(2.0 * CV_PI * k / neighbors));
        float ry = -static_cast<float>(radius * sin(2.0 * CV_PI * k / neighbors));
        //為雙線性插值做準備
        //對取樣點偏移量分別進行上下取整
        int x1 = static_cast<int>(floor(rx));
        int x2 = static_cast<int>(ceil(rx));
        int y1 = static_cast<int>(floor(ry));
        int y2 = static_cast<int>(ceil(ry));
        //將座標偏移量對映到0-1之間
        float tx = rx - x1;
        float ty = ry - y1;
        //根據0-1之間的x,y的權重計算公式計算權重,權重與座標具體位置無關,與座標間的差值有關
        float w1 = (1-tx) * (1-ty);
        float w2 =    tx  * (1-ty);
        float w3 = (1-tx) *    ty;
        float w4 =    tx  *    ty;
        //迴圈處理每個畫素
        for(int i=radius;i<src.rows-radius;i++)
        {
            for(int j=radius;j<src.cols-radius;j++)
            {
                //獲得中心畫素點的灰度值
                _tp center = src.at<_tp>(i,j);
                //根據雙線性插值公式計算第k個取樣點的灰度值
                float neighbor = src.at<_tp>(i+x1,j+y1) * w1 + src.at<_tp>(i+x1,j+y2) *w2 \
                    + src.at<_tp>(i+x2,j+y1) * w3 +src.at<_tp>(i+x2,j+y2) *w4;
                //LBP特徵影象的每個鄰居的LBP值累加,累加通過與操作完成,對應的LBP值通過移位取得
                dst.at<uchar>(i-radius,j-radius) |= (neighbor>center) <<(neighbors-k-1);
                //進行LBP特徵的UniformPattern編碼
                if(flag)
                {
                    dst.at<uchar>(i-radius,j-radius) = table[dst.at<uchar>(i-radius,j-radius)];
                }
            }
        }
    }
}
//計算跳變次數
int getHopTimes(int n)
{
    int count = 0;
    bitset<8> binaryCode = n;
    for(int i=0;i<8;i++)
    {
        if(binaryCode[i] != binaryCode[(i+1)%8])
        {
            count++;
        }
    }
    return count;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

測試結果: 
radius = 3,neighbors = 8,最後一幅是等價模式LBP特徵 
這裡寫圖片描述

2.4 MB-LBP特徵

MB-LBP特徵,全稱為Multiscale Block LBP,來源於論文[9],中科院的人發明的,在Traincascade級聯目標訓練檢測中的LBP特徵使用的就是MB-LBP。 
MB-LBP的原理: 
這裡寫圖片描述 
將影象分成一個個小塊(Block),每個小塊再分為一個個的小區域(類似於HOG中的cell),小區域內的灰度平均值作為當前小區域的灰度值,與周圍小區域灰度進行比較形成LBP特徵,生成的特徵稱為MB-LBP,Block大小為3*3,則小區域的大小為1,就是原始的LBP特徵,上圖的Block大小為9*9,小區域的大小為3*3。 
不同Block提取的MB-LBP特徵如圖所示: 
這裡寫圖片描述 
計算MB-LBP程式碼:

            
           

相關推薦

LBP小結LBP改進版本原理opencv實現原始碼

一、LBP特徵的背景介紹 LBP指區域性二值模式,英文全稱:Local Binary Pattern,是一種用來描述影象區域性特徵的運算元,LBP特徵具有灰度不變性和旋轉不變性等顯著優點。它是由T. Ojala, M.Pietikäinen, 和 D. Harwood

SpringMvc Spring 工作原理作用

復雜 script 人員 部分 開發 cit 組件 上下 校驗和 1.springmvc請所有的請求都提交給DispatcherServlet,它會委托應用系統的其他模塊負責負責對請求進行真正的處理工作。   2.DispatcherServlet查詢一個或多個Ha

第7課實戰解析spark執行原理rdd解密

1.spark執行優勢 善於使用記憶體,磁碟,迭代式計算是其核心 2.現在為什麼很多公司都是使用java開發spark a.scala高手較少,java高手較多 b.專案對接比較容易 c.系統運維方便 3.spark只能取代hive的儲存引擎,不能取代hive的數倉部分 4.資料輸

深入理解JVM虛擬機器2JVM垃圾回收基本原理演算法

JVM GC基本原理與GC演算法  Java的記憶體分配與回收全部由JVM垃圾回收程序自動完成。與C語言不同,Java開發者不需要自己編寫程式碼實現垃圾回收。這是Java深受大家歡迎的眾多特性之一,能夠幫助程式設計師更好地編寫Java程式。  下面四篇教程是瞭解Jav

資料探勘十大演算法(五)EM(Expectation Maximum)演算法原理與Python實現

參考: 一、一個簡單的概率問題 實驗:現在有A和B兩個硬幣,我們從這兩個硬幣中,隨機選取5次,做5組實驗,每組實驗內容是:丟擲所選的硬幣,記錄正反面。 實驗資料如下: 目標:根據所得到的實驗資料,分別求出硬幣A和B丟擲後正面向上的概率。 根據古典概率的原

Android Studio 3.0 版本下載 gradle 各版本下載

Android Studio 3.0下載地址:Android Studio 3.0 包含了三大主要功能:一套全新的應用效能分析工具,用於快速診斷效能問題;支援 Kotlin 程式語言;加快大規模應用專案

SpringMVC攔截器實現原理登入實現

SpringMVC 攔截器的原理圖 springMVC攔截器的實現一般有兩種方式      第一種方式是要定義的Interceptor類要實現了Spring的HandlerInterceptor 介面    &n

Android熱修復(二)以DexClassLoader類載入原理編寫demo實現類替換修復

上一篇文章簡易總結了熱修復實現的幾大原理,並詳細介紹了Android中的類載入機制及原始碼探索,Android的類載入機制涉及到ClassLoader、DexClassLoader 、PathClassLoader 、BaseDexClassLoader 、De

數據結構-排序算法原理Python實現

遞歸 pivot 依次 新的 樹形 希爾排序 image pso 代碼 排序算法概覽 插入排序 基本思想是每次講一個待排序的記錄,按其關鍵字大小插入到前面已拍好的子序列中,直到全部完成。 直接插入排序 講元素L(i)插入到有序序列L[1,…,i-1]中,執行以下操作: 1

對數損失函數(Logarithmic Loss Function)的原理 Python 實現

NPU 技術分享 blog 入參 rom __main__ bsp nat () 原理   對數損失, 即對數似然損失(Log-likelihood Loss), 也稱邏輯斯諦回歸損失(Logistic Loss)或交叉熵損失(cross-entropy Loss), 是在

今日頭條面試題——LRU原理Redis實現

unsigned dom bestv acs 大量 不存在 技術 aci 頭條 很久前參加過今日頭條的面試,遇到一個題,目前半部分是如何實現 LRU,後半部分是 Redis 中如何實現 LRU。 我的第一反應應該是內存不夠的場景下,淘汰舊內容的策略。LRU ... Leas

LRU原理Redis實現——一個今日頭條的面試題

滿了 存儲空間 當前 node 硬盤 java 原理 remove http 看了評論,發現有些地方有問題,更新了圖和一些描述,希望可以更清晰一些,也歡迎關註,還會有幹貨文章 -------- 很久前參加過今日頭條的面試,遇到一個題,目前半部分是如何實現 LRU,後半部

今天我們來說說Ajax的原理怎麼實現非同步的!

純JavaScript實現非同步Ajax的基本原理 Ajax實際就是XMLHttpRequest物件和DOM、(X)HTML和CSS的簡稱,用於概括非同步載入頁面內容的技術。 Ajax例項 HTML程式碼如下,包含一個h5標題和一個按鈕: JS程式碼如下: 上述程

HOG原理OpenCV實現

方向梯度直方圖(Histogram of Oriented Gradient, HOG)於2005年提出,是一種常用的特徵提取方法,HOG+SVM在行人檢測中有著優異的效果。 HOG特徵提取演算法原理 在一幅影象中,梯度或邊緣的方向密度分佈能夠很好地描述區域性目標區域

常見素書篩選方法原理Python實現

1. 普通篩選(常用於求解單個素數問題) 自然數中,除了1和它本身以外不再有其他因數。 import math def func_get_prime(n): func = lambda x: not [x%i for i in range(2, int(ma

HashTable原理底層實現

1. 概述 上次討論了HashMap的結構,原理和實現,本文來對Map家族的另外一個常用集合HashTable進行介紹。HashTable和HashMap兩種集合非常相似,經常被各種面試官問到兩者的區別。 對於兩者的區別,主要有以下幾點: HashMap是非同步的,

AVL樹的旋轉圖解簡單實現

AVL樹的旋轉圖解和簡單實現 2017年07月07日 18:03:51 喵了個嗚s 閱讀數:11048 標籤: 二叉樹 資料結構 更多 個人分類: 資料結構 AVL樹是帶有平衡條件的查詢二叉樹。這個平衡條件要容易保持,而且他要保證樹的深度為O(logN) 平衡

LRU 原理 Redis 實現

轉自:https://baijiahao.baidu.com/s?id=1595292420641966263&wfr=spider&for=pc 很久前參加過今日頭條的面試,遇到一個題,目前半部分是如何實現 LRU,後半部分是 Redis 中如何實現 LRU。 我的第一反應

資料探勘十大演算法(九)樸素貝葉斯 pythonsklearn實現

第三個演算法終於算是稍有了解了,其實當你結合資料瞭解了它的實現原理後,你會發現確實很樸素。這裡對樸素貝葉斯演算法做一個介紹和總結,包括(原理、一個程式碼示例、sklearn實現),皆為親自實踐後的感悟,下面進入正文。 原理: 首先我們需要了解概率論的一些簡單知識:

gdb工作原理核心實現

gdb主要功能的實現依賴於一個系統函式ptrace,通過man手冊可以瞭解到,ptrace可以讓父程序觀察和控制其子程序的檢查、執行,改變其暫存器和記憶體的內容,主要應用於打斷點(也是gdb的主要功能)和列印系統呼叫軌跡。 一、ptrace函式 函式原型如下: