图像处理之局部二值特征

简介: 图像处理之局部二值特征一:局部二值模式(LBP)介绍 局部二值模式(Local Binary Pattern)主要用来实现2D图像纹理分析。其基本思想是用每个像素跟它周围的像素相比较得到局部图像结构,假设中心像素值大于相邻像素值则则相邻像素点赋值为1,否则赋值为0,最终对每个像素点都会得到一个二进制八位的表示,比如11100111。

图像处理之局部二值特征

一:局部二值模式(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学堂】定期推送更多干货,图像处理算法!

目录
相关文章
|
3月前
|
算法 计算机视觉
图像处理之积分图应用四(基于局部均值的图像二值化算法)
图像处理之积分图应用四(基于局部均值的图像二值化算法)
514 0
|
2月前
|
机器学习/深度学习 编解码 PyTorch
【YOLOv8改进】HWD: Haar小波降采样,用于语义分割的降采样模块,减少特征图的空间分辨率
YOLOv8专栏探讨了卷积网络的改进,特别是提出了一种名为HWD的基于Haar小波的下采样模块,用于语义分割,旨在保留更多空间信息。HWD结合了无损编码和特征表示学习,提高了模型性能并减少了信息不确定性。新度量标准FEI量化了下采样的信息保留能力。论文和代码可在提供的链接中找到。核心代码展示了如何在PyTorch中实现HWD模块。
|
4月前
|
机器学习/深度学习 存储 数据可视化
MambaOut:状态空间模型并不适合图像的分类任务
该论文研究了Mamba架构(含状态空间模型SSM)在视觉任务(图像分类、目标检测、语义分割)中的必要性。实验表明,Mamba在这些任务中效果不如传统卷积和注意力模型。论文提出,SSM更适合长序列和自回归任务,而非视觉任务。MambaOut(不带SSM的门控CNN块)在图像分类上优于视觉Mamba,但在检测和分割任务中略逊一筹,暗示SSM在这类任务中可能仍有价值。研究还探讨了Mamba在处理长序列任务时的效率和局部信息整合能力。尽管整体表现一般,但论文为优化不同视觉任务的模型架构提供了新视角。
75 2
|
2月前
|
并行计算 算法 Java
尺度函数在图像处理中的应用与优化
尺度函数在图像处理中的应用与优化
|
3月前
|
计算机视觉
图像处理之局部二值特征
图像处理之局部二值特征
36 0
|
4月前
|
机器学习/深度学习 编解码 测试技术
图像超分:真实感图像超分辨率的局部判别学习方法
图像超分:真实感图像超分辨率的局部判别学习方法
71 0
|
4月前
用图直观上理解梯度算子(一阶)与拉普拉斯算子(二阶)的区别,线检测与边缘检测的区别
用图直观上理解梯度算子(一阶)与拉普拉斯算子(二阶)的区别,线检测与边缘检测的区别
121 1
|
4月前
|
机器学习/深度学习 文字识别 算法
[Halcon&图像] 基于多层神经网络MLP分类器的思想提取颜色区域
[Halcon&图像] 基于多层神经网络MLP分类器的思想提取颜色区域
121 0
|
12月前
|
机器学习/深度学习 传感器 算法
【图像分割】图像检测(分割、特征提取)、各种特征(面积等)的测量和过滤(Matlab代码实现)
【图像分割】图像检测(分割、特征提取)、各种特征(面积等)的测量和过滤(Matlab代码实现)
|
vr&ar
用于非线性时间序列预测的稀疏局部线性和邻域嵌入(Matlab代码实现)
用于非线性时间序列预测的稀疏局部线性和邻域嵌入(Matlab代码实现)
113 0
用于非线性时间序列预测的稀疏局部线性和邻域嵌入(Matlab代码实现)