数字图像处理之LBP特征[Java]
文章目录
目录
文章目录
前言
一、LBP特征是什么?
二、大致思路
前言
主要是为了记录并分享自己在学习过程中的问题及相应的解决方案,并且可能存在一些错误的观点或理解等信息,请大家多多包涵。该代码仅限于从RGB角度进行处理,并未引入任何第三方库如OpenCV等技术手段
主要是为了记录并分享自己在学习过程中的问题及相应的解决方案,并且可能存在一些错误的观点或理解等信息,请大家多多包涵。该代码仅限于从RGB角度进行处理,并未引入任何第三方库如OpenCV等技术手段
一、LBP特征是什么?
LBP特征(Local Binary Pattern)是一种用于描述图像局部特征的重要运算符。该方法由T.Ojala, M.Pietikäinen, 和 D. Harwood于1994年提出,在纹理分析领域具有开创性意义。该算法因其对单调灰度变化具有不变性且计算效率高的特点,在计算机视觉等领域的广泛应用包括人脸识别、目标检测以及基于LBP特征的目标检测分类器训练等任务。
详尽信息可访问这篇博客获取

1条消息 详尽透彻阐述LBP特征原理与应用_literacy_wang的博客-博客
摘要
关键词
正文
参考文献
二、大致思路
我们将LBP分为两种方法,下面介绍第一种
1.原始的LBP算法:
LBP算子定义在一个3×3像素的邻域内,并以该区域中心像素为基准值。该区域中相邻8个像素的灰度值与中心像素值进行对比:若周围像素灰度高于中心,则标记为1;反之则标记为0。经过比较运算后可获得8位二进制码序列;将此序列按顺序组合起来形成一个完整的二进制数值。这个数值即为中心像素点对应的LBP特征码。由于每一位特征码仅有两种取值(0或1),因此总的特征码种类数目共计2^8=256种可能性(如图所示)。

