4.1 理解层叠分类器的检测原理

4.1 理解级联分类器的检测原理

级联是一系列测试或阶段,用于区分是不是某一个对象,比如脸和非脸。对于正向分类,图像的某个部分必须通过级联的所有阶段。反之,如果图像在任何一个阶段失败了,分类器就会立即判定他为非。

图像的部分或窗口是在给定位置和给定放大级别上的像素样本。级联分类器获取图像在不同位置和不同放大级别的窗口,并为每个窗口运行级联的各个阶段。通常,正向检测出现在多个重叠窗口中。这些重叠的正向检测被称为“领域”,它们意味着更有可能出现真正的匹配。例如,如果我们稍微移动或调整框架的大小,一个真实的脸看起来仍然像一个脸。

现在,您可能想知道我们是如何设计级联的各个阶段的。答案是,我们不直接设计它们。相反,我们让机器学习元算法基于一组训练图像和一组特征来设计阶段。通常,元算法是AdaBoost(自适应增强)的变体,AdaBoost是一种带有特定指数误差函数的线性回归公式。训练图像包括正样本和负样本,我们必须提供正样本中对象坐标的元数据。这些特性是分类器可能会(也可能不会)在每个邻域中找到的本地模式模板。训练算法选取了正样本的典型特征和负样本的非典型特征,并根据这些特征设计了训练阶段。

4.1.1 Haar-like特征

Haar-like特征是人脸检测和一般目标检测中最常用的特征之一。对于每个窗口,Haar级联分类器从其他窗口中抽取一些灰度像素值,用来衡量窗口与以下暗区与亮区相遇的特征的相似性:
在这里插入图片描述
因此,Haar级联的阶段表示水平或对角线边缘、细线或点,它们代表一个对象(相对于非对象)。该算法的一些变体删除了一些特征(如对角线特征)或添加了一些特征(如四个矩形相交的角),但基本思想是相同的。

Haar-like的特征在旋转或翻转方面不够健壮。例如,如果Haar级联被训练来检测直立的面孔,它将不会检测倒置的面孔。同样的,如果Haar级联训练的是左眼,那么右眼就不是理想的,因为右眼是左眼的镜像。因此,左眼和右眼最好有单独的级联。我们将使用OpenCV附带的4个训练有素的Haar级联,这些级联将检测一张直立的人脸、一张直立的猫脸、一个人的左眼和一个人的右眼。

4.1.2 局部二值模式特征

局部二值模式(LBP)特征是另一种流行的特征。它们也被称为局部二值模式直方图(LBPH)特征。顾名思义,LBPH特征是亮度值的直方图或计数。对于窗口中的每个像素,分类器观察在一定半径内的每个相邻像素是更亮了还是更暗了。直方图包含了每个相邻位置中较暗像素的计数。例如,假设一个窗口包含以下两个1像素半径的邻域:
在这里插入图片描述
计算这两个邻域(还没有计算窗口中的其他邻域),直方图可以如下图所示:
在这里插入图片描述
让我们回顾一下我们是如何得出这些数字的。第一个邻域有黑色的角(相对于中心),因此我们向直方图表的每个角落的单元格加1。第二个邻域有一个黑色的顶行(相对于中心),因此我们向直方图表顶行的每个单元格添加另一个1。

LBP级联的阶段表示代表对象(相对于非对象)的渐变或转换。

和Haar级联一样,LBP级联在旋转或翻转方面也不健壮。OpenCV带有预先训练的LBP级联,适用于直立的人脸和直立的猫脸。可选地,我们可以使用这些来代替Haar级联。

与Haar级联相比,LBP级联的检测速度更快,但精度较低。对于低端设备,或者在需要高帧速率的情况下,LBP级联可能是一个不错的选择。然而,现在的iOS设备非常适合Haar级联用于实时视频。

[有关OpenCV实现级联分类器的信息,请参见官方文档,位于:http://docs.opencv.org/3.1.0/d5/d54/group__objdetect.html。具体来说,我们将使用cv::CascadeClassifier类.]

###返回到第四章目录###
###返回到书籍目录###

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于使用Netty 4.1和Protobuf的WebSocket编码器,你可以按照以下步骤进行设置: 1. 首先,确保你已经添加了Netty和Protobuf的依赖到你的项目中。 2. 创建一个WebSocket编码器类,该类将负责将Protobuf消息编码为WebSocket帧。下面是一个示例代码: ```java import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; public class ProtobufWebSocketEncoder extends MessageToByteEncoder<MessageLite> { @Override protected void encode(ChannelHandlerContext ctx, MessageLite msg, ByteBuf out) throws Exception { byte[] bytes = msg.toByteArray(); out.writeBytes(bytes); } } ``` 3. 在你的Netty初始化代码中,添加WebSocket编码器到你的ChannelPipeline中。下面是一个示例代码: ```java import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast(new HttpServerCodec()) .addLast(new HttpObjectAggregator(65536)) .addLast(new WebSocketServerProtocolHandler("/websocket")) .addLast(new ProtobufWebSocketEncoder()) .addLast(new YourCustomWebSocketHandler()); } } ``` 在上面的代码中,`YourCustomWebSocketHandler`是你自己实现的处理WebSocket消息的处理器。 4. 最后,在你的Netty服务器启动代码中,绑定正确的端口并启动服务器。下面是一个示例代码: ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; public class WebSocketServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new WebSocketServerInitializer()); ChannelFuture f = b.bind(8080).sync(); f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } ``` 确保将端口号8080更改为你实际使用的端口号。 以上就是使用Netty 4.1和Protobuf的WebSocket编码器的基本设置。请根据你的实际需求进行适当的修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值