圖像處理之局部二值特徵

圖像處理之局部二值特徵

一:局部二值模式(LBP)介紹
局部二值模式(Local Binary Pattern)主要用來實現2D圖像紋理分析。其基本思想是用每個像素跟它周圍的像素相比較得到局部圖像結構,假設中心像素值大於相鄰像素值則則相鄰像素點賦值爲1,否則賦值爲0,最終對每個像素點都會得到一個二進制八位的表示,比如11100111。假設3x3的窗口大小,這樣對每個像素點來說組合得到的像素值的空間爲[0~2^8]。這種結果我稱爲圖像的局部二值模式或者簡寫爲了LBP。
這裏寫圖片描述

二:局部二值模式(LBP)擴展
對於這種固定窗口大小方式的局部二值模式,很多人很快就發現它的弊端,不能很好的反映出圖像結構,於是高人紛紛上陣把它改爲窗口大小可變,而且把矩形結構改成圓形結構。而且還總結出來如下一系列的典型結構單元:
這裏寫圖片描述

該操作是基於原來的局部二值模式的擴展,所以又被稱爲擴展的局部二值模式。但是一旦改爲圓形的時候,尋找八個點座標可能會產生小數座標,這個時候就需要通過插值方式產生該像素點的像素值,最常見的插值方式基於雙線性插值。這樣就完成了任意尺度上的局部二值模式的採樣。

三:運行
輸入圖像與3x3默認的LBP運行結果如下:
這裏寫圖片描述
在擴展模式下半徑分別爲1、3、5、7時候的運行結果:
這裏寫圖片描述

四:代碼實現 - 基於OpenCV實現
簡單說一下步驟
1. 讀入圖像
2. 彩色圖像轉灰度
3. 默認LBP處理操作
4. 擴展LBP處理操作
完整的源代碼如下:

#include <opencv2/opencv.hpp>
#include <iostream>
#include "math.h"

using namespace cv;
using namespace std;

int max_thresh = 20;
int current_radius = 5;
Mat gray_src, LBP_image, ELBP_image;
void Demo_ELBP(int, void*);
int main(int argc, char** argv) {
    Mat src, dst;
    src = imread("D:/vcprojects/images/cat.jpg");
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    const char* output_tt = "LBP Result";
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    namedWindow(output_tt, CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    // convert to gray

    cvtColor(src, gray_src, COLOR_BGR2GRAY);
    int width = gray_src.cols;
    int height = gray_src.rows;

    // default LBP image
    LBP_image = Mat::zeros(src.rows - 2, src.cols - 2, CV_8UC1);
    for (int row = 1; row < height-1; row++) {
        for (int col = 1; col < width-1; col++) {
            uchar center = gray_src.at<uchar>(row, col);
            uchar code = 0;
            code |= (gray_src.at<uchar>(row - 1, col - 1) > center) << 7;
            code |= (gray_src.at<uchar>(row - 1, col) > center) << 6;
            code |= (gray_src.at<uchar>(row - 1, col + 1) > center) << 5;
            code |= (gray_src.at<uchar>(row, col + 1) > center) << 4;
            code |= (gray_src.at<uchar>(row+ 1, col + 1) > center) << 3;
            code |= (gray_src.at<uchar>(row + 1, col) > center) << 2;
            code |= (gray_src.at<uchar>(row + 1, col - 1) > center) << 1;
            code |= (gray_src.at<uchar>(row, col - 1) > center) << 0;
            LBP_image.at<uchar>(row- 1, col - 1) = code;
        }
    }

    imshow(output_tt, LBP_image);

    // extend LBP 
    namedWindow("ELBP_Result", CV_WINDOW_AUTOSIZE);
    createTrackbar("Radius:", "ELBP_Result", &current_radius, max_thresh, Demo_ELBP);
    Demo_ELBP(0, 0);

    waitKey(0);
    return 0;
}

void Demo_ELBP(int, void*) {
    int offset = current_radius * 2;
    ELBP_image = Mat::zeros(gray_src.rows - offset, gray_src.cols - offset, CV_8UC1);
    int height = gray_src.rows;
    int width = gray_src.cols;

    int neighbors = 8;
    for (int n = 0; n<neighbors; n++) {
        // sample points
        float x = static_cast<float>(current_radius) * cos(2.0*CV_PI*n / static_cast<float>(neighbors));
        float y = static_cast<float>(current_radius) * -sin(2.0*CV_PI*n / static_cast<float>(neighbors));
        // relative indices
        int fx = static_cast<int>(floor(x));
        int fy = static_cast<int>(floor(y));
        int cx = static_cast<int>(ceil(x));
        int cy = static_cast<int>(ceil(y));
        // fractional part
        float ty = y - fy;
        float tx = x - fx;
        // set interpolation weights
        float w1 = (1 - tx) * (1 - ty);
        float w2 = tx  * (1 - ty);
        float w3 = (1 - tx) *      ty;
        float w4 = tx  *      ty;
        // iterate through your data
        for (int i = current_radius; i < gray_src.rows - current_radius; i++) {
            for (int j = current_radius; j < gray_src.cols - current_radius; j++) {
                float t = w1*gray_src.at<uchar>(i + fy, j + fx) + w2*gray_src.at<uchar>(i + fy, j + cx) + w3*gray_src.at<uchar>(i + cy, j + fx) + w4*gray_src.at<uchar>(i + cy, j + cx);
                // we are dealing with floating point precision, so add some little tolerance
                ELBP_image.at<uchar>(i - current_radius, j - current_radius) += ((t > gray_src.at<uchar>(i, j)) && (abs(t - gray_src.at<uchar>(i, j)) > std::numeric_limits<float>::epsilon())) << n;
            }
        }
    }

    imshow("ELBP_Result", ELBP_image);
}

請繼續關注本博客,同時關注微信公衆號【OpenCV學堂】定期推送更多幹貨,圖像處理算法!

發佈了269 篇原創文章 · 獲贊 1318 · 訪問量 365萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章