基于获取的八个点按照顺时针顺序进行处理后会转换为一个十进制数值,则作为中心像素的像素值。如上图所示计算得出:0×2⁷ + 1×2⁶ + 1×2⁵ + 1×2⁴ + 1×2³ + 1×2² + 0×2¹ + 0×2⁰ = 124。
起始点位置的不同得到的结果也不同,但刚性需求是按顺时针处理。
代码如下:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.util.LinkedList;
import java.util.Deque;
public class LBP
{
BufferedImage bufferedImage;
BufferedImage buf;
int height;
int width;
Deque<Integer> queue = new LinkedList<>();
public LBP(String path)
{
try
{
bufferedImage = ImageIO.read(new File(path));
}
catch (IOException e)
{
e.printStackTrace();
}
height = bufferedImage.getHeight();
width = bufferedImage.getWidth();
buf = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
public void getTexture()
{
getWhite();
getCenterPixel();
}
public void getCenterPixel()
{
double pixel = 0;
for(int y = 1;y < height-1;y++)
{
for(int x = 1;x < width-1;x++)
{
pixel = getGray(x,y);
getAround(x,y,pixel);
}
}
}
public void getAround(int x,int y,double pixel)//从左上开始
{
Compare(x-1,y,pixel);
Compare(x-1,y-1,pixel);
Compare(x,y-1,pixel);
Compare(x+1,y-1,pixel);
Compare(x+1,y,pixel);
Compare(x+1,y+1,pixel);
Compare(x,y+1,pixel);
Compare(x-1,y+1,pixel);
Calculate(x,y);
}
public void Compare(int x,int y,double pixel)
{
double value = getGray(x,y);
if(value > pixel)
queue.offer(1);
else
queue.offer(0);
}
public void Calculate(int x,int y)
{
int pixelval = 0;
for(int i = queue.size()-1;i >= 0;i--)
{
pixelval += queue.poll()*Math.pow(2,i);
}
Color color = new Color(pixelval,pixelval,pixelval);
buf.setRGB(x,y,color.getRGB());
}
public double getGray(int x,int y)
{
Color color = new Color(bufferedImage.getRGB(x,y));
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
return 0.3*r + 0.59*g + 0.11*b;
}
public void getWhite()
{
Color white = new Color(255,255,255);
for(int y = 0;y < height;y++)
{
for(int x = 0;x < width;x++)
{
buf.setRGB(x,y,white.getRGB());
}
}
}
public void outPicture(String path)
{
try
{
ImageIO.write(buf,"png",new File(path));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
LBP lbp1 = new LBP("图片/1.png");//图片是相对地址,如果想要直接用需要更换下图片路径即可
lbp1.getTexture();
lbp1.outPicture("图片/zuoshang1_1wenli.png");
}
}
在此插入几张效果图




以上是不同起始点得出的不同效果。
2.Circular LBP or Extended LBP:
基本的LBP算法的主要缺陷在于其仅能处理固定半径范围内的小区域这一单一场景,在面对不同尺寸及频率下的纹理特征提取时显现出明显的局限性。值得注意的是尽管LBP算法具备良好的灰度不变特性即在光照变化下仍能保持描述信息的一致性但在实现细节上存在一定的约束条件具体表现为该方法缺乏对于旋转特性的适应能力
为了更好地适应不同尺度下的纹理特征分析需求,Ojala团队对经典的LBP算子进行了优化,将传统的3×3领域扩展为可变大小的领域,并采用圆形领域取代了传统的正方形领域.这种改进使得改进后的LBP算法可在半径R内的圆周上布置任意数量的采样点,从而导出了具有P个采样点位于半径R圆周上的新型LBP算法.
x_p = x_c+Rcos(2πp/P)
y_p = y_c−Rsin(2πp/P)
中心点位于(x_c,y_c)位置附近进行研究;其中每个采样点的位置设在(x_p,y_p)处;邻域半径由R值确定;每个第p个采样点用p来表示;总共有P个采样点被选取
详细内容可以去上面推荐的博客上看,在此就不多赘述了,直接上代码:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.util.LinkedList;
import java.util.Deque;
public class LBP
{
BufferedImage bufferedImage;
BufferedImage buf;
int height;
int width;
Deque<Integer> queue = new LinkedList<>();
public LBP(String path)
{
try
{
bufferedImage = ImageIO.read(new File(path));
}
catch (IOException e)
{
e.printStackTrace();
}
height = bufferedImage.getHeight();
width = bufferedImage.getWidth();
buf = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
public void getTexture()
{
getWhite();
getCenterPixel();
}
public void getCenterPixel()
{
double pixel = 0;
for(int y = 3;y < height-3;y++)//从2开始是因为半径为2
{
for(int x = 3;x < width-3;x++)
{
pixel = getGray(x,y);
getAround(x,y,pixel);
}
}
}
public void getAround(int x,int y,double pixel)//半径为3,采样点为8,半径越小,纹理越精细,采样点越多,亮度越大
{
for(int i = 1;i < 9;i++)
Compare(x+3*Math.cos(2*3.14*i/9),y-3*Math.sin(2*3.14*i/9),pixel);
Calculate(x,y);
}
public void Compare(double x,double y,double pixel)
{
double value;
int a = (int)x;
int b = (int)y;
if(x%a == 0 && y%b == 0)//判断x,y是否为整数,若为0则为整数,反之则不是
value = getGray(a,b);
else
value = getLinearInterpolation(x,y);
if(value >= pixel)
queue.offer(1);
else
queue.offer(0);
}
public double getLinearInterpolation(double x,double y)//对x,y进行双线性插值
{
int x1 = (int)x;
int x2 = x1+1;
int y1 = (int)y;
int y2 = y1+1;
double v11 = getGray(x1,y1);
double v21 = getGray(x2,y1);
double v12 = getGray(x1,y2);
double v22 = getGray(x2,y2);
double factor1 = (x2-x)*v11/(x2-x1)+(x-x1)*v21/(x2-x1);//factor1,factor2对x进行线性插值
double factor2 = (x2-x)*v12/(x2-x1)+(x-x1)*v22/(x2-x1);
return (y2-y)*factor1/(y2-y1)+(y-y1)*factor2/(y2-y1);//对y进行线性插值得值并返回
}
public void Calculate(int x,int y)
{
int pixelval = 0;
for(int i = queue.size()-1;i >= 0;i--)
{
pixelval += queue.poll()*Math.pow(2,i);
}
Color color = new Color(pixelval,pixelval,pixelval);
buf.setRGB(x,y,color.getRGB());
}
public void getWhite()
{
Color white = new Color(255,255,255);
for(int y = 0;y < height;y++)
{
for(int x = 0;x < width;x++)
{
buf.setRGB(x,y,white.getRGB());
}
}
}
public double getGray(int x,int y)
{
Color color = new Color(bufferedImage.getRGB(x,y));
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
return 0.3*r + 0.59*g + 0.11*b;
}
public void outPicture(String path)
{
try
{
ImageIO.write(buf,"png",new File(path));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
LBP lbp1 = new LBP("图片/8.png");
lbp1.getTexture();
lbp1.outPicture("图片/8_1wenli.png");
}
}
同样的,上效果图:


如果有可以优化的点欢迎大家帮忙指出!看到这里了点个赞吧!感谢!
