-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
128 lines (60 loc) · 188 KB
/
search.xml
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>‘JetsonNano控制舵机’</title>
<link href="/2022/11/23/%E2%80%98JetsonNano%E6%8E%A7%E5%88%B6%E8%88%B5%E6%9C%BA%E2%80%99/"/>
<url>/2022/11/23/%E2%80%98JetsonNano%E6%8E%A7%E5%88%B6%E8%88%B5%E6%9C%BA%E2%80%99/</url>
<content type="html"><![CDATA[<h3 id="材料:"><a href="#材料:" class="headerlink" title="材料:"></a>材料:</h3><ol><li>PCA9685舵机驱动板</li><li>MG996R舵机</li></ol><h3 id="配置环境"><a href="#配置环境" class="headerlink" title="配置环境"></a>配置环境</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pip3 install adafruit-circuitpython-servokit</span><br><span class="line">sudo i2cdetect -y -r 1</span><br></pre></td></tr></table></figure><p>安装adafruit-circuitpython-servokit库</p><p>以及监测目前Jetson 的GPIO上的引脚已连接的接口</p><h3 id="简单实现"><a href="#简单实现" class="headerlink" title="简单实现"></a>简单实现</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> time <span class="comment">#引入time库</span></span><br><span class="line"><span class="keyword">from</span> adafruit_servokit <span class="keyword">import</span> ServoKit <span class="comment">#引入PCA9685库</span></span><br><span class="line"></span><br><span class="line">kit = ServoKit(channels=<span class="number">16</span>) <span class="comment">#明确PCA9685的舵机控制数</span></span><br><span class="line">kit.servo[<span class="number">0</span>].angle = <span class="number">75</span> <span class="comment">#channel0上的舵机旋转。</span></span><br><span class="line">time.sleep(<span class="number">1</span>) <span class="comment">#休眠一秒</span></span><br><span class="line">kit.servo[<span class="number">0</span>].angle = <span class="number">150</span> <span class="comment">#channel0上的舵机旋转。</span></span><br></pre></td></tr></table></figure><p>实现效果如下:</p><p><img src="/../img/%E2%80%98JetsonNano%E6%8E%A7%E5%88%B6%E8%88%B5%E6%9C%BA%E2%80%99/image-20221123114424700.png" alt="image-20221123114424700"></p><p><video src="../video/1.mp4"></video></p>]]></content>
<tags>
<tag> Jetson </tag>
</tags>
</entry>
<entry>
<title>UAV信号控制问题</title>
<link href="/2022/11/22/UAV%E5%9B%BE%E4%BC%A0%E4%BB%A5%E5%8F%8A%E4%BF%A1%E5%8F%B7%E6%8E%A7%E5%88%B6/"/>
<url>/2022/11/22/UAV%E5%9B%BE%E4%BC%A0%E4%BB%A5%E5%8F%8A%E4%BF%A1%E5%8F%B7%E6%8E%A7%E5%88%B6/</url>
<content type="html"><![CDATA[<p>摘要:基于简单的无人机端,地面站端,无人机调度端进行3端数据交互的过程中产生了不可不考虑的时间延迟,导致了整个系统精确降落过程无法实现</p><h3 id="原系统困难点"><a href="#原系统困难点" class="headerlink" title="原系统困难点"></a>原系统困难点</h3><h4 id="核心部分:精确降落无法实现"><a href="#核心部分:精确降落无法实现" class="headerlink" title="核心部分:精确降落无法实现"></a>核心部分:精确降落无法实现</h4><ol><li>子原因:调度控制3端交互时间延迟——http协议TCP三次握手</li><li>子原因:地面站端的无人机检测识别仍不能实现实时检测</li><li>子原因:无人机上的摄像头返回UAV调度端数据量较大</li></ol><blockquote><p>这些问题目前有了改进的大概思路,但需要推翻原有技术架构,更换核心框架,成本巨大,推荐重构系统</p></blockquote><h3 id="原系统通信设计"><a href="#原系统通信设计" class="headerlink" title="原系统通信设计"></a>原系统通信设计</h3><p>局域网+TCP+数传–H264–2bit转换</p><p>使用平台:</p><p>树莓派+pixhawk飞控+树莓派上位机连接校园网(无人机端)+笔记本连接校园网(UAV调度端)+地面站端(Jetson Nano+摄像头)</p><h4 id="主要的通信实现:"><a href="#主要的通信实现:" class="headerlink" title="主要的通信实现:"></a>主要的通信实现:</h4><p>SpringBoot 通过 Feign 调用Django 接口</p><p>处理流程:</p><ol><li>SpringBoot调用Feign服务</li><li>Feign客户端创建请求报文</li><li>Django框架接收到请求后解析请求</li><li>Django框架接收到请求后进行处理(如封装js、数据库交互、业务处理等操作)。</li><li>处理结束后把HTTP的响应对象通过接口返回给Feign。</li><li>SpringBoot把接收到的HTTP响应对象报文最后返回给浏览器或者做出调整决策。</li></ol><h3 id="失败分析"><a href="#失败分析" class="headerlink" title="失败分析"></a>失败分析</h3><ol><li><p>局域网损失</p><p>ping值80-300ms左右</p></li><li><p>TCP损失</p><p>3次握手本身导致的损失</p></li><li><p>调度端数传网页显示</p><p>虽然兼容性更高,但是编码时间损失较大</p></li><li><p>3端TCP调度</p><p>3端TCP6次握手,框架时间损失较大</p></li><li><p>视频压缩的帧间压缩导致的损失</p><p>到指定一段时间的视频流不可避免的需要进行编码压缩,不然视频流过大,压缩需要一段时间导致并发时间无法实现良好的图传</p></li></ol><h3 id="延迟影响性"><a href="#延迟影响性" class="headerlink" title="延迟影响性"></a>延迟影响性</h3><ol><li><p>codec编码</p><ol><li>模拟VTL</li></ol></li><li><p>数传MP</p></li><li><p>format格式</p><p>H264 H265</p><ul><li>H265相对来说压缩率更高一点(60%左右)</li><li>实现上来说h264更好h265需要看硬件是否呢支持</li></ul></li><li><p>Streaming protocols</p><ul><li><p>TCP</p><p>三次握手</p><p>可靠性高</p></li><li><p>UDP</p><p>无三次握手</p><p>少量数据,传输快</p><p><strong>丢包率高</strong></p></li><li><blockquote><p>H264:RTMP/RTSP/Http-based</p><p>H265:RTSP /RTP/Http-based</p></blockquote></li></ul></li></ol><h3 id="关于4g模块"><a href="#关于4g模块" class="headerlink" title="关于4g模块"></a>关于4g模块</h3><blockquote><p>比较常见的可以使用USB随身WIFI,但是USB接口散热有限,容易掉速,进行长时间图传不太现实</p><p>为解决散热问题可以采用移远EC40模块,可以通过4g模块联网操作,散热较强</p></blockquote><ol><li>需要看实机带宽(一般在20kbps)</li><li>仍需要压缩(例如1080p 60FPS RGB的视频1920x1080x3x60/1024/1024)</li></ol><h3 id="关于SDR"><a href="#关于SDR" class="headerlink" title="关于SDR"></a>关于SDR</h3><blockquote><p><em>SDR</em> (Software Defination Radio), “软件定义的无线电”的简称。 软件定义的无线电 (<em>SDR</em>) 是无线电广播通信技术,它基于软件定义的无线通信协议而非通过硬连线实现</p></blockquote><p>使用sdr搭建自己的数字传输协议</p><ol><li>降低频率实现距离的增加</li><li>使用单图片传输</li><li>图片差分压缩</li></ol><h3 id="重构方案"><a href="#重构方案" class="headerlink" title="重构方案"></a>重构方案</h3><p>1.RTP协议+H.265+4g模块</p><p>2.使用SDR</p>]]></content>
</entry>
<entry>
<title>zxing</title>
<link href="/2022/11/10/zxing/"/>
<url>/2022/11/10/zxing/</url>
<content type="html"><![CDATA[<h2 id="zxing介绍"><a href="#zxing介绍" class="headerlink" title="zxing介绍"></a>zxing介绍</h2><p>zxing项目是谷歌推出的用来识别多种格式条形码的开源项目,项目地址为<a href="https://github.com/zxing/zxing">https://github.com/zxing/zxing</a>,zxing有多个人在维护,覆盖主流编程语言,也是目前还在维护的较受欢迎的二维码扫描开源项目之一。</p><p>zxing的项目很庞大,主要的核心代码在<code>core</code>文件夹里面,也可以单独下载由这个文件夹打包而成的<code>jar</code>包,具体地址在<a href="http://mvnrepository.com/artifact/com.google.zxing/core">http://mvnrepository.com/artifact/com.google.zxing/core</a>,直接下载jar包也省去了通过<code>maven</code>编译的麻烦,如果喜欢折腾的,可以从<a href="https://github.com/zxing/zxing/wiki/Getting-Started-Developing">https://github.com/zxing/zxing/wiki/Getting-Started-Developing</a>获取帮助文档。 </p><h2 id="zxing基本使用"><a href="#zxing基本使用" class="headerlink" title="zxing基本使用"></a>zxing基本使用</h2><p>官方提供了zxing在Android机子上的使用例子,<a href="https://github.com/zxing/zxing/tree/master/android">https://github.com/zxing/zxing/tree/master/android</a>,作为官方的例子,zxing-android考虑了各种各样的情况,包括多种解析格式、解析得到的结果分类、长时间无活动自动销毁机制等。有时候我们需要根据自己的情况定制使用需求,因此会精简官方给的例子。在项目中,我们仅仅用来实现扫描二维码和识别图片二维码两个功能。为了实现高精度的二维码识别,在zxing原有项目的基础上,本文做了大量改进,使得二维码识别的效率有所提升。先来看看工程的项目结构。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="0" class="" name="code"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span><span class="line" style="height:20px">12</span><span class="line" style="height:20px">13</span><span class="line" style="height:20px">14</span><span class="line" style="height:20px">15</span><span class="line" style="height:20px">16</span><span class="line" style="height:20px">17</span><span class="line" style="height:20px">18</span><span class="line" style="height:20px">19</span><span class="line" style="height:20px">20</span><span class="line" style="height:20px">21</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="1" class="" name="code"><span class="line" style="height:20px">.</span><span class="line" style="height:20px">├── QrCodeActivity<span class="class">.java</span></span><span class="line" style="height:20px">├── camera</span><span class="line" style="height:20px">│ ├── AutoFocusCallback<span class="class">.java</span></span><span class="line" style="height:20px">│ ├── CameraConfigurationManager<span class="class">.java</span></span><span class="line" style="height:20px">│ ├── CameraManager<span class="class">.java</span></span><span class="line" style="height:20px">│ └── PreviewCallback<span class="class">.java</span></span><span class="line" style="height:20px">├── decode</span><span class="line" style="height:20px">│ ├── CaptureActivityHandler<span class="class">.java</span></span><span class="line" style="height:20px">│ ├── DecodeHandler<span class="class">.java</span></span><span class="line" style="height:20px">│ ├── DecodeImageCallback<span class="class">.java</span></span><span class="line" style="height:20px">│ ├── DecodeImageThread<span class="class">.java</span></span><span class="line" style="height:20px">│ ├── DecodeManager<span class="class">.java</span></span><span class="line" style="height:20px">│ ├── DecodeThread<span class="class">.java</span></span><span class="line" style="height:20px">│ ├── FinishListener<span class="class">.java</span></span><span class="line" style="height:20px">│ └── InactivityTimer<span class="class">.java</span></span><span class="line" style="height:20px">├── utils</span><span class="line" style="height:20px">│ ├── QrUtils<span class="class">.java</span></span><span class="line" style="height:20px">│ └── ScreenUtils<span class="class">.java</span></span><span class="line" style="height:20px">└── view</span><span class="line" style="height:20px"> └── QrCodeFinderView.java</span></pre></td></tr></tbody></table><p>源码比较简单,这里不做过多地讲解,大部分方法都有注释。主要分为几大块,</p><ul><li>camera</li></ul><p>主要实现相机的配置和管理,相机自动聚焦功能,以及相机成像回调(通过<code>byte[]</code>数组返回实际的数据)。</p><ul><li>decode</li></ul><p>图片解析相关类。通过相机扫描二维码和解析图片使用两套逻辑。前者对实时性要求比较高,后者对解析结果要求较高,因此采用不同的配置。相机扫描主要在<code>DecodeHandler</code>里通过串行的方式解析,图片识别主要通过线程<code>DecodeImageThread</code>异步调用返回回调的结果。<code>FinishListener</code>和<code>InactivityTimer</code>用来控制长时间无活动时自动销毁创建的Activity,避免耗电。</p><h2 id="扫描精度问题"><a href="#扫描精度问题" class="headerlink" title="扫描精度问题"></a>扫描精度问题</h2><p>使用过zxing自带的二维码扫描程序来识别二维码的童鞋应该知道,zxing二维码的扫描程序很慢,而且有可能扫不出来。zxing在配置相机参数和二维码扫描程序参数的时候,配置都比较保守,兼顾了低端手机,并且兼顾了多种条形码的识别。如果说仅仅是拿zxing项目来扫描和识别二维码的话,完全可以对项目中的一些配置做精简,并针对二维码的识别做优化。</p><h3 id="PlanarYUVLuminanceSource"><a href="#PlanarYUVLuminanceSource" class="headerlink" title="PlanarYUVLuminanceSource"></a>PlanarYUVLuminanceSource</h3><p>官方的解码程序主要是下边这段代码:</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="2" class="" name="code"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span><span class="line" style="height:20px">12</span><span class="line" style="height:20px">13</span><span class="line" style="height:20px">14</span><span class="line" style="height:20px">15</span><span class="line" style="height:20px">16</span><span class="line" style="height:20px">17</span><span class="line" style="height:20px">18</span><span class="line" style="height:20px">19</span><span class="line" style="height:20px">20</span><span class="line" style="height:20px">21</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="3" class="" name="code"><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">void</span> decode(<span class="built_in" style="color:rgb(222,147,95)">byte</span>[] data, <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">height</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">long</span> start = System.currentTimeMillis();</span><span class="line" style="height:20px"> Result rawResult = <span class="keyword" style="color:rgb(178,148,187)">null</span>;</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 构造基于平面的YUV亮度源,即包含二维码区域的数据源</span></span><span class="line" style="height:20px"> PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="variable" style="color:rgb(204,102,102)">height</span>);</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (source != <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 构造二值图像比特流,使用HybridBinarizer算法解析数据源</span></span><span class="line" style="height:20px"> BinaryBitmap bitmap = <span class="keyword" style="color:rgb(178,148,187)">new</span> BinaryBitmap(<span class="keyword" style="color:rgb(178,148,187)">new</span> HybridBinarizer(source));</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">try</span> {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 采用MultiFormatReader解析图像,可以解析多种数据格式</span></span><span class="line" style="height:20px"> rawResult = multiFormatReader.decodeWithState(bitmap);</span><span class="line" style="height:20px"> } <span class="keyword" style="color:rgb(178,148,187)">catch</span> (ReaderException re) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// continue</span></span><span class="line" style="height:20px"> } <span class="keyword" style="color:rgb(178,148,187)">finally</span> {<!-- --></span><span class="line" style="height:20px"> multiFormatReader.reset();</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px">···</span><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">// Hanlder处理解析失败或成功的结果</span></span><span class="line" style="height:20px">···</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><p>再来看看YUV亮度源是怎么构造的,在<code>CameraManager</code>里,首先获取预览图像的聚焦框矩形<code>getFramingRect()</code>,这个聚焦框的矩形大小是根据屏幕的宽高值来做计算的,官方定义了最小和最大的聚焦框大小,分别是<code>240*240</code>和<code>1200*675</code>,即最多的聚焦框大小为屏幕宽高的5/8。获取屏幕的聚焦框大小后,还需要做从屏幕分辨率到相机分辨率的转换才能得到预览聚焦框的大小,这个转换在<code>getFramingRectInPreview()</code>里完成。这样便完成了亮度源的构造。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="4" class="" name="code"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span><span class="line" style="height:20px">12</span><span class="line" style="height:20px">13</span><span class="line" style="height:20px">14</span><span class="line" style="height:20px">15</span><span class="line" style="height:20px">16</span><span class="line" style="height:20px">17</span><span class="line" style="height:20px">18</span><span class="line" style="height:20px">19</span><span class="line" style="height:20px">20</span><span class="line" style="height:20px">21</span><span class="line" style="height:20px">22</span><span class="line" style="height:20px">23</span><span class="line" style="height:20px">24</span><span class="line" style="height:20px">25</span><span class="line" style="height:20px">26</span><span class="line" style="height:20px">27</span><span class="line" style="height:20px">28</span><span class="line" style="height:20px">29</span><span class="line" style="height:20px">30</span><span class="line" style="height:20px">31</span><span class="line" style="height:20px">32</span><span class="line" style="height:20px">33</span><span class="line" style="height:20px">34</span><span class="line" style="height:20px">35</span><span class="line" style="height:20px">36</span><span class="line" style="height:20px">37</span><span class="line" style="height:20px">38</span><span class="line" style="height:20px">39</span><span class="line" style="height:20px">40</span><span class="line" style="height:20px">41</span><span class="line" style="height:20px">42</span><span class="line" style="height:20px">43</span><span class="line" style="height:20px">44</span><span class="line" style="height:20px">45</span><span class="line" style="height:20px">46</span><span class="line" style="height:20px">47</span><span class="line" style="height:20px">48</span><span class="line" style="height:20px">49</span><span class="line" style="height:20px">50</span><span class="line" style="height:20px">51</span><span class="line" style="height:20px">52</span><span class="line" style="height:20px">53</span><span class="line" style="height:20px">54</span><span class="line" style="height:20px">55</span><span class="line" style="height:20px">56</span><span class="line" style="height:20px">57</span><span class="line" style="height:20px">58</span><span class="line" style="height:20px">59</span><span class="line" style="height:20px">60</span><span class="line" style="height:20px">61</span><span class="line" style="height:20px">62</span><span class="line" style="height:20px">63</span><span class="line" style="height:20px">64</span><span class="line" style="height:20px">65</span><span class="line" style="height:20px">66</span><span class="line" style="height:20px">67</span><span class="line" style="height:20px">68</span><span class="line" style="height:20px">69</span><span class="line" style="height:20px">70</span><span class="line" style="height:20px">71</span><span class="line" style="height:20px">72</span><span class="line" style="height:20px">73</span><span class="line" style="height:20px">74</span><span class="line" style="height:20px">75</span><span class="line" style="height:20px">76</span><span class="line" style="height:20px">77</span><span class="line" style="height:20px">78</span><span class="line" style="height:20px">79</span><span class="line" style="height:20px">80</span><span class="line" style="height:20px">81</span><span class="line" style="height:20px">82</span><span class="line" style="height:20px">83</span><span class="line" style="height:20px">84</span><span class="line" style="height:20px">85</span><span class="line" style="height:20px">86</span><span class="line" style="height:20px">87</span><span class="line" style="height:20px">88</span><span class="line" style="height:20px">89</span><span class="line" style="height:20px">90</span><span class="line" style="height:20px">91</span><span class="line" style="height:20px">92</span><span class="line" style="height:20px">93</span><span class="line" style="height:20px">94</span><span class="line" style="height:20px">95</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="5" class="" name="code"><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> <span class="keyword" style="color:rgb(178,148,187)">final</span> <span class="built_in" style="color:rgb(222,147,95)">int</span> MIN_FRAME_WIDTH = <span class="number" style="color:rgb(181,189,104)">240</span>;</span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> <span class="keyword" style="color:rgb(178,148,187)">final</span> <span class="built_in" style="color:rgb(222,147,95)">int</span> MIN_FRAME_HEIGHT = <span class="number" style="color:rgb(181,189,104)">240</span>;</span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> <span class="keyword" style="color:rgb(178,148,187)">final</span> <span class="built_in" style="color:rgb(222,147,95)">int</span> MAX_FRAME_WIDTH = <span class="number" style="color:rgb(181,189,104)">1200</span>; <span class="comment" style="color:rgb(150,152,150)">// = 5/8 * 1920</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> <span class="keyword" style="color:rgb(178,148,187)">final</span> <span class="built_in" style="color:rgb(222,147,95)">int</span> MAX_FRAME_HEIGHT = <span class="number" style="color:rgb(181,189,104)">675</span>; <span class="comment" style="color:rgb(150,152,150)">// = 5/8 * 1080</span></span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * A factory method to build the appropriate LuminanceSource object based on the format of the preview buffers, as</span><span class="line" style="height:20px"> * described by Camera.Parameters.</span><span class="line" style="height:20px"> *</span><span class="line" style="height:20px"> * @param data A preview frame.</span><span class="line" style="height:20px"> * @param width The width of the image.</span><span class="line" style="height:20px"> * @param height The height of the image.</span><span class="line" style="height:20px"> * @return A PlanarYUVLuminanceSource instance.</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> PlanarYUVLuminanceSource buildLuminanceSource(<span class="built_in" style="color:rgb(222,147,95)">byte</span>[] data, <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">height</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 取得预览框内的矩形</span></span><span class="line" style="height:20px"> Rect <span class="built_in" style="color:rgb(222,147,95)">rect</span> = getFramingRectInPreview();</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (<span class="built_in" style="color:rgb(222,147,95)">rect</span> == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> <span class="keyword" style="color:rgb(178,148,187)">null</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Go ahead and assume it's YUV rather than die.</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> <span class="keyword" style="color:rgb(178,148,187)">new</span> PlanarYUVLuminanceSource(data, <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="variable" style="color:rgb(204,102,102)">height</span>, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.left, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.<span class="variable" style="color:rgb(204,102,102)">width</span>(), <span class="built_in" style="color:rgb(222,147,95)">rect</span>.<span class="variable" style="color:rgb(204,102,102)">height</span>(),</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">false</span>);</span><span class="line" style="height:20px">}</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * Like {@link #getFramingRect} but coordinates are in terms of the preview frame, not UI / screen.</span><span class="line" style="height:20px"> *</span><span class="line" style="height:20px"> * @return {@link Rect} expressing barcode scan area in terms of the preview size</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> <span class="keyword" style="color:rgb(178,148,187)">synchronized</span> Rect getFramingRectInPreview() {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (framingRectInPreview == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> Rect framingRect = getFramingRect();</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (framingRect == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> <span class="keyword" style="color:rgb(178,148,187)">null</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 获取相机分辨率和屏幕分辨率</span></span><span class="line" style="height:20px"> Rect <span class="built_in" style="color:rgb(222,147,95)">rect</span> = <span class="keyword" style="color:rgb(178,148,187)">new</span> Rect(framingRect);</span><span class="line" style="height:20px"> Point cameraResolution = configManager.getCameraResolution();</span><span class="line" style="height:20px"> Point screenResolution = configManager.getScreenResolution();</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (cameraResolution == <span class="keyword" style="color:rgb(178,148,187)">null</span> || screenResolution == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Called early, before init even finished</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> <span class="keyword" style="color:rgb(178,148,187)">null</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 根据相机分辨率和屏幕分辨率的比例对屏幕中央聚焦框进行调整</span></span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">rect</span>.left = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.left * cameraResolution.x / screenResolution.x;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">rect</span>.right = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.right * cameraResolution.x / screenResolution.x;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top * cameraResolution.y / screenResolution.y;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">rect</span>.bottom = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.bottom * cameraResolution.y / screenResolution.y;</span><span class="line" style="height:20px"> framingRectInPreview = <span class="built_in" style="color:rgb(222,147,95)">rect</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> framingRectInPreview;</span><span class="line" style="height:20px">}</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * Calculates the framing rect which the UI should draw to show the user where to place the barcode. This target</span><span class="line" style="height:20px"> * helps with alignment as well as forces the user to hold the device far enough away to ensure the image will be in</span><span class="line" style="height:20px"> * focus.</span><span class="line" style="height:20px"> *</span><span class="line" style="height:20px"> * @return The rectangle to draw on screen in window coordinates.</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> <span class="keyword" style="color:rgb(178,148,187)">synchronized</span> Rect getFramingRect() {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (framingRect == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (<span class="built_in" style="color:rgb(222,147,95)">camera</span> == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> <span class="keyword" style="color:rgb(178,148,187)">null</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 获取屏幕的尺寸像素</span></span><span class="line" style="height:20px"> Point screenResolution = configManager.getScreenResolution();</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (screenResolution == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Called early, before init even finished</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> <span class="keyword" style="color:rgb(178,148,187)">null</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 根据屏幕的宽高找到最合适的矩形框宽高值</span></span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">width</span> = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">height</span> = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 取屏幕中间的,宽为width,高为height的矩形框</span></span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> leftOffset = (screenResolution.x - <span class="variable" style="color:rgb(204,102,102)">width</span>) / <span class="number" style="color:rgb(181,189,104)">2</span>;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> topOffset = (screenResolution.y - <span class="variable" style="color:rgb(204,102,102)">height</span>) / <span class="number" style="color:rgb(181,189,104)">2</span>;</span><span class="line" style="height:20px"> framingRect = <span class="keyword" style="color:rgb(178,148,187)">new</span> Rect(leftOffset, topOffset, leftOffset + <span class="variable" style="color:rgb(204,102,102)">width</span>, topOffset + <span class="variable" style="color:rgb(204,102,102)">height</span>);</span><span class="line" style="height:20px"> Log.d(TAG, <span class="string" style="color:rgb(181,189,104)">"Calculated framing rect: "</span> + framingRect);</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> framingRect;</span><span class="line" style="height:20px">}</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> <span class="built_in" style="color:rgb(222,147,95)">int</span> findDesiredDimensionInRange(<span class="built_in" style="color:rgb(222,147,95)">int</span> resolution, <span class="built_in" style="color:rgb(222,147,95)">int</span> hardMin, <span class="built_in" style="color:rgb(222,147,95)">int</span> hardMax) {<!-- --></span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> dim = <span class="number" style="color:rgb(181,189,104)">5</span> * resolution / <span class="number" style="color:rgb(181,189,104)">8</span>; <span class="comment" style="color:rgb(150,152,150)">// Target 5/8 of each dimension</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (dim < hardMin) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> hardMin;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (dim > hardMax) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> hardMax;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> dim;</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><p>这段代码并没有什么问题,也完全符合逻辑。但为什么在扫描的时候这么难扫到二维码呢,原因在于官方为了减少解码的数据,提高解码效率和速度,采用了<strong>裁剪无用区域的方式</strong>。这样会带来一定的问题,整个二维码数据需要完全放到聚焦框里才有可能被识别,并且在<code>buildLuminanceSource(byte[],int,int)</code>这个方法签名中,传入的byte数组便是图像的数据,并没有因为裁剪而使数据量减小,而是采用了取这个数组中的部分数据来达到裁剪的目的。对于目前CPU性能过剩的大多数智能手机来说,这种裁剪显得没有必要。如果把解码数据换成采用全幅图像数据,这样在识别的过程中便不再拘束于聚焦框,也使得二维码数据可以铺满整个屏幕。这样用户在使用程序来扫描二维码时,尽管不完全对准聚焦框,也可以识别出来。这属于一种策略上的让步,给用户造成了错觉,但提高了识别的精度。</p><p>解决办法很简单,就是不仅仅使用聚焦框里的图像数据,而是采用全幅图像的数据。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="6"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="7"><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> PlanarYUVLuminanceSource buildLuminanceSource(<span class="built_in" style="color:rgb(222,147,95)">byte</span>[] data, <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">height</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 直接返回整幅图像的数据,而不计算聚焦框大小。</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> <span class="keyword" style="color:rgb(178,148,187)">new</span> PlanarYUVLuminanceSource(data, <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="variable" style="color:rgb(204,102,102)">height</span>, <span class="number" style="color:rgb(181,189,104)">0</span>, <span class="number" style="color:rgb(181,189,104)">0</span>, <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="variable" style="color:rgb(204,102,102)">height</span>, <span class="keyword" style="color:rgb(178,148,187)">false</span>);</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><h3 id="DecodeHintType"><a href="#DecodeHintType" class="headerlink" title="DecodeHintType"></a>DecodeHintType</h3><p>在使用zxing解析二维码时,允许事先进行相关配置,这个文件通过<code>Map<DecodeHintType, ?></code>键值对来保存,然后使用方法<code>public void setHints(Map<DecodeHintType,?> hints)</code>来设置到相应的解码器中。DecodeHintType是一个枚举类,其中有几个重要的枚举值,</p><ul><li>POSSIBLE_FORMATS(List.class)</li></ul><p>用于列举支持的解析格式,一共有17种,在<code>com.google.zxing.BarcodeFormat</code>里定义。官方默认支持所有的格式。</p><ul><li>TRY_HARDER(Void.class)</li></ul><p>是否使用HARDER模式来解析数据,如果启用,则会花费更多的时间去解析二维码,对精度有优化,对速度则没有。</p><ul><li>CHARACTER_SET(String.class)</li></ul><p>解析的字符集。这个对解析也比较关键,最好定义需要解析数据对应的字符集。</p><p>如果项目仅仅用来解析二维码,完全没必要支持所有的格式,也没有必要使用<code>MultiFormatReader</code>来解析。所以在配置的过程中,我移除了所有与二维码不相关的代码。直接使用<code>QRCodeReader</code>类来解析,字符集采用utf-8,使用Harder模式,并且把可能的解析格式只定义为<code>BarcodeFormat.QR_CODE</code>,这对于直接二维码扫描解析无疑是帮助最大的。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="8"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="9"><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">final</span> Map<DecodeHintType, Object> mHints;</span><span class="line" style="height:20px">DecodeHandler(QrCodeActivity activity) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">this</span>.mActivity = activity;</span><span class="line" style="height:20px"> mQrCodeReader = <span class="keyword" style="color:rgb(178,148,187)">new</span> QRCodeReader();</span><span class="line" style="height:20px"> mHints = <span class="keyword" style="color:rgb(178,148,187)">new</span> Hashtable<>();</span><span class="line" style="height:20px"> mHints.put(DecodeHintType.CHARACTER_SET, <span class="string" style="color:rgb(181,189,104)">"utf-8"</span>);</span><span class="line" style="height:20px"> mHints.put(DecodeHintType.TRY_HARDER, <span class="keyword" style="color:rgb(178,148,187)">Boolean</span>.<span class="keyword" style="color:rgb(178,148,187)">TRUE</span>);</span><span class="line" style="height:20px"> mHints.put(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><h1 id="二维码图像识别精度探究"><a href="#二维码图像识别精度探究" class="headerlink" title="二维码图像识别精度探究"></a>二维码图像识别精度探究</h1><h2 id="图像-x2F-像素编码格式"><a href="#图像-x2F-像素编码格式" class="headerlink" title="图像/像素编码格式"></a>图像/像素编码格式</h2><p>Android相机预览的时候支持几种不同的格式,从图像的角度(<a href="http://developer.android.com/intl/zh-cn/reference/android/graphics/ImageFormat.html">ImageFormat</a>)来说有NV16、NV21、YUY2、YV12、RGB_565和JPEG,从像素的角度(<a href="http://developer.android.com/intl/zh-cn/reference/android/graphics/PixelFormat.html">PixelFormat</a>)来说,有YUV422SP、YUV420SP、YUV422I、YUV420P、RGB565和JPEG,它们之间的对应关系可以从<code>Camera.Parameters.cameraFormatForPixelFormat(int)</code>方法中得到。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="10"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="11"><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> String cameraFormatForPixelFormat(<span class="typename">int</span> pixel_format) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">switch</span>(pixel_format) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">case</span> ImageFormat.<span class="string" style="color:rgb(181,189,104)">NV16:</span> <span class="keyword" style="color:rgb(178,148,187)">return</span> PIXEL_FORMAT_YUV422SP;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">case</span> ImageFormat.<span class="string" style="color:rgb(181,189,104)">NV21:</span> <span class="keyword" style="color:rgb(178,148,187)">return</span> PIXEL_FORMAT_YUV420SP;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">case</span> ImageFormat.<span class="string" style="color:rgb(181,189,104)">YUY2:</span> <span class="keyword" style="color:rgb(178,148,187)">return</span> PIXEL_FORMAT_YUV422I;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">case</span> ImageFormat.<span class="string" style="color:rgb(181,189,104)">YV12:</span> <span class="keyword" style="color:rgb(178,148,187)">return</span> PIXEL_FORMAT_YUV420P;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">case</span> ImageFormat.<span class="string" style="color:rgb(181,189,104)">RGB_565:</span> <span class="keyword" style="color:rgb(178,148,187)">return</span> PIXEL_FORMAT_RGB565;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">case</span> ImageFormat.<span class="string" style="color:rgb(181,189,104)">JPEG:</span> <span class="keyword" style="color:rgb(178,148,187)">return</span> PIXEL_FORMAT_JPEG;</span><span class="line" style="height:20px"><span class="label"> default:</span> <span class="keyword" style="color:rgb(178,148,187)">return</span> <span class="literal" style="color:rgb(222,147,95)">null</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><p>目前大部分Android手机摄像头设置的默认格式是<code>yuv420sp</code>,其原理可参考文章<a href="http://www.cnblogs.com/azraelly/archive/2013/01/01/2841269.html">《图文详解YUV420数据格式》</a>。编码成YUV的所有像素格式里,yuv420sp占用的空间是最小的。既然如此,zxing当然会考虑到这种情况。因此针对YUV编码的数据,有<code>PlanarYUVLuminanceSource</code>这个类去处理,而针对RGB编码的数据,则使用<code>RGBLuminanceSource</code>去处理。在下节介绍的图像识别算法中我们可以知道,大部分二维码的识别都是基于二值化的方法,在色域的处理上,YUV的二值化效果要优于RGB,并且RGB图像在处理中不支持旋转。因此,一种优化的思路是讲所有ARGB编码的图像转换成YUV编码,再使用<code>PlanarYUVLuminanceSource</code>去处理生成的结果。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="12" class="" name="code"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span><span class="line" style="height:20px">12</span><span class="line" style="height:20px">13</span><span class="line" style="height:20px">14</span><span class="line" style="height:20px">15</span><span class="line" style="height:20px">16</span><span class="line" style="height:20px">17</span><span class="line" style="height:20px">18</span><span class="line" style="height:20px">19</span><span class="line" style="height:20px">20</span><span class="line" style="height:20px">21</span><span class="line" style="height:20px">22</span><span class="line" style="height:20px">23</span><span class="line" style="height:20px">24</span><span class="line" style="height:20px">25</span><span class="line" style="height:20px">26</span><span class="line" style="height:20px">27</span><span class="line" style="height:20px">28</span><span class="line" style="height:20px">29</span><span class="line" style="height:20px">30</span><span class="line" style="height:20px">31</span><span class="line" style="height:20px">32</span><span class="line" style="height:20px">33</span><span class="line" style="height:20px">34</span><span class="line" style="height:20px">35</span><span class="line" style="height:20px">36</span><span class="line" style="height:20px">37</span><span class="line" style="height:20px">38</span><span class="line" style="height:20px">39</span><span class="line" style="height:20px">40</span><span class="line" style="height:20px">41</span><span class="line" style="height:20px">42</span><span class="line" style="height:20px">43</span><span class="line" style="height:20px">44</span><span class="line" style="height:20px">45</span><span class="line" style="height:20px">46</span><span class="line" style="height:20px">47</span><span class="line" style="height:20px">48</span><span class="line" style="height:20px">49</span><span class="line" style="height:20px">50</span><span class="line" style="height:20px">51</span><span class="line" style="height:20px">52</span><span class="line" style="height:20px">53</span><span class="line" style="height:20px">54</span><span class="line" style="height:20px">55</span><span class="line" style="height:20px">56</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="13" class="" name="code"><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * RGB转YUV420sp</span><span class="line" style="height:20px"> *</span><span class="line" style="height:20px"> * @param yuv420sp inputWidth * inputHeight * 3 / 2</span><span class="line" style="height:20px"> * @param argb inputWidth * inputHeight</span><span class="line" style="height:20px"> * @param width image width</span><span class="line" style="height:20px"> * @param height image height</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="function" style="color:rgb(129,162,190)"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> <span class="keyword" style="color:rgb(178,148,187)">void</span> <span class="title" style="color:rgb(138,190,183)">encodeYUV420SP</span><span class="params" style="color:rgb(222,147,95)">(byte[] yuv420sp, <span class="keyword" style="color:rgb(178,148,187)">int</span>[] argb, <span class="keyword" style="color:rgb(178,148,187)">int</span> width, <span class="keyword" style="color:rgb(178,148,187)">int</span> height)</span> </span>{<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 帧图片的像素大小</span></span><span class="line" style="height:20px"> final <span class="keyword" style="color:rgb(178,148,187)">int</span> frameSize = width * height;</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// ---YUV数据---</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> Y, U, V;</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Y的index从0开始</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> yIndex = <span class="number" style="color:rgb(181,189,104)">0</span>;</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// UV的index从frameSize开始</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> uvIndex = frameSize;</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// ---颜色数据---</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> R, G, B;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> rgbIndex = <span class="number" style="color:rgb(181,189,104)">0</span>;</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// ---循环所有像素点,RGB转YUV---</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">for</span> (<span class="keyword" style="color:rgb(178,148,187)">int</span> j = <span class="number" style="color:rgb(181,189,104)">0</span>; j < height; j++) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">for</span> (<span class="keyword" style="color:rgb(178,148,187)">int</span> i = <span class="number" style="color:rgb(181,189,104)">0</span>; i < width; i++) {<!-- --></span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> R = (argb[rgbIndex] & <span class="number" style="color:rgb(181,189,104)">0xff0000</span>) >> <span class="number" style="color:rgb(181,189,104)">16</span>;</span><span class="line" style="height:20px"> G = (argb[rgbIndex] & <span class="number" style="color:rgb(181,189,104)">0xff00</span>) >> <span class="number" style="color:rgb(181,189,104)">8</span>;</span><span class="line" style="height:20px"> B = (argb[rgbIndex] & <span class="number" style="color:rgb(181,189,104)">0xff</span>);</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">//</span></span><span class="line" style="height:20px"> rgbIndex++;</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// well known RGB to YUV algorithm</span></span><span class="line" style="height:20px"> Y = ((<span class="number" style="color:rgb(181,189,104)">66</span> * R + <span class="number" style="color:rgb(181,189,104)">129</span> * G + <span class="number" style="color:rgb(181,189,104)">25</span> * B + <span class="number" style="color:rgb(181,189,104)">128</span>) >> <span class="number" style="color:rgb(181,189,104)">8</span>) + <span class="number" style="color:rgb(181,189,104)">16</span>;</span><span class="line" style="height:20px"> U = ((-<span class="number" style="color:rgb(181,189,104)">38</span> * R - <span class="number" style="color:rgb(181,189,104)">74</span> * G + <span class="number" style="color:rgb(181,189,104)">112</span> * B + <span class="number" style="color:rgb(181,189,104)">128</span>) >> <span class="number" style="color:rgb(181,189,104)">8</span>) + <span class="number" style="color:rgb(181,189,104)">128</span>;</span><span class="line" style="height:20px"> V = ((<span class="number" style="color:rgb(181,189,104)">112</span> * R - <span class="number" style="color:rgb(181,189,104)">94</span> * G - <span class="number" style="color:rgb(181,189,104)">18</span> * B + <span class="number" style="color:rgb(181,189,104)">128</span>) >> <span class="number" style="color:rgb(181,189,104)">8</span>) + <span class="number" style="color:rgb(181,189,104)">128</span>;</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> Y = Math.max(<span class="number" style="color:rgb(181,189,104)">0</span>, Math.min(Y, <span class="number" style="color:rgb(181,189,104)">255</span>));</span><span class="line" style="height:20px"> U = Math.max(<span class="number" style="color:rgb(181,189,104)">0</span>, Math.min(U, <span class="number" style="color:rgb(181,189,104)">255</span>));</span><span class="line" style="height:20px"> V = Math.max(<span class="number" style="color:rgb(181,189,104)">0</span>, Math.min(V, <span class="number" style="color:rgb(181,189,104)">255</span>));</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2</span></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// meaning for every 4 Y pixels there are 1 V and 1 U. Note the sampling is every other</span></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// pixel AND every other scan line.</span></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// ---Y---</span></span><span class="line" style="height:20px"> yuv420sp[yIndex++] = (byte) Y;</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// ---UV---</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> ((j % <span class="number" style="color:rgb(181,189,104)">2</span> == <span class="number" style="color:rgb(181,189,104)">0</span>) && (i % <span class="number" style="color:rgb(181,189,104)">2</span> == <span class="number" style="color:rgb(181,189,104)">0</span>)) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">//</span></span><span class="line" style="height:20px"> yuv420sp[uvIndex++] = (byte) V;</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">//</span></span><span class="line" style="height:20px"> yuv420sp[uvIndex++] = (byte) U;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><p>Android中读取一张图片一般是通过<code>BitmapFactory.decodeFile(imgPath, options)</code>这个方法去得到这张图片的Bitmap数据,Bitmap是由ARGB值编码得到的,因此如果需要转换成YUV,还需要做一点小小的变换。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="14" class="" name="code"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span><span class="line" style="height:20px">12</span><span class="line" style="height:20px">13</span><span class="line" style="height:20px">14</span><span class="line" style="height:20px">15</span><span class="line" style="height:20px">16</span><span class="line" style="height:20px">17</span><span class="line" style="height:20px">18</span><span class="line" style="height:20px">19</span><span class="line" style="height:20px">20</span><span class="line" style="height:20px">21</span><span class="line" style="height:20px">22</span><span class="line" style="height:20px">23</span><span class="line" style="height:20px">24</span><span class="line" style="height:20px">25</span><span class="line" style="height:20px">26</span><span class="line" style="height:20px">27</span><span class="line" style="height:20px">28</span><span class="line" style="height:20px">29</span><span class="line" style="height:20px">30</span><span class="line" style="height:20px">31</span><span class="line" style="height:20px">32</span><span class="line" style="height:20px">33</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="15" class="" name="code"><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> byte[] yuvs;</span><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * 根据Bitmap的ARGB值生成YUV420SP数据。</span><span class="line" style="height:20px"> *</span><span class="line" style="height:20px"> * @param inputWidth image width</span><span class="line" style="height:20px"> * @param inputHeight image height</span><span class="line" style="height:20px"> * @param scaled bmp</span><span class="line" style="height:20px"> * @return YUV420SP数组</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> byte[] getYUV420sp(<span class="keyword" style="color:rgb(178,148,187)">int</span> inputWidth, <span class="keyword" style="color:rgb(178,148,187)">int</span> inputHeight, Bitmap scaled) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span>[] argb = <span class="keyword" style="color:rgb(178,148,187)">new</span> <span class="keyword" style="color:rgb(178,148,187)">int</span>[inputWidth * inputHeight];</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> scaled.getPixels(argb, <span class="number" style="color:rgb(181,189,104)">0</span>, inputWidth, <span class="number" style="color:rgb(181,189,104)">0</span>, <span class="number" style="color:rgb(181,189,104)">0</span>, inputWidth, inputHeight);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * 需要转换成偶数的像素点,否则编码YUV420的时候有可能导致分配的空间大小不够而溢出。</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> requiredWidth = inputWidth % <span class="number" style="color:rgb(181,189,104)">2</span> == <span class="number" style="color:rgb(181,189,104)">0</span> ? inputWidth : inputWidth + <span class="number" style="color:rgb(181,189,104)">1</span>;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> requiredHeight = inputHeight % <span class="number" style="color:rgb(181,189,104)">2</span> == <span class="number" style="color:rgb(181,189,104)">0</span> ? inputHeight : inputHeight + <span class="number" style="color:rgb(181,189,104)">1</span>;</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> byteLength = requiredWidth * requiredHeight * <span class="number" style="color:rgb(181,189,104)">3</span> / <span class="number" style="color:rgb(181,189,104)">2</span>;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (yuvs == null || yuvs.length < byteLength) {<!-- --></span><span class="line" style="height:20px"> yuvs = <span class="keyword" style="color:rgb(178,148,187)">new</span> byte[byteLength];</span><span class="line" style="height:20px"> } <span class="keyword" style="color:rgb(178,148,187)">else</span> {<!-- --></span><span class="line" style="height:20px"> Arrays.fill(yuvs, (byte) <span class="number" style="color:rgb(181,189,104)">0</span>);</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> encodeYUV420SP(yuvs, argb, inputWidth, inputHeight);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> scaled.recycle();</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> yuvs;</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><p>这里面有几个坑,在方法里已经列出来了。首先,如果每次都生成新的YUV数组,不知道在扫一扫解码时要进行GC多少次。。。所以就采用了静态的数组变量来存储数据,只有当当前的长宽乘积超过数组大小时,才重新生成新的_<code>yuvs</code>_。其次,如果鉴于YUV的特性,长宽只能是偶数个像素点,否则可能会造成数组溢出(不信可以尝试)。最后,使用完了Bitmap要记得回收,那玩意吃内存不是随便说说的。</p><h2 id="二维码图像识别算法选择"><a href="#二维码图像识别算法选择" class="headerlink" title="二维码图像识别算法选择"></a>二维码图像识别算法选择</h2><p>二维码扫描精度和许多因素有关,最关键的因素是扫描算法。目前在图形识别领域中,较常用的二维码识别算法主要有两种,分别是<code>HybridBinarizer</code>和<code>GlobalHistogramBinarizer</code>,这两种算法都是基于二值化,即将图片的色域变为黑白两个颜色,然后提取图形中的二维码矩阵。实际上,zxing中的HybridBinarizer继承自GlobalHistogramBinarizer,并在此基础上做了功能性的改进。援引官方介绍:</p><p><strong>This Binarizer(GlobalHistogramBinarizer) implementation uses the old ZXing global histogram approach. It is suitable for low-end mobile devices which don’t have enough CPU or memory to use a local thresholding algorithm. However, because it picks a global black point, it cannot handle difficult shadows and gradients. Faster mobile devices and all desktop applications should probably use HybridBinarizer instead.</strong></p><p><strong>This class(HybridBinarizer) implements a local thresholding algorithm, which while slower than the GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for high frequency images of barcodes with black data on white backgrounds. For this application, it does a much better job than a global blackpoint with severe shadows and gradients. However it tends to produce artifacts on lower frequency images and is therefore not a good general purpose binarizer for uses outside ZXing. This class extends GlobalHistogramBinarizer, using the older histogram approach for 1D readers, and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already inherently local, and only fails for horizontal gradients. We can revisit that problem later, but for now it was not a win to use local blocks for 1D.</strong> ···</p><p><code>GlobalHistogramBinarizer</code>算法<strong>适合于低端的设备,对手机的CPU和内存要求不高</strong>。但它选择了全部的黑点来计算,因此无法处理阴影和渐变这两种情况。HybridBinarizer算法在执行效率上要慢于GlobalHistogramBinarizer算法,但识别相对更有效。它专门为<strong>以白色为背景的连续黑色块二维码图像</strong>解析而设计,也更适合用来解析具有<strong>严重阴影和渐变</strong>的二维码图像。</p><p>网上对这两种算法的解析并不多,目前仅找到一篇文章详解了GlobalHistogramBinarizer算法,详见<a href="http://iluhcm.com/2016/01/08/scan-qr-code-and-recognize-it-from-picture-fastly-using-zxing/[http://kuangjianwei.blog.163.com/blog/static/190088953201361015055110/]%28%29"><a href="">http://kuangjianwei.blog.163.com/blog/static/190088953201361015055110/</a></a>。有时间再看一下相关源码。</p><p>zxing项目官方默认使用的是HybridBinarizer二值化方法。在实际的测试中,和官方的介绍大致一样。然而目前的大部分二维码都是黑色二维码,白色背景的。不管是二维码扫描还是二维码图像识别,使用GlobalHistogramBinarizer算法的效果要稍微比HybridBinarizer好一些,识别的速度更快,对低分辨的图像识别精度更高。</p><p>除了这两种算法,我相信在图像识别领域肯定还有更好的算法存在,目前受限于知识水平,对二值化算法这一块还比较陌生,期待以后能够深入理解并改进目前的开源算法(*^__^*)……</p><h2 id="图像大小对识别精度的影响"><a href="#图像大小对识别精度的影响" class="headerlink" title="图像大小对识别精度的影响"></a>图像大小对识别精度的影响</h2><p>这点是测试中无意发现的。现在的手机摄像头拍照出现的照片像素都很高,动不动就1200W像素,1600W像素,甚至是2000W都不稀奇,但照片的成像质量不一定高。将一张高分辨率的图片按原分辨率导入Android手机,很容易产生OOM。我们来计算一下,导入一张1200W像素的图片需要的内存,假设图片是<code>4000px*3000px</code>,如果导入的图片采用ARGB_8888编码形式,则每个像素需要占用4个Bytes(分别存储ARGB值)来存储,则需要<code>4000*3000*4bytes=45.776MB</code>的内存,这在有限的移动资源里,显然是不能忍受的。</p><p>通过上一节对图像算法的简单研究,在<code>GlobalHistogramBinarizer</code>中,是从图像中均匀取5行(覆盖整个图像高度),每行取中间五分之四作为样本;以灰度值为X轴,每个灰度值的像素个数为Y轴建立一个直方图,从直方图中取点数最多的一个灰度值,然后再去给其他的灰度值进行分数计算,按照点数乘以与最多点数灰度值的距离的平方来进行打分,选分数最高的一个灰度值。接下来在这两个灰度值中间选取一个区分界限,取的原则是尽量靠近中间并且要点数越少越好。界限有了以后就容易了,与整幅图像的每个点进行比较,如果灰度值比界限小的就是黑,在新的矩阵中将该点置1,其余的就是白,为0。(摘自<a href="http://kuangjianwei.blog.163.com/blog/static/190088953201361015055110/">zxing源码分析——QR码部分</a>)</p><p>根据算法的实现,可以知道图像的分辨率对二维码的取值是有影响的。并不是图像的分辨率越高就越容易取到二维码。高分辨率的图像对Android的内存资源占用也很可怕。所以在测试的过程中,我尝试将图片压缩成不同大小分辨率,然后再进行图片的二维码识别。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="16" class="" name="code"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span><span class="line" style="height:20px">12</span><span class="line" style="height:20px">13</span><span class="line" style="height:20px">14</span><span class="line" style="height:20px">15</span><span class="line" style="height:20px">16</span><span class="line" style="height:20px">17</span><span class="line" style="height:20px">18</span><span class="line" style="height:20px">19</span><span class="line" style="height:20px">20</span><span class="line" style="height:20px">21</span><span class="line" style="height:20px">22</span><span class="line" style="height:20px">23</span><span class="line" style="height:20px">24</span><span class="line" style="height:20px">25</span><span class="line" style="height:20px">26</span><span class="line" style="height:20px">27</span><span class="line" style="height:20px">28</span><span class="line" style="height:20px">29</span><span class="line" style="height:20px">30</span><span class="line" style="height:20px">31</span><span class="line" style="height:20px">32</span><span class="line" style="height:20px">33</span><span class="line" style="height:20px">34</span><span class="line" style="height:20px">35</span><span class="line" style="height:20px">36</span><span class="line" style="height:20px">37</span><span class="line" style="height:20px">38</span><span class="line" style="height:20px">39</span><span class="line" style="height:20px">40</span><span class="line" style="height:20px">41</span><span class="line" style="height:20px">42</span><span class="line" style="height:20px">43</span><span class="line" style="height:20px">44</span><span class="line" style="height:20px">45</span><span class="line" style="height:20px">46</span><span class="line" style="height:20px">47</span><span class="line" style="height:20px">48</span><span class="line" style="height:20px">49</span><span class="line" style="height:20px">50</span><span class="line" style="height:20px">51</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="17" class="" name="code"><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * 根据给定的宽度和高度动态计算图片压缩比率</span><span class="line" style="height:20px"> * </span><span class="line" style="height:20px"> * <span class="doctag">@param</span> options Bitmap配置文件</span><span class="line" style="height:20px"> * <span class="doctag">@param</span> reqWidth 需要压缩到的宽度</span><span class="line" style="height:20px"> * <span class="doctag">@param</span> reqHeight 需要压缩到的高度</span><span class="line" style="height:20px"> * <span class="doctag">@return</span> 压缩比</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> <span class="function" style="color:rgb(129,162,190)"><span class="keyword" style="color:rgb(178,148,187)">int</span> <span class="title" style="color:rgb(138,190,183)">calculateInSampleSize</span><span class="params" style="color:rgb(222,147,95)">(BitmapFactory.Options options, <span class="keyword" style="color:rgb(178,148,187)">int</span> reqWidth, <span class="keyword" style="color:rgb(178,148,187)">int</span> reqHeight)</span> </span>{<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Raw height and width of image</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">final</span> <span class="keyword" style="color:rgb(178,148,187)">int</span> height = options.outHeight;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">final</span> <span class="keyword" style="color:rgb(178,148,187)">int</span> width = options.outWidth;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">int</span> inSampleSize = <span class="number" style="color:rgb(181,189,104)">1</span>;</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (height > reqHeight || width > reqWidth) {<!-- --></span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">final</span> <span class="keyword" style="color:rgb(178,148,187)">int</span> halfHeight = height / <span class="number" style="color:rgb(181,189,104)">2</span>;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">final</span> <span class="keyword" style="color:rgb(178,148,187)">int</span> halfWidth = width / <span class="number" style="color:rgb(181,189,104)">2</span>;</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Calculate the largest inSampleSize value that is a power of 2 and keeps both</span></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// height and width larger than the requested height and width.</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">while</span> ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {<!-- --></span><span class="line" style="height:20px"> inSampleSize *= <span class="number" style="color:rgb(181,189,104)">2</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span> inSampleSize;</span><span class="line" style="height:20px">}</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * 将图片根据压缩比压缩成固定宽高的Bitmap,实际解析的图片大小可能和#reqWidth、#reqHeight不一样。</span><span class="line" style="height:20px"> * </span><span class="line" style="height:20px"> * <span class="doctag">@param</span> imgPath 图片地址</span><span class="line" style="height:20px"> * <span class="doctag">@param</span> reqWidth 需要压缩到的宽度</span><span class="line" style="height:20px"> * <span class="doctag">@param</span> reqHeight 需要压缩到的高度</span><span class="line" style="height:20px"> * <span class="doctag">@return</span> Bitmap</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> <span class="keyword" style="color:rgb(178,148,187)">static</span> <span class="function" style="color:rgb(129,162,190)">Bitmap <span class="title" style="color:rgb(138,190,183)">decodeSampledBitmapFromFile</span><span class="params" style="color:rgb(222,147,95)">(String imgPath, <span class="keyword" style="color:rgb(178,148,187)">int</span> reqWidth, <span class="keyword" style="color:rgb(178,148,187)">int</span> reqHeight)</span> </span>{<!-- --></span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// First decode with inJustDecodeBounds=true to check dimensions</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">final</span> BitmapFactory.Options options = <span class="keyword" style="color:rgb(178,148,187)">new</span> BitmapFactory.Options();</span><span class="line" style="height:20px"> options.inJustDecodeBounds = <span class="keyword" style="color:rgb(178,148,187)">true</span>;</span><span class="line" style="height:20px"> BitmapFactory.decodeFile(imgPath, options);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Calculate inSampleSize</span></span><span class="line" style="height:20px"> options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Decode bitmap with inSampleSize set</span></span><span class="line" style="height:20px"> options.inJustDecodeBounds = <span class="keyword" style="color:rgb(178,148,187)">false</span>;</span><span class="line" style="height:20px"> <span class="function" style="color:rgb(129,162,190)"><span class="keyword" style="color:rgb(178,148,187)">return</span> BitmapFactory.<span class="title" style="color:rgb(138,190,183)">decodeFile</span><span class="params" style="color:rgb(222,147,95)">(imgPath, options)</span></span>;</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><p>Android图片优化需要通过在解析图片的时候,设置<code>BitmapFactory.Options.inSampleSize</code>的值,根据比例压缩图片大小。在进行图片二维码解析的线程中,通过设置不同的图片大小,来测试二维码的识别率。这个测试过程我忘记保存了,只记得测试了压缩成最大宽高值为2048、1024、512、256和128像素的包含二维码的图片,但实际的测试结果是,当<code>MAX_PICTURE_PIXEL=256</code>的时候识别率最高。</p><h2 id="相机预览倍数设置及聚焦时间调整"><a href="#相机预览倍数设置及聚焦时间调整" class="headerlink" title="相机预览倍数设置及聚焦时间调整"></a>相机预览倍数设置及聚焦时间调整</h2><p>如果使用zxing默认的相机配置,会发现需要离二维码很近才能够识别出来,但这样会带来一个问题——聚焦困难。解决办法就是调整相机预览倍数以及减小相机聚焦的时间。</p><p>通过测试可以发现,每个手机的最大放大倍数几乎是不一样的,这可能和摄像头的型号有关。如果设置成一个固定的值,那可能会产生在某些手机上过度放大,某些手机上放大的倍数不够。索性相机的参数设定里给我们提供了最大的放大倍数值,通过取放大倍数值的N分之一作为当前的放大倍数,就完美地解决了手机的适配问题。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="18"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="19"><span class="line" style="height:20px">// 需要判断摄像头是否支持缩放</span><span class="line" style="height:20px"><span class="section"><span class="keyword" style="color:rgb(178,148,187)">Parameters</span> <span class="keyword" style="color:rgb(178,148,187)">parameters</span> = camera.getParameters();</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">if</span> (<span class="section"><span class="keyword" style="color:rgb(178,148,187)">parameters</span>.isZoomSupported()) {<!-- --></span><span class="line" style="height:20px">// 设置成最大倍数的1/<span class="number" style="color:rgb(181,189,104)">10</span>,基本符合远近需求</span><span class="line" style="height:20px"> parameters.setZoom(parameters.getMaxZoom() / 10);</span></span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><p>zxing默认的相机聚焦时间是<code>2s</code>,可以根据扫描的视觉适当调整。聚焦时间的调整也很简单,在<code>AutoFocusCallback</code>这个类里,调整<code>AUTO_FOCUS_INTERVAL_MS</code>这个值就可以了。</p><h1 id="二维码扫描视觉调整"><a href="#二维码扫描视觉调整" class="headerlink" title="二维码扫描视觉调整"></a>二维码扫描视觉调整</h1><p>二维码扫描视觉的绘制在<code>ViewfinderView.java</code>完成,官方是继承了View然后在<code>onDraw()</code>方法中实现了视图的绘制。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="20" class="" name="code"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span><span class="line" style="height:20px">12</span><span class="line" style="height:20px">13</span><span class="line" style="height:20px">14</span><span class="line" style="height:20px">15</span><span class="line" style="height:20px">16</span><span class="line" style="height:20px">17</span><span class="line" style="height:20px">18</span><span class="line" style="height:20px">19</span><span class="line" style="height:20px">20</span><span class="line" style="height:20px">21</span><span class="line" style="height:20px">22</span><span class="line" style="height:20px">23</span><span class="line" style="height:20px">24</span><span class="line" style="height:20px">25</span><span class="line" style="height:20px">26</span><span class="line" style="height:20px">27</span><span class="line" style="height:20px">28</span><span class="line" style="height:20px">29</span><span class="line" style="height:20px">30</span><span class="line" style="height:20px">31</span><span class="line" style="height:20px">32</span><span class="line" style="height:20px">33</span><span class="line" style="height:20px">34</span><span class="line" style="height:20px">35</span><span class="line" style="height:20px">36</span><span class="line" style="height:20px">37</span><span class="line" style="height:20px">38</span><span class="line" style="height:20px">39</span><span class="line" style="height:20px">40</span><span class="line" style="height:20px">41</span><span class="line" style="height:20px">42</span><span class="line" style="height:20px">43</span><span class="line" style="height:20px">44</span><span class="line" style="height:20px">45</span><span class="line" style="height:20px">46</span><span class="line" style="height:20px">47</span><span class="line" style="height:20px">48</span><span class="line" style="height:20px">49</span><span class="line" style="height:20px">50</span><span class="line" style="height:20px">51</span><span class="line" style="height:20px">52</span><span class="line" style="height:20px">53</span><span class="line" style="height:20px">54</span><span class="line" style="height:20px">55</span><span class="line" style="height:20px">56</span><span class="line" style="height:20px">57</span><span class="line" style="height:20px">58</span><span class="line" style="height:20px">59</span><span class="line" style="height:20px">60</span><span class="line" style="height:20px">61</span><span class="line" style="height:20px">62</span><span class="line" style="height:20px">63</span><span class="line" style="height:20px">64</span><span class="line" style="height:20px">65</span><span class="line" style="height:20px">66</span><span class="line" style="height:20px">67</span><span class="line" style="height:20px">68</span><span class="line" style="height:20px">69</span><span class="line" style="height:20px">70</span><span class="line" style="height:20px">71</span><span class="line" style="height:20px">72</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="21" class="" name="code"><span class="line" style="height:20px">@Override</span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> <span class="keyword" style="color:rgb(178,148,187)">void</span> onDraw(Canvas canvas) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (cameraManager == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span>; <span class="comment" style="color:rgb(150,152,150)">// not ready yet, early draw before done configuring</span></span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> Rect frame = cameraManager.getFramingRect();</span><span class="line" style="height:20px"> Rect previewFrame = cameraManager.getFramingRectInPreview();</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (frame == <span class="keyword" style="color:rgb(178,148,187)">null</span> || previewFrame == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">width</span> = canvas.getWidth();</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">height</span> = canvas.getHeight();</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 绘制聚焦框外的暗色透明层</span></span><span class="line" style="height:20px"> paint.setColor(resultBitmap != <span class="keyword" style="color:rgb(178,148,187)">null</span> ? resultColor : maskColor);</span><span class="line" style="height:20px"> canvas.drawRect(<span class="number" style="color:rgb(181,189,104)">0</span>, <span class="number" style="color:rgb(181,189,104)">0</span>, <span class="variable" style="color:rgb(204,102,102)">width</span>, frame.top, paint);</span><span class="line" style="height:20px"> canvas.drawRect(<span class="number" style="color:rgb(181,189,104)">0</span>, frame.top, frame.left, frame.bottom + <span class="number" style="color:rgb(181,189,104)">1</span>, paint);</span><span class="line" style="height:20px"> canvas.drawRect(frame.right + <span class="number" style="color:rgb(181,189,104)">1</span>, frame.top, <span class="variable" style="color:rgb(204,102,102)">width</span>, frame.bottom + <span class="number" style="color:rgb(181,189,104)">1</span>, paint);</span><span class="line" style="height:20px"> canvas.drawRect(<span class="number" style="color:rgb(181,189,104)">0</span>, frame.bottom + <span class="number" style="color:rgb(181,189,104)">1</span>, <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="variable" style="color:rgb(204,102,102)">height</span>, paint);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (resultBitmap != <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 如果扫描结果不为空,则把扫描的结果填充到聚焦框中</span></span><span class="line" style="height:20px"> paint.setAlpha(CURRENT_POINT_OPACITY);</span><span class="line" style="height:20px"> canvas.drawBitmap(resultBitmap, <span class="keyword" style="color:rgb(178,148,187)">null</span>, frame, paint);</span><span class="line" style="height:20px"> } <span class="keyword" style="color:rgb(178,148,187)">else</span> {<!-- --></span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 画一根红色的激光线表示二维码解码正在进行</span></span><span class="line" style="height:20px"> paint.setColor(laserColor);</span><span class="line" style="height:20px"> paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);</span><span class="line" style="height:20px"> scannerAlpha = (scannerAlpha + <span class="number" style="color:rgb(181,189,104)">1</span>) % SCANNER_ALPHA.length;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> middle = frame.<span class="variable" style="color:rgb(204,102,102)">height</span>() / <span class="number" style="color:rgb(181,189,104)">2</span> + frame.top;</span><span class="line" style="height:20px"> canvas.drawRect(frame.left + <span class="number" style="color:rgb(181,189,104)">2</span>, middle - <span class="number" style="color:rgb(181,189,104)">1</span>, frame.right - <span class="number" style="color:rgb(181,189,104)">1</span>, middle + <span class="number" style="color:rgb(181,189,104)">2</span>, paint);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">float</span> scaleX = frame.<span class="variable" style="color:rgb(204,102,102)">width</span>() / (<span class="built_in" style="color:rgb(222,147,95)">float</span>) previewFrame.<span class="variable" style="color:rgb(204,102,102)">width</span>();</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">float</span> scaleY = frame.<span class="variable" style="color:rgb(204,102,102)">height</span>() / (<span class="built_in" style="color:rgb(222,147,95)">float</span>) previewFrame.<span class="variable" style="color:rgb(204,102,102)">height</span>();</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> List<ResultPoint> currentPossible = possibleResultPoints;</span><span class="line" style="height:20px"> List<ResultPoint> currentLast = lastPossibleResultPoints;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> frameLeft = frame.left;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> frameTop = frame.top;</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 绘制解析过程中可能扫描到的关键点,使用黄色小圆点表示</span></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (currentPossible.isEmpty()) {<!-- --></span><span class="line" style="height:20px"> lastPossibleResultPoints = <span class="keyword" style="color:rgb(178,148,187)">null</span>;</span><span class="line" style="height:20px"> } <span class="keyword" style="color:rgb(178,148,187)">else</span> {<!-- --></span><span class="line" style="height:20px"> possibleResultPoints = <span class="keyword" style="color:rgb(178,148,187)">new</span> ArrayList<>(<span class="number" style="color:rgb(181,189,104)">5</span>);</span><span class="line" style="height:20px"> lastPossibleResultPoints = currentPossible;</span><span class="line" style="height:20px"> paint.setAlpha(CURRENT_POINT_OPACITY);</span><span class="line" style="height:20px"> paint.setColor(resultPointColor);</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">synchronized</span> (currentPossible) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">for</span> (ResultPoint <span class="built_in" style="color:rgb(222,147,95)">point</span> : currentPossible) {<!-- --></span><span class="line" style="height:20px"> canvas.drawCircle(frameLeft + (<span class="built_in" style="color:rgb(222,147,95)">int</span>) (<span class="built_in" style="color:rgb(222,147,95)">point</span>.getX() * scaleX),</span><span class="line" style="height:20px"> frameTop + (<span class="built_in" style="color:rgb(222,147,95)">int</span>) (<span class="built_in" style="color:rgb(222,147,95)">point</span>.getY() * scaleY), POINT_SIZE, paint);</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (currentLast != <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> paint.setAlpha(CURRENT_POINT_OPACITY / <span class="number" style="color:rgb(181,189,104)">2</span>);</span><span class="line" style="height:20px"> paint.setColor(resultPointColor);</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">synchronized</span> (currentLast) {<!-- --></span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">float</span> radius = POINT_SIZE / <span class="number" style="color:rgb(181,189,104)">2.0</span>f;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">for</span> (ResultPoint <span class="built_in" style="color:rgb(222,147,95)">point</span> : currentLast) {<!-- --></span><span class="line" style="height:20px"> canvas.drawCircle(frameLeft + (<span class="built_in" style="color:rgb(222,147,95)">int</span>) (<span class="built_in" style="color:rgb(222,147,95)">point</span>.getX() * scaleX),</span><span class="line" style="height:20px"> frameTop + (<span class="built_in" style="color:rgb(222,147,95)">int</span>) (<span class="built_in" style="color:rgb(222,147,95)">point</span>.getY() * scaleY), radius, paint);</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 重绘聚焦框里的内容,不需要重绘整个界面。</span></span><span class="line" style="height:20px"> postInvalidateDelayed(ANIMATION_DELAY, frame.left - POINT_SIZE, frame.top - POINT_SIZE,</span><span class="line" style="height:20px"> frame.right + POINT_SIZE, frame.bottom + POINT_SIZE);</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table><p>我给它做了一点小改变,效果差不多,代码更简洁一些。由于代码中我不是根据屏幕的宽高动态计算聚焦框的大小,因此这里省去了从CameraManager获取FramingRect和FramingRectInPreview这两个矩形的过程。我在聚焦框外加了四个角,目前大部分二维码产品基本都是这么设计的吧,当然也可以使用图片来代替。总之视觉定制是因人而异,这里不做过多介绍。</p><table style="border-collapse:collapse; border-spacing:0px; margin:0px; width:auto; border:none; font-size:14px; table-layout:fixed"><tbody><tr style="background-color:rgb(249,249,249)"><td class="gutter" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px 20px 1px 1px; color: rgb(102, 102, 102); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; text-align: right; -webkit-user-select: auto;" data-index="22" class="" name="code"><span class="line" style="height:20px">1</span><span class="line" style="height:20px">2</span><span class="line" style="height:20px">3</span><span class="line" style="height:20px">4</span><span class="line" style="height:20px">5</span><span class="line" style="height:20px">6</span><span class="line" style="height:20px">7</span><span class="line" style="height:20px">8</span><span class="line" style="height:20px">9</span><span class="line" style="height:20px">10</span><span class="line" style="height:20px">11</span><span class="line" style="height:20px">12</span><span class="line" style="height:20px">13</span><span class="line" style="height:20px">14</span><span class="line" style="height:20px">15</span><span class="line" style="height:20px">16</span><span class="line" style="height:20px">17</span><span class="line" style="height:20px">18</span><span class="line" style="height:20px">19</span><span class="line" style="height:20px">20</span><span class="line" style="height:20px">21</span><span class="line" style="height:20px">22</span><span class="line" style="height:20px">23</span><span class="line" style="height:20px">24</span><span class="line" style="height:20px">25</span><span class="line" style="height:20px">26</span><span class="line" style="height:20px">27</span><span class="line" style="height:20px">28</span><span class="line" style="height:20px">29</span><span class="line" style="height:20px">30</span><span class="line" style="height:20px">31</span><span class="line" style="height:20px">32</span><span class="line" style="height:20px">33</span><span class="line" style="height:20px">34</span><span class="line" style="height:20px">35</span><span class="line" style="height:20px">36</span><span class="line" style="height:20px">37</span><span class="line" style="height:20px">38</span><span class="line" style="height:20px">39</span><span class="line" style="height:20px">40</span><span class="line" style="height:20px">41</span><span class="line" style="height:20px">42</span><span class="line" style="height:20px">43</span><span class="line" style="height:20px">44</span><span class="line" style="height:20px">45</span><span class="line" style="height:20px">46</span><span class="line" style="height:20px">47</span><span class="line" style="height:20px">48</span><span class="line" style="height:20px">49</span><span class="line" style="height:20px">50</span><span class="line" style="height:20px">51</span><span class="line" style="height:20px">52</span><span class="line" style="height:20px">53</span><span class="line" style="height:20px">54</span><span class="line" style="height:20px">55</span><span class="line" style="height:20px">56</span><span class="line" style="height:20px">57</span><span class="line" style="height:20px">58</span><span class="line" style="height:20px">59</span><span class="line" style="height:20px">60</span><span class="line" style="height:20px">61</span><span class="line" style="height:20px">62</span><span class="line" style="height:20px">63</span><span class="line" style="height:20px">64</span><span class="line" style="height:20px">65</span><span class="line" style="height:20px">66</span><span class="line" style="height:20px">67</span><span class="line" style="height:20px">68</span><span class="line" style="height:20px">69</span><span class="line" style="height:20px">70</span><span class="line" style="height:20px">71</span><span class="line" style="height:20px">72</span><span class="line" style="height:20px">73</span><span class="line" style="height:20px">74</span><span class="line" style="height:20px">75</span><span class="line" style="height:20px">76</span><span class="line" style="height:20px">77</span><span class="line" style="height:20px">78</span><span class="line" style="height:20px">79</span><span class="line" style="height:20px">80</span><span class="line" style="height:20px">81</span><span class="line" style="height:20px">82</span><span class="line" style="height:20px">83</span><span class="line" style="height:20px">84</span><span class="line" style="height:20px">85</span><span class="line" style="height:20px">86</span><span class="line" style="height:20px">87</span><span class="line" style="height:20px">88</span><span class="line" style="height:20px">89</span><span class="line" style="height:20px">90</span><span class="line" style="height:20px">91</span><span class="line" style="height:20px">92</span><span class="line" style="height:20px">93</span><span class="line" style="height:20px">94</span><span class="line" style="height:20px">95</span><span class="line" style="height:20px">96</span><span class="line" style="height:20px">97</span><span class="line" style="height:20px">98</span><span class="line" style="height:20px">99</span><span class="line" style="height:20px">100</span><span class="line" style="height:20px">101</span><span class="line" style="height:20px">102</span></pre></td><td class="code" style="padding:0px; vertical-align:middle; border:none"><pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin-top: 0px; margin-bottom: 0px; padding: 1px; color: rgb(197, 200, 198); background-color: rgb(29, 31, 33); line-height: 1.6; border: none; -webkit-user-select: auto;" data-index="23" class="" name="code"><span class="line" style="height:20px">@Override</span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">public</span> <span class="keyword" style="color:rgb(178,148,187)">void</span> onDraw(Canvas canvas) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (isInEditMode()) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> Rect frame = mFrameRect;</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">if</span> (frame == <span class="keyword" style="color:rgb(178,148,187)">null</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">return</span>;</span><span class="line" style="height:20px"> }</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">width</span> = canvas.getWidth();</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> <span class="variable" style="color:rgb(204,102,102)">height</span> = canvas.getHeight();</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 绘制焦点框外边的暗色背景</span></span><span class="line" style="height:20px"> mPaint.setColor(mMaskColor);</span><span class="line" style="height:20px"> canvas.drawRect(<span class="number" style="color:rgb(181,189,104)">0</span>, <span class="number" style="color:rgb(181,189,104)">0</span>, <span class="variable" style="color:rgb(204,102,102)">width</span>, frame.top, mPaint);</span><span class="line" style="height:20px"> canvas.drawRect(<span class="number" style="color:rgb(181,189,104)">0</span>, frame.top, frame.left, frame.bottom + <span class="number" style="color:rgb(181,189,104)">1</span>, mPaint);</span><span class="line" style="height:20px"> canvas.drawRect(frame.right + <span class="number" style="color:rgb(181,189,104)">1</span>, frame.top, <span class="variable" style="color:rgb(204,102,102)">width</span>, frame.bottom + <span class="number" style="color:rgb(181,189,104)">1</span>, mPaint);</span><span class="line" style="height:20px"> canvas.drawRect(<span class="number" style="color:rgb(181,189,104)">0</span>, frame.bottom + <span class="number" style="color:rgb(181,189,104)">1</span>, <span class="variable" style="color:rgb(204,102,102)">width</span>, <span class="variable" style="color:rgb(204,102,102)">height</span>, mPaint);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> drawFocusRect(canvas, frame);</span><span class="line" style="height:20px"> drawAngle(canvas, frame);</span><span class="line" style="height:20px"> drawText(canvas, frame);</span><span class="line" style="height:20px"> drawLaser(canvas, frame);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// Request another update at the animation interval, but only repaint the laser line,</span></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// not the entire viewfinder mask.</span></span><span class="line" style="height:20px"> postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);</span><span class="line" style="height:20px">}</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * 画聚焦框,白色的</span><span class="line" style="height:20px"> * </span><span class="line" style="height:20px"> * @param canvas</span><span class="line" style="height:20px"> * @param rect</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">void</span> drawFocusRect(Canvas canvas, Rect <span class="built_in" style="color:rgb(222,147,95)">rect</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 绘制焦点框(黑色)</span></span><span class="line" style="height:20px"> mPaint.setColor(mFrameColor);</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 上</span></span><span class="line" style="height:20px"> canvas.drawRect(<span class="built_in" style="color:rgb(222,147,95)">rect</span>.left + mAngleLength, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.right - mAngleLength, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top + mFocusThick, mPaint);</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 左</span></span><span class="line" style="height:20px"> canvas.drawRect(<span class="built_in" style="color:rgb(222,147,95)">rect</span>.left, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top + mAngleLength, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.left + mFocusThick, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.bottom - mAngleLength,</span><span class="line" style="height:20px"> mPaint);</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 右</span></span><span class="line" style="height:20px"> canvas.drawRect(<span class="built_in" style="color:rgb(222,147,95)">rect</span>.right - mFocusThick, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top + mAngleLength, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.right, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.bottom - mAngleLength,</span><span class="line" style="height:20px"> mPaint);</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 下</span></span><span class="line" style="height:20px"> canvas.drawRect(<span class="built_in" style="color:rgb(222,147,95)">rect</span>.left + mAngleLength, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.bottom - mFocusThick, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.right - mAngleLength, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.bottom,</span><span class="line" style="height:20px"> mPaint);</span><span class="line" style="height:20px">}</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="comment" style="color:rgb(150,152,150)">/**</span><span class="line" style="height:20px"> * 画粉色的四个角</span><span class="line" style="height:20px"> * </span><span class="line" style="height:20px"> * @param canvas</span><span class="line" style="height:20px"> * @param rect</span><span class="line" style="height:20px"> */</span></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">void</span> drawAngle(Canvas canvas, Rect <span class="built_in" style="color:rgb(222,147,95)">rect</span>) {<!-- --></span><span class="line" style="height:20px"> mPaint.setColor(mLaserColor);</span><span class="line" style="height:20px"> mPaint.setAlpha(OPAQUE);</span><span class="line" style="height:20px"> mPaint.setStyle(Paint.Style.FILL);</span><span class="line" style="height:20px"> mPaint.setStrokeWidth(mAngleThick);</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> left = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.left;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> top = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> right = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.right;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> bottom = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.bottom;</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 左上角</span></span><span class="line" style="height:20px"> canvas.drawRect(left, top, left + mAngleLength, top + mAngleThick, mPaint);</span><span class="line" style="height:20px"> canvas.drawRect(left, top, left + mAngleThick, top + mAngleLength, mPaint);</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 右上角</span></span><span class="line" style="height:20px"> canvas.drawRect(right - mAngleLength, top, right, top + mAngleThick, mPaint);</span><span class="line" style="height:20px"> canvas.drawRect(right - mAngleThick, top, right, top + mAngleLength, mPaint);</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 左下角</span></span><span class="line" style="height:20px"> canvas.drawRect(left, bottom - mAngleLength, left + mAngleThick, bottom, mPaint);</span><span class="line" style="height:20px"> canvas.drawRect(left, bottom - mAngleThick, left + mAngleLength, bottom, mPaint);</span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 右下角</span></span><span class="line" style="height:20px"> canvas.drawRect(right - mAngleLength, bottom - mAngleThick, right, bottom, mPaint);</span><span class="line" style="height:20px"> canvas.drawRect(right - mAngleThick, bottom - mAngleLength, right, bottom, mPaint);</span><span class="line" style="height:20px">}</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">void</span> drawText(Canvas canvas, Rect <span class="built_in" style="color:rgb(222,147,95)">rect</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> margin = <span class="number" style="color:rgb(181,189,104)">40</span>;</span><span class="line" style="height:20px"> mPaint.setColor(mTextColor);</span><span class="line" style="height:20px"> mPaint.setTextSize(getResources().getDimension(R.dimen.text_size_13sp));</span><span class="line" style="height:20px"> <span class="keyword" style="color:rgb(178,148,187)">String</span> <span class="built_in" style="color:rgb(222,147,95)">text</span> = getResources().getString(R.string.qr_code_auto_scan_notification);</span><span class="line" style="height:20px"> Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">float</span> fontTotalHeight = fontMetrics.bottom - fontMetrics.top;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">float</span> offY = fontTotalHeight / <span class="number" style="color:rgb(181,189,104)">2</span> - fontMetrics.bottom;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">float</span> newY = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.bottom + margin + offY;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">float</span> left = (ScreenUtils.getScreenWidth(mContext) - mPaint.getTextSize() * <span class="built_in" style="color:rgb(222,147,95)">text</span>.length()) / <span class="number" style="color:rgb(181,189,104)">2</span>;</span><span class="line" style="height:20px"> canvas.drawText(<span class="built_in" style="color:rgb(222,147,95)">text</span>, left, newY, mPaint);</span><span class="line" style="height:20px">}</span><span class="line" style="height:20px"></span><span class="line" style="height:20px"><span class="keyword" style="color:rgb(178,148,187)">private</span> <span class="keyword" style="color:rgb(178,148,187)">void</span> drawLaser(Canvas canvas, Rect <span class="built_in" style="color:rgb(222,147,95)">rect</span>) {<!-- --></span><span class="line" style="height:20px"> <span class="comment" style="color:rgb(150,152,150)">// 绘制焦点框内固定的一条扫描线(红色)</span></span><span class="line" style="height:20px"> mPaint.setColor(mLaserColor);</span><span class="line" style="height:20px"> mPaint.setAlpha(SCANNER_ALPHA[mScannerAlpha]);</span><span class="line" style="height:20px"> mScannerAlpha = (mScannerAlpha + <span class="number" style="color:rgb(181,189,104)">1</span>) % SCANNER_ALPHA.length;</span><span class="line" style="height:20px"> <span class="built_in" style="color:rgb(222,147,95)">int</span> middle = <span class="built_in" style="color:rgb(222,147,95)">rect</span>.<span class="variable" style="color:rgb(204,102,102)">height</span>() / <span class="number" style="color:rgb(181,189,104)">2</span> + <span class="built_in" style="color:rgb(222,147,95)">rect</span>.top;</span><span class="line" style="height:20px"> canvas.drawRect(<span class="built_in" style="color:rgb(222,147,95)">rect</span>.left + <span class="number" style="color:rgb(181,189,104)">2</span>, middle - <span class="number" style="color:rgb(181,189,104)">1</span>, <span class="built_in" style="color:rgb(222,147,95)">rect</span>.right - <span class="number" style="color:rgb(181,189,104)">1</span>, middle + <span class="number" style="color:rgb(181,189,104)">2</span>, mPaint);</span><span class="line" style="height:20px"></span><span class="line" style="height:20px">}</span></pre></td></tr></tbody></table>## 总结<p>使用zxing进行二维码的编解码是非常方便的,zxing的API覆盖了多种主流编程语言,具有良好的扩展性和可定制性。文中进行了二维码基本功能介绍,zxing项目基本使用方法,zxing项目中目前存在的缺点及改进方案,以及自己在进行zxing项目二次开发的摸索过程中总结出的提高二维码扫描的方法。文中还有许多不足的地方,对源码的理解还不够深,特别是二维码解析关键算法(<code>GlobalHistogramBinarizer</code>和<code>HybridBinarizer</code>)。这些算法需要投入额外的时间去理解,对于目前以业务为导向的App开发来说,还存在优化的空间,期待将来有一天能像微信的二维码扫描一样快速,精确。</p>]]></content>
</entry>
<entry>
<title>「数学」Dandelin spheres 更好的理解椭圆</title>
<link href="/2022/11/06/Dandelin-spheres/"/>
<url>/2022/11/06/Dandelin-spheres/</url>
<content type="html"><![CDATA[<ul><li><p>Dandelin spheres</p><blockquote><p>对于椭圆,并不陌生</p><p>我大概简单梳理了一下大概有三种定义</p><ol><li>从圆对与xy轴的变换</li><li>一条绳子通过两个图钉进行绘画</li><li>圆锥的切面</li></ol></blockquote><p>这三个定义之间有什么样的联系我们需要去思考</p><h2 id="所以为什么圆锥的切面就会是椭圆呢?"><a href="#所以为什么圆锥的切面就会是椭圆呢?" class="headerlink" title="所以为什么圆锥的切面就会是椭圆呢?"></a>所以为什么圆锥的切面就会是椭圆呢?</h2><p>在这里我们引入:丹德林球体</p><p>主要条件无不是创建一个相切的条件</p><p><a href="https://en.wikipedia.org/wiki/File:Dandelin_spheres.svg"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Dandelin_spheres.svg/330px-Dandelin_spheres.svg.png" alt="img"></a></p><h3 id="解决本题的关键是什么呢?"><a href="#解决本题的关键是什么呢?" class="headerlink" title="解决本题的关键是什么呢?"></a>解决本题的关键是什么呢?</h3><p>主要是根据椭圆的其他定义,连线相加是一个固定值。</p><p><strong>所以我们的关键是:「于变化中寻找不变量」</strong></p><h3 id="何谓不变量?"><a href="#何谓不变量?" class="headerlink" title="何谓不变量?"></a>何谓不变量?</h3><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221106202146068.png" alt="image-20221106202146068"></p><h3 id="所以我们需要寻找一种方法将椭圆的“图钉连线”转换到圆锥的侧面上。"><a href="#所以我们需要寻找一种方法将椭圆的“图钉连线”转换到圆锥的侧面上。" class="headerlink" title="所以我们需要寻找一种方法将椭圆的“图钉连线”转换到圆锥的侧面上。"></a>所以我们需要寻找一种方法将椭圆的“图钉连线”转换到圆锥的侧面上。</h3><p>这时候相切条件就非常重要了</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221106203150231.png" alt="image-20221106203150231"></p><h4 id="严谨的解释如下:"><a href="#严谨的解释如下:" class="headerlink" title="严谨的解释如下:"></a>严谨的解释如下:</h4><p>设 S 为此圆锥的顶点,平面 <em>e</em> 与此圆锥交于曲线 <em>C</em>(蓝色区域)。 以下则证明 <em>C</em> 是椭圆。</p><p>放置两个棕色的丹德林球<em>G</em>1 和 <em>G</em>2,皆与平面和圆锥相交,上面的为<em>G</em>1,下面的为<em>G</em>2。 而两个球体与锥体相切的点形成圆形(白色的部分),分别记为k1 and k2。</p><p>将 <em>G</em>1 与此平面的切点记为 <em>F</em>1 ;类似地,用于<em>G</em>2 与<em>F</em>2。<em>P</em> 为曲线 <em>C</em> 上一点 。</p><p><em>需要证明</em>:当 <em>P</em> 沿着截面曲线 <em>C</em> 移动时,d(P,F1)+d(P,F2) 仍是定值(椭圆的定义之一)。</p><ul><li><p>将 <em>P</em> 与圆锥顶点 <em>S</em> 作一直线,与 <em>G</em>1 和 <em>G</em>2 分别交于 <em>P</em>1 和 <em>P</em>2 。</p></li><li><p>将 <em>P</em> 移动时,<em>P</em>1 和 <em>P</em>2 则沿着两个圆移动,且其距离 d(P1,P2) 是定值。</p></li><li><p><em>P</em> 和 <em>F</em>1 的距离会等同于 <em>P</em> 到 <em>P</em>1 的距离,因为线段 | <em>PF</em>1 and <em>PP</em>1 都相切于<em>G</em>1。</p></li><li><p>基于对称性,<em>P</em> 到 <em>F</em>2 的距离,等于 <em>P</em> 到 <em>P</em>2 的距离,因为线段 | <em>PF</em>2 和 <em>PP</em>2 都<a href="https://zh.wikipedia.org/wiki/%E7%9B%B8%E5%88%87">相切</a>于<em>G</em>2</p></li><li><p>于是,我们计算出其距离和 d(P,F1)+d(P,F2) = d(P,P1)+d(P,P2) = d(P1,P2) 是定值。</p></li></ul></li></ul>]]></content>
<tags>
<tag> 数学 </tag>
</tags>
</entry>
<entry>
<title>「密码学」二维码与RS码</title>
<link href="/2022/11/06/RS%E7%A0%81/"/>
<url>/2022/11/06/RS%E7%A0%81/</url>
<content type="html"><![CDATA[<h2 id="译-为程序员写的Reed-Solomon码解释-Felix021-So-far-so-good"><a href="#译-为程序员写的Reed-Solomon码解释-Felix021-So-far-so-good" class="headerlink" title="[译] 为程序员写的Reed-Solomon码解释 - Felix021 - So far so good"></a>[<a href="https://www.felix021.com/blog/read.php?2116">译] 为程序员写的Reed-Solomon码解释 - Felix021 - So far so good</a></h2><blockquote><p>一点阅读过程中有点感触就想写点</p></blockquote><h2 id="RS码的历史"><a href="#RS码的历史" class="headerlink" title="RS码的历史"></a>RS码的历史</h2><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030222511963.png" alt="image-20221030222511963"></p><h2 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h2><p>看RS码主要是再github上那个zxing生成二维码的项目</p><p>看源码的时候遇到了较大的困难,主要来自数学层面,于是到互联网上搜集资料找到了这一篇</p><h2 id="从程序员的视角"><a href="#从程序员的视角" class="headerlink" title="从程序员的视角"></a>从程序员的视角</h2><h4 id="QR码结构"><a href="#QR码结构" class="headerlink" title="QR码结构"></a>QR码结构</h4><p>在角落的3个方形定位器模式是QR码的典型可见特征</p><p><img src="https://upload-images.jianshu.io/upload_images/3071283-cae1182d137db6d6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/368/format/webp" alt="img"></p><h3 id="掩码"><a href="#掩码" class="headerlink" title="掩码"></a>掩码</h3><p>掩码处理:逆转某些模块(白色变成黑色,黑色变成白色),保留其他模块不变。</p><p>目的:为了避免数据区域中出现诸如类似定位器模式的形状,或者是大片的空白区域等,可能会使扫描器混淆、错乱。</p><p><img src="https://upload-images.jianshu.io/upload_images/3071283-d1927f454c1996b1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/696/format/webp" alt="img"></p><p>红色区域使用一个固定的掩码模式编码保存了数据区域(黑白部分)的掩码格式信息。</p><blockquote><p>其实可以理解成,掩码就是一个有固定格式的点阵图,点阵图上的标记可以让黑白进行转换</p></blockquote><h4 id="掩码使用什么操作"><a href="#掩码使用什么操作" class="headerlink" title="掩码使用什么操作"></a>掩码使用什么操作</h4><p>使用异或运算(XOR,eXclusive-or,通常在变成语言中用 ^ 来表示)</p><h4 id="具体是怎么样的"><a href="#具体是怎么样的" class="headerlink" title="具体是怎么样的"></a>具体是怎么样的</h4><ol><li><p>逆时针读取左上角的定位器模式</p></li><li><p>得到下面的比特序列,白色表示0,黑色表示1</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Input 101101101001011</span><br><span class="line">Mask ^ 101010000010010</span><br><span class="line">Output 000111101011001</span><br></pre></td></tr></table></figure></li></ol><h5 id="格式信息"><a href="#格式信息" class="headerlink" title="格式信息"></a>格式信息</h5><blockquote><p>格式信息有另一份可辨别的副本,因此即使其中一份被毁坏,也仍然有机会被识别</p></blockquote><p>副本被分成两个部分,分别放在另外两个定位器的边上,同样也是逆时针方向阅读(沿着左下角定位器往上,然后是右上角定位器边缘从左往右)。</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027210323174.png" alt="image-20221027210323174"></p><h4 id="格式信息的前2-bits-给出了用于数据的纠错级别。"><a href="#格式信息的前2-bits-给出了用于数据的纠错级别。" class="headerlink" title="格式信息的前2 bits 给出了用于数据的纠错级别。"></a>格式信息的前2 <em>bits</em> 给出了用于数据的纠错级别。</h4><p>这个尺寸的QR码包含26字节(<em>bytes</em>,1 <em>byte</em> = 8 <em>bits</em> )信息,其中一些用于保存原数据,一些用于保存校验码,如下表所示。左边第一列只是给纠错级别起了个简单的名字。</p><table><thead><tr><th align="center">纠错级别</th><th align="center">级别指示器</th><th align="center">纠错码字节数</th><th align="center">原数据字节数</th></tr></thead><tbody><tr><td align="center">L</td><td align="center">01</td><td align="center">7</td><td align="center">19</td></tr><tr><td align="center">M</td><td align="center">00</td><td align="center">10</td><td align="center">16</td></tr><tr><td align="center">Q</td><td align="center">11</td><td align="center">13</td><td align="center">13</td></tr><tr><td align="center">H</td><td align="center">10</td><td align="center">17</td><td align="center">9</td></tr></tbody></table><h4 id="格式信息中的接下来3-bits用于指定对数据区域使用的掩码模式。"><a href="#格式信息中的接下来3-bits用于指定对数据区域使用的掩码模式。" class="headerlink" title="格式信息中的接下来3 bits用于指定对数据区域使用的掩码模式。"></a>格式信息中的接下来3 <em>bits</em>用于指定对数据区域使用的掩码模式。</h4><p>掩码模式使用6*6方格,根据需要覆盖区域进行掩码计算</p><p>下方的计算式i,j分别表示行列(从左上角算起)</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027201918347.png" alt="image-20221027201918347"></p><h4 id="格式信息中剩下的10-bits-是用于对格式信息本身的错误校验"><a href="#格式信息中剩下的10-bits-是用于对格式信息本身的错误校验" class="headerlink" title="格式信息中剩下的10 bits 是用于对格式信息本身的错误校验"></a>格式信息中剩下的10 <em>bits</em> 是用于对格式信息本身的错误校验</h4><h2 id="数据"><a href="#数据" class="headerlink" title="数据"></a>数据</h2><h3 id="反掩码操作后的的图样"><a href="#反掩码操作后的的图样" class="headerlink" title="反掩码操作后的的图样"></a>反掩码操作后的的图样</h3><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027202239375.png" alt="image-20221027202239375"></p><h3 id="数据如何读取"><a href="#数据如何读取" class="headerlink" title="数据如何读取"></a>数据如何读取</h3><h4 id="从右下角开始,沿着最右边的两列向上走“之”字形"><a href="#从右下角开始,沿着最右边的两列向上走“之”字形" class="headerlink" title="从右下角开始,沿着最右边的两列向上走“之”字形"></a>从右下角开始,沿着最右边的两列向上走“之”字形</h4><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027202421447.png" alt="image-20221027202421447"></p><p>前三个字节分别是 01000000 11010010 01110101</p><p>一个字节Bytes=8bit</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027202459121.png" alt="image-20221027202459121"></p><h4 id="接下来两列从上向下读取,当读取到底部后,再反过来从下往上读取接下来两列"><a href="#接下来两列从上向下读取,当读取到底部后,再反过来从下往上读取接下来两列" class="headerlink" title="接下来两列从上向下读取,当读取到底部后,再反过来从下往上读取接下来两列"></a>接下来两列从上向下读取,当读取到底部后,再反过来从下往上读取接下来两列</h4><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027202701684.png" alt="image-20221027202701684"></p><h4 id="纠错码读取方式和原来一样"><a href="#纠错码读取方式和原来一样" class="headerlink" title="纠错码读取方式和原来一样"></a>纠错码读取方式和原来一样</h4><p>一直读到最左边的列</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027202759707.png" alt="image-20221027202759707"></p><h4 id="十六进制表示的数据:"><a href="#十六进制表示的数据:" class="headerlink" title="十六进制表示的数据:"></a>十六进制表示的数据:</h4><p>进制转换</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027203047352.png" alt="image-20221027203047352"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">二进制:</span><br><span class="line">原始信息:</span><br><span class="line">0100000011010010011101010100--7 0111011101100001011100110010--7</span><br><span class="line">011000100111001001101001--6</span><br><span class="line">011011000110110001101001--6</span><br><span class="line">01100111000011101100--5</span><br><span class="line"></span><br><span class="line">错误纠正:001010101001000000010011011010111010111111101111111111000000000000000000....</span><br><span class="line">原始信息: 40 d2 75 47 76 17 32 06 27 26 96 c6 c6 96 70 ec</span><br><span class="line">错误纠正: bc 2a 90 13 6b af ef fd 4b e0</span><br></pre></td></tr></table></figure><h2 id="解码"><a href="#解码" class="headerlink" title="解码"></a>解码</h2><h3 id="将信息解码成可读格式"><a href="#将信息解码成可读格式" class="headerlink" title="将信息解码成可读格式"></a>将信息解码成可读格式</h3><p>前4 <em>bits</em> 指明了信息是如何编码的</p><h4 id="QR码的编码方案"><a href="#QR码的编码方案" class="headerlink" title="QR码的编码方案"></a>QR码的编码方案</h4><table><thead><tr><th align="center">方案名称</th><th align="center">模式指示器</th><th align="center">长度字节数</th><th align="center">数据字节数</th></tr></thead><tbody><tr><td align="center">数字</td><td align="center">0001</td><td align="center">10</td><td align="center">10 <em>bits</em> per 3 digits</td></tr><tr><td align="center">字母数字</td><td align="center">0010</td><td align="center">9</td><td align="center">11 <em>bits</em> per 2 characters</td></tr><tr><td align="center">字节</td><td align="center">0100</td><td align="center">8</td><td align="center">8 <em>bits</em> per character</td></tr><tr><td align="center">汉字</td><td align="center">1000</td><td align="center">8</td><td align="center">13 <em>bits</em> per character</td></tr></tbody></table><p>我们的样例数据开头是 0100表明接下来是每个字符8 <em>bits</em>,接下来8 <em>bits</em> 是长度字段</p><p>00001101——-转为10进制——-13(8+4+1)</p><p>表明有13个字符之后才是数据字符</p><p>前两个是00100111和01010100(对于ASCII字符 ‘ 和 T)</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027204733677.png" alt="image-20221027204733677"></p><p>使用微信扫扫看</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/de349945566f64b9a25c4d344414d84.jpg" alt="de349945566f64b9a25c4d344414d84"></p><p><strong>验证了对于ASCII字符 ‘ 和 T以及一共13个字符</strong></p><p>在数据 <em>bit</em> 之后是另外一个4 <em>bit</em> 模式指示器</p><p>可以跟前一个不同,从而允许在一个QR码中混合多个编码方案。如果没有其他数据了,用 0000 来标记结尾(注意,标准允许忽略这个标记,如果存储空间不够的话)。</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027210212414.png" alt="image-20221027210212414"></p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>总结一下:从二维码的视觉识别方法到RS码到BCH码,是一个编解码方法逐步追求本质的过程,下一节内容是关于BCH码以及Hamming code的详细分析,欢迎各位阅读。</p>]]></content>
<tags>
<tag> 密码学 </tag>
</tags>
</entry>
<entry>
<title>「密码学」BCH与HammingCode</title>
<link href="/2022/11/06/BCH%E4%B8%8EHammingCode/"/>
<url>/2022/11/06/BCH%E4%B8%8EHammingCode/</url>
<content type="html"><![CDATA[<p><strong>Bose–Chaudhuri–Hocquenghem codes</strong></p><p>BCH代码是里德- 所罗门代码的推广</p><h3 id="我们可以尝试把二进制数表示为多项式"><a href="#我们可以尝试把二进制数表示为多项式" class="headerlink" title="我们可以尝试把二进制数表示为多项式"></a>我们可以尝试把二进制数表示为多项式</h3><p>例如11011表示成为<br>$$<br>1+x+x^3+x^4<br>$$</p><p>计算11*11,在多项式表示<br>$$<br>(1+x)∗(1+x)=1+2∗x+x^2=1+x^2<br>$$<br>这儿的x的系数2在二进制中等于0</p><p>另外很重要的概念就是二进制域中,加等于减<br>$$<br>x^2+1 =0相当于x^2 = 1<br>$$</p><h6 id="模2运算"><a href="#模2运算" class="headerlink" title="模2运算"></a>模2运算</h6><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027220342073.png" alt="image-20221027220342073"></p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027220743056.png" alt="image-20221027220743056"></p><h3 id="BCH的出现"><a href="#BCH的出现" class="headerlink" title="BCH的出现"></a>BCH的出现</h3><h4 id="多位错误"><a href="#多位错误" class="headerlink" title="多位错误"></a>多位错误</h4><p>我们先回顾简单的奇偶校验码和hamming码。简单的奇偶校验码只能检查出错误而不知道具体是哪里出错,而hamming码只能纠正一位错误。因此我们想能不能有一种方法可以纠正多位错误呢?</p><ol><li>假如我们的真正的消息是m(x)</li><li>乘上一个编码多项式p(x),</li><li>得到m(x)p(x)再将其发送过去。</li><li>多项式被加上错误多项式e(x),</li><li>接收者接收者的消息为c(x)</li></ol><p>$$<br>c(x)=m(x)p(x)+e(x)<br>$$</p><h4 id="纠单个错方法"><a href="#纠单个错方法" class="headerlink" title="纠单个错方法"></a>纠单个错方法</h4><h5 id="前提"><a href="#前提" class="headerlink" title="前提"></a>前提</h5><p><strong>p(x)必须是不可约的本原多项式(primitive polynomials)</strong></p><h5 id="寻找本原多项式"><a href="#寻找本原多项式" class="headerlink" title="寻找本原多项式"></a>寻找本原多项式</h5><blockquote><p>让e(x)不被除尽</p></blockquote><ul><li><p>r次多项式,最高次项x^r的系数必须是1。</p></li><li><p>多项式如果不包含常数项1,就会被x整除。</p></li><li><p>多项式项数不能是偶数的,比如<br>$$<br>1 + x + x^2 + x^41 + x + x^2 + x^4<br>$$<br>有四项,很容易将其分解为<br>$$<br>(1 + x)(1 + x^2)(1 + x)(1 + x^2)<br>$$</p></li><li><p>每一项的次数也不能都是偶数,否则将每一项次数减半就能得到因子。例如<br>$$<br>1 + x^2 + x^4 = (1 + x + x^2)^2<br>$$</p></li></ul><p>和发送者商量好p(x)</p><p>让c(x)除以p(x),</p><ol><li><p>如果余项是0,即没有e(x),没有受到干扰,那么商就是m(x),就是正确的消息。</p></li><li><p>如果余项不是零,我们的商就变成了m(x) + e(x)/p(x),无法将真正的消息分离出来。</p><h5 id="本原多项式"><a href="#本原多项式" class="headerlink" title="本原多项式"></a><strong>本原多项式</strong></h5></li></ol><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-44b203b9f80b2a857fca1aa92f787c53_720w.webp" alt="img"></p><h4 id="纠正多个错误"><a href="#纠正多个错误" class="headerlink" title="纠正多个错误"></a>纠正多个错误</h4><h5 id="BCH码"><a href="#BCH码" class="headerlink" title="BCH码"></a>BCH码</h5><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-bb2cbac64a88307e27de57009bee91e4_720w.webp" alt="img"></p><ol><li>p(x)是本原多项式</li><li>p3(x3)…都是可以被p(x)除余0的多项式</li></ol><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-b1b0631c114f9b8dcc75381133c3c1b6_720w.webp" alt="img"></p><h5 id="可以纠正两个错误的编码多项式"><a href="#可以纠正两个错误的编码多项式" class="headerlink" title="可以纠正两个错误的编码多项式"></a>可以纠正两个错误的编码多项式</h5><p>$$<br>Q(x) = p(x)p3(x)<br>$$</p><h5 id="纠正三个错误的编码多项式"><a href="#纠正三个错误的编码多项式" class="headerlink" title="纠正三个错误的编码多项式"></a>纠正三个错误的编码多项式</h5><p>$$<br>Q(x) = p(x)p3(x)p5(x)<br>$$</p><p>eg.纠正两个错误<br>$$<br>p(x) = 1 + x + x^4<br>$$<br>可以看出<br>$$<br>(x^6 + x^9 + x^12) = 1 + x^3 (mod \space p(x))<br>$$<br>模二除法</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/0ef1910781ec28df9c0c7af16019a89.jpg" alt="0ef1910781ec28df9c0c7af16019a89"></p><p>得1001余数就是1 + x^3</p><p>将1+x3移到左边<br>$$<br>p3(x) = 1 + x + x^2 + x^3 + x^4<br>$$<br>以此为方法可以得出<br>$$<br>p5(x) = 1 + x + x^2<br>$$</p><h6 id="编码多项式如下"><a href="#编码多项式如下" class="headerlink" title="编码多项式如下"></a>编码多项式如下</h6><p>$$<br>Q(x) = p(x)p3(x)p5(x) = ( 1 + x + x^4 )( 1+x + x^2 + x^3 + x^4 )(1 + x + x^2)= 1 + x^2 + x^3 + x^4 + x^5 + x^8 + x^10<br>$$</p><p>表示成二进制是11101100101</p><p>再乘上消息m(x)就是100001110110010,就是我们发送的出去的</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-f9d7c6758ad7dd91ffb34ad2d04206ff_r.jpg"></p><h6 id="设:现在接收者受到的r-x-却是-101000110110010"><a href="#设:现在接收者受到的r-x-却是-101000110110010" class="headerlink" title="设:现在接收者受到的r(x)却是 101000110110010"></a>设:现在接收者受到的r(x)却是 10<strong>1</strong>00<strong>0</strong>110110010</h6><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-7f444c31e69d826832c2a4613bf0a119_r.jpg"></p><p>前两项余项不为0,而第三项为0说明接到的只有两处错误。</p><h6 id="开始用错误定位多项式(-error-locator-polynomial-)"><a href="#开始用错误定位多项式(-error-locator-polynomial-)" class="headerlink" title="开始用错误定位多项式( error locator polynomial )"></a>开始用错误定位多项式( error locator polynomial )</h6><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-2732dbd14b7e04ce36a2b79bd5436e2e_720w.webp" alt="img"></p><ol><li>因为这里只有两个错误</li><li>所以第三个X^e3可以认为是0</li><li>找到这个函数的两个根</li></ol><h6 id="初等对称函数-Elementary-symmetric-polynomial-s"><a href="#初等对称函数-Elementary-symmetric-polynomial-s" class="headerlink" title="初等对称函数(Elementary symmetric polynomial)s"></a>初等对称函数(Elementary symmetric polynomial)s</h6><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027222713543.png" alt="image-20221027222713543"></p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-f9e699a8755d88dca5fc7173b922088e_720w.webp" alt="img"></p><p>另定义幂和对称函数( power sum symmetric functions)t,</p><blockquote><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030235433335.png" alt="image-20221030235433335"></p><p>这里主要使用了power sum symmetric functions幂和对称函数</p></blockquote><h2 id="power-sum-symmetric-functions幂和对称函数"><a href="#power-sum-symmetric-functions幂和对称函数" class="headerlink" title="power sum symmetric functions幂和对称函数"></a>power sum symmetric functions幂和对称函数</h2><blockquote><p>[Symmetric functions Monomial symmetric functions Elementary symmetric functions](<a href="https://www.symmetricfunctions.com/standardSymmetricFunctions.htm#:~:text=Powersum">https://www.symmetricfunctions.com/standardSymmetricFunctions.htm#:~:text=Powersum</a> symmetric functions The powersum symmetric functions are,an orthogonal basis for the Hall inner product.)</p></blockquote><h2 id="Symmetric-functions对称函数"><a href="#Symmetric-functions对称函数" class="headerlink" title="Symmetric functions对称函数"></a>Symmetric functions对称函数</h2><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031000232255.png" alt="image-20221031000232255"></p><p>对于任意排列的w∈Sn<br>$$<br>f(x1,x2,…,xn)=f(xw(1),xw(2),…,xw(n))<br>$$</p><h2 id="Monomial-symmetric-functions单项式对称函数"><a href="#Monomial-symmetric-functions单项式对称函数" class="headerlink" title="Monomial symmetric functions单项式对称函数"></a>Monomial symmetric functions单项式对称函数</h2><p>对于一个范围的λ我们定义其函数为</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031001006131.png" alt="image-20221031001006131"></p><p>如果<img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031001033532.png" alt="image-20221031001033532">是<img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031000934322.png" alt="image-20221031000934322">范围的一部分,那么就可以定义其为augmented monomial symmetric functions</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031001152122.png" alt="image-20221031001152122"></p><p>where</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031001205480.png" alt="image-20221031001205480"></p><p>更多请看此链接<a href="http://dx.doi.org/10.1186/s40064-015-1506-5">http://dx.doi.org/10.1186/s40064-015-1506-5</a></p><h2 id="Elementary-symmetric-functions"><a href="#Elementary-symmetric-functions" class="headerlink" title="Elementary symmetric functions"></a>Elementary symmetric functions</h2><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031002235040.png" alt="image-20221031002235040"></p><h2 id="Powersum-symmetric-functions"><a href="#Powersum-symmetric-functions" class="headerlink" title="Powersum symmetric functions"></a>Powersum symmetric functions</h2><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031003237660.png" alt="image-20221031003237660"></p><p>They serve as an orthogonal basis for the <a href="https://www.symmetricfunctions.com/schur.htm#schurInnerProduct">Hall inner product</a>. We have the following product expansions [Sec. 1.4, <a href="https://www.symmetricfunctions.com/standardSymmetricFunctions.htm#Macdonald1995">Mac95</a>] (see the <a href="https://www.symmetricfunctions.com/preliminaries.htm#prelimPartitionStatistics">preliminaries</a> for the definition of zλ).</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031005515331.png" alt="image-20221031005515331"></p><h5 id="proof"><a href="#proof" class="headerlink" title="proof"></a>proof</h5><p><a href="https://www.symmetricfunctions.com/standardQuasiSymmetricFunctions.htm#qPsi">https://www.symmetricfunctions.com/standardQuasiSymmetricFunctions.htm#qPsi</a></p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221031005525968.png" alt="image-20221031005525968"></p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-98ed54e945b225fe3f45cc19f58cbf37_720w.webp" alt="img"></p><p>例子中,可能有三个错误,于是可表示成:</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-bc7cffd3138d8584f92e54fdf9c579b0_720w.webp" alt="img"></p><p>我们有s与t的关系:</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-6fca53b784fc8b1a427f1c298c1d7393_720w.webp" alt="img"></p><p>此时上面的错误定位不等式就可以用s函数来描述:</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-8c9fed6bddba4647150d8a9b0eb63451_720w.webp" alt="img"></p><p>我们知道一些t的结果:</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-6a61c5f97d988257e48919574ae3fe59_720w.webp" alt="img"></p><p>再用s和t的关系计算</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-3d7405a9bb79ddd2120e0221be1d7a0d_720w.webp" alt="img"></p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/v2-38bb301de659478dcc54efc342f7dcfe_720w.webp" alt="img"></p><p>这里st之间用到了初等对称函数,相对来说求解过程比较难理解</p><h2 id="建议看原网页"><a href="#建议看原网页" class="headerlink" title="建议看原网页"></a>建议看原网页</h2><p><a href="https://math.mit.edu/~djk/18.310/18.310F04/bch_codes.html">11. BCH Codes: Constructing them and finding the Syndrome of a Message (mit.edu)</a></p><p>主要是这句</p><blockquote><p>The k-th elementary symmetric function of d elements is defined as the sum of the products of k different elements from among the d elements, combined in all possible ways. </p><p>d 元素的第 k 个基本对称函数定义为<br>从D元素中得到K个不同元素的乘积,尽可能组合在一起<br>方式。</p><p>e, the 2nd elementary function of a, b, c, d is ab+ac+ad+bc+bd+cd.</p><p>e,a,b,c,d的第二个初等函数是ab+ac+ad+bc+bd+cd。</p><p>There is a linear relationship between the elementary symmetric functions and the odd power sums, ti , of the error monomials. The coefficients, sj, 1 ≤ j ≤ k of the error locator polynomial are related to the ti ’s in the following for k odd and s0 = t0 = 1</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030235014380.png" alt="image-20221030235014380"></p></blockquote><h6 id="对称函数及初等对称函数【补】"><a href="#对称函数及初等对称函数【补】" class="headerlink" title="对称函数及初等对称函数【补】"></a>对称函数及初等对称函数【补】</h6><p>对称函数就是对称的函数(symmetric functions)</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221027224219024.png" alt="image-20221027224219024"></p><p>对称函数对加法和乘法封闭</p><h3 id="Hanming-code-implementing"><a href="#Hanming-code-implementing" class="headerlink" title="Hanming code implementing"></a>Hanming code implementing</h3><h6 id="Hamming(7,4)的硬件实现"><a href="#Hamming(7,4)的硬件实现" class="headerlink" title="Hamming(7,4)的硬件实现"></a>Hamming(7,4)的硬件实现</h6><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030223938066.png"></p><p>早期的Hamming(7,4)形式如上</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030230007921.png"></p><p>下边使用异或门的硬件实现</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030224253221.png" alt="image-20221030224253221"></p><p>这是早期的Hamming(7,4)形式</p><h6 id="汉明码理解【补】"><a href="#汉明码理解【补】" class="headerlink" title="汉明码理解【补】"></a>汉明码理解【补】</h6><p>(英文阅读)</p><p><a href="https://www.bilibili.com/video/BV1WK411N7kz/?spm_id_from=333.999.0.0&vd_source=5f8dc99b785171c1c1179ddedc4c195c">【官方双语】汉明码Pa■t1,如何克服噪■_哔哩哔哩_bilibili</a></p><h6 id="Error-correction"><a href="#Error-correction" class="headerlink" title="Error correction"></a>Error correction</h6><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028185621483.png" alt="image-20221028185621483"></p><p>we all need to be concerned about Redundancy.</p><p>balance data and redundancy.</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028190019192.png" alt="image-20221028190019192"></p><p>the hamming code having them sit in positions that are powers of 2 allows for something really elegant by the end.</p><p>Also in this picture, you will find out there’s a mild nuance for what goes on in position 0 .</p><p>from sender to receiver it will possible to have Potential noise.</p><p>Before we diving it, we need to talk about the idea which was fresh on Hamming’s mind at the time of his discovery.</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028204558420.png" alt="image-20221028204558420"></p><h5 id="Parity-check"><a href="#Parity-check" class="headerlink" title="Parity check"></a>Parity check</h5><p>For a parity check, we separate only one single bit that the sender is responsible for tuning.</p><h6 id="And-what-about-rest"><a href="#And-what-about-rest" class="headerlink" title="And what about rest?"></a>And what about rest?</h6><p>The rest will be free to carry a message.</p><h6 id="And-what-use-of-the-single-bit"><a href="#And-what-use-of-the-single-bit" class="headerlink" title="And what use of the single bit?"></a>And what use of the single bit?</h6><p>It’s to make sure the total number of 1’s in the message is an even number.</p><h6 id="How-does-it-work"><a href="#How-does-it-work" class="headerlink" title="How does it work?"></a>How does it work?</h6><p>with the noise making a single one-bit from 0 change to 1, the receiver will find the parity is odd, which is typically more helpful once you start doing math with the idea.</p><p>And this special bit that the sender uses to control the parity is called a “parity bit”</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028210257754.png" alt="image-20221028210257754"></p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028203736185.png" alt="image-20221028203736185"></p><h6 id="What-about-3-errors-or-any-other-odd-number"><a href="#What-about-3-errors-or-any-other-odd-number" class="headerlink" title="What about 3 errors, or any other odd number?"></a>What about 3 errors, or any other odd number?</h6><p>But they can know for sure that it wasn’t a 0 error.</p><p>On the other hand, if there had been 2 errors, or any even number of errors, that final count of 1’s would still be even, so the receiver can’t have full confidence that an even count necessarily means the message is error-free.</p><h6 id="Messed-up-by-only-two-bit-flips-is-pretty-weak"><a href="#Messed-up-by-only-two-bit-flips-is-pretty-weak" class="headerlink" title="Messed up by only two-bit flips is pretty weak?"></a>Messed up by only two-bit flips is pretty weak?</h6><p>But we all need to know, there is no method for error detection, or correction, that could give you 100% confidence.</p><p>why?</p><p>Because enough random noise has the ability to change one valid message into another valid message.</p><p>Instead, the goal is to come up with a scheme that’s robust up to a certain maximum number of errors.</p><h6 id="Identify-where-the-error-happened"><a href="#Identify-where-the-error-happened" class="headerlink" title="Identify where the error happened."></a>Identify where the error happened.</h6><p>Let’s take this(4*4)image as an example ,we divide the original image into 4 parts,4 parts have it’s own redundant code.</p><p>The four redundant codes distinguish the rows and columns separately.</p><p>Just enjoy taking a moment to convince yourself that the answsers four parts really will always let you pin down a specific position.</p><p>If you look carefully here, you might find the connection between these question and binary counting.</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028211738256.png" alt="image-20221028211738256"></p><h6 id="17th-outcome"><a href="#17th-outcome" class="headerlink" title="17th outcome"></a>17th outcome</h6><p>You see, with four yes or no questions, we have 16 possible outcomes for our parity checks.</p><p>下边内容相对来说比较难理解,还是用中文表达了</p><blockquote><h6 id="第17种可能–没错误的情形"><a href="#第17种可能–没错误的情形" class="headerlink" title="第17种可能–没错误的情形"></a>第17种可能–没错误的情形</h6><p>如果我们四位奇偶校验全部通过,没有错误,那这种情形怎么办?</p><p>因为我们前边四个冗余码成功的奇偶校验了4*4个方格的位置,也就是16种有一个位置发生错误的情况,那我们这个数据如果没有错误的这个情况用什么表示?</p><p>解决方案异常简单,就直接忽略0位</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028213513415.png" alt="image-20221028213513415"></p><p>就是说我们只用15bit的内容进行奇偶校验,11位用来携带信息,4位作为冗余的控制位</p><p>这就是业内人士说的(15,11)汉明码</p><p>扩展汉明码(Extend Hamming Code)</p><p>如果我们使用这个第一位进行一个新的奇偶校验位,那我们就可以检测出2两个错误位,但是不能修复他</p><h6 id="实际信息"><a href="#实际信息" class="headerlink" title="实际信息"></a>实际信息</h6><p>我们实际的信息通常是进行数据分割,每部分11-bit</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028214213765.png" alt="image-20221028214213765"></p><p>每个块放入一个16bit的 error-resistant 块中</p><p>eg.奇偶性为偶例子</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028214312190.png" alt="image-20221028214312190"></p><p>拍去冗余位,将数据位放入</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028214505712.png" alt="image-20221028214505712"></p><p>第一组:2^0</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028214612203.png" alt="image-20221028214612203"></p><p>第二组:2^1</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028214700338.png" alt="image-20221028214700338"></p><p>第三组:2^2</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028214738542.png" alt="image-20221028214738542"></p><p>第四组:2^3</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028215014108.png" alt="image-20221028215014108"></p><p>最后把整体0号位为偶</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028215104585.png" alt="image-20221028215104585"></p><p>思想相对来说不是很难</p><p>但是我们究其本质,是极其的优雅,将数据进行1-15的二值化,可以看出</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028220529923.png" alt="image-20221028220529923"></p><p>不同位上是否位01决定了我们的四个PART的区域</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028220621230.png" alt="image-20221028220621230"></p><p>后面我们引入异或的思想(xor)exclusive or</p><p>异或通俗理解就是进行两个的相同比较,相同为0,不同为1</p><p><strong>从数学的角度理解,我们可以看作模2加法(mod 2)</strong></p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028221143269.png" alt="image-20221028221143269"></p><p>发送方使得各位异或结果为0000</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221028221235042.png" alt="image-20221028221235042"></p><p>如果有区域变化,那么我们可以通过对数据进行异或操作,特别简单的找到错误的 位置</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">C:\Users\<span class="number">17278</span>\anaconda3\python.exe <span class="string">"C:\Users\17278\应用程序\PYCHARM\PyCharm 2021.3.2\plugins\python\helpers\pydev\pydevconsole.py"</span> --mode=client --port=<span class="number">10787</span></span><br><span class="line"><span class="keyword">import</span> sys; <span class="built_in">print</span>(<span class="string">'Python %s on %s'</span> % (sys.version, sys.platform))</span><br><span class="line">sys.path.extend([<span class="string">'D:\\Subject\\四维码'</span>, <span class="string">'D:/Subject/四维码'</span>])</span><br><span class="line">Python <span class="number">3.9</span><span class="number">.7</span> (default, Sep <span class="number">16</span> <span class="number">2021</span>, <span class="number">16</span>:<span class="number">59</span>:<span class="number">28</span>) [MSC v<span class="number">.1916</span> <span class="number">64</span> bit (AMD64)]</span><br><span class="line"><span class="type">Type</span> <span class="string">'copyright'</span>, <span class="string">'credits'</span> <span class="keyword">or</span> <span class="string">'license'</span> <span class="keyword">for</span> more information</span><br><span class="line">IPython <span class="number">7.29</span><span class="number">.0</span> -- An enhanced Interactive Python. <span class="type">Type</span> <span class="string">'?'</span> <span class="keyword">for</span> <span class="built_in">help</span>.</span><br><span class="line">PyDev console: using IPython <span class="number">7.29</span><span class="number">.0</span></span><br><span class="line">Python <span class="number">3.9</span><span class="number">.7</span> (default, Sep <span class="number">16</span> <span class="number">2021</span>, <span class="number">16</span>:<span class="number">59</span>:<span class="number">28</span>) [MSC v<span class="number">.1916</span> <span class="number">64</span> bit (AMD64)] on win32</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line">np.random.randint(<span class="number">0</span>,<span class="number">2</span>,<span class="number">16</span>)</span><br><span class="line">Out[<span class="number">3</span>]: array([<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line">bits=np.random.randint(<span class="number">0</span>,<span class="number">2</span>,<span class="number">16</span>)</span><br><span class="line"><span class="built_in">enumerate</span>(bits)</span><br><span class="line">Out[<span class="number">5</span>]: <<span class="built_in">enumerate</span> at <span class="number">0x1e0d2bc5840</span>></span><br><span class="line"><span class="built_in">list</span>(<span class="built_in">enumerate</span>(bits))</span><br><span class="line">Out[<span class="number">6</span>]: </span><br><span class="line">[(<span class="number">0</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">1</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">2</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">3</span>, <span class="number">0</span>),</span><br><span class="line">(<span class="number">4</span>, <span class="number">0</span>),</span><br><span class="line">(<span class="number">5</span>, <span class="number">0</span>),</span><br><span class="line">(<span class="number">6</span>, <span class="number">0</span>),</span><br><span class="line">(<span class="number">7</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">8</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">9</span>, <span class="number">0</span>),</span><br><span class="line">(<span class="number">10</span>, <span class="number">0</span>),</span><br><span class="line">(<span class="number">11</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">12</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">13</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">14</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="number">15</span>, <span class="number">1</span>)]</span><br><span class="line">[i <span class="keyword">for</span> i,bit <span class="keyword">in</span> <span class="built_in">enumerate</span>(bits) ]</span><br><span class="line">Out[<span class="number">7</span>]: [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>, <span class="number">10</span>, <span class="number">11</span>, <span class="number">12</span>, <span class="number">13</span>, <span class="number">14</span>, <span class="number">15</span>]</span><br><span class="line">[i <span class="keyword">for</span> i,bit <span class="keyword">in</span> <span class="built_in">enumerate</span>(bits) <span class="keyword">if</span> bit]</span><br><span class="line">Out[<span class="number">8</span>]: [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">11</span>, <span class="number">12</span>, <span class="number">13</span>, <span class="number">14</span>, <span class="number">15</span>]</span><br><span class="line">bits</span><br><span class="line">Out[<span class="number">9</span>]: array([<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>])</span><br><span class="line"><span class="number">0</span>^ <span class="number">1</span>^ <span class="number">2</span>^ <span class="number">7</span>^ <span class="number">8</span>^ <span class="number">11</span>^ <span class="number">12</span>^ <span class="number">13</span>^ <span class="number">14</span>^<span class="number">15</span></span><br><span class="line">Out[<span class="number">10</span>]: <span class="number">7</span></span><br><span class="line"><span class="keyword">from</span> functools <span class="keyword">import</span> reduce</span><br><span class="line"><span class="keyword">import</span> operator <span class="keyword">as</span> op</span><br><span class="line">reduce(op.xor,[i <span class="keyword">for</span> i,bit <span class="keyword">in</span> <span class="built_in">enumerate</span>(bits) <span class="keyword">if</span> bit])</span><br><span class="line">Out[<span class="number">13</span>]: <span class="number">7</span></span><br><span class="line">reduce(<span class="keyword">lambda</span> x,y:x^y,[i <span class="keyword">for</span> i,bit <span class="keyword">in</span> <span class="built_in">enumerate</span>(bits) <span class="keyword">if</span> bit])</span><br><span class="line">Out[<span class="number">14</span>]: <span class="number">7</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></blockquote><h6 id="RS-py"><a href="#RS-py" class="headerlink" title="RS.py"></a>RS.py</h6><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> functools <span class="keyword">import</span> reduce</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line">np.random.randint(<span class="number">0</span>,<span class="number">2</span>,<span class="number">16</span>)</span><br><span class="line">bits=np.random.randint(<span class="number">0</span>,<span class="number">2</span>,<span class="number">16</span>)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">hamming_syndrome</span>(<span class="params">bits</span>):</span><br><span class="line"> <span class="keyword">return</span> reduce(</span><br><span class="line"> <span class="comment">#Reduce by xor</span></span><br><span class="line"> <span class="keyword">lambda</span> x,y: x^y,</span><br><span class="line"> <span class="comment">#All indices of active bits..-</span></span><br><span class="line"> [i <span class="keyword">for</span> (i,b)<span class="keyword">in</span> <span class="built_in">enumerate</span>(bits) <span class="keyword">if</span> b]</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(hamming_syndrome(bits))</span><br></pre></td></tr></table></figure><h5 id="something-Interesting-of-efficiency"><a href="#something-Interesting-of-efficiency" class="headerlink" title="something Interesting of efficiency"></a>something Interesting of efficiency</h5><p>Comparing the two image , It is not difficult to see that when the larger the matrix data block, the less error correction code we need ,So the efficiency of this scheme is better.</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030221950554.png" alt="image-20221030221950554"></p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030221926650.png" alt="image-20221030221926650"></p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>总结一下:详细探究BCH的数学基础,再到Hamming code 的通俗理解,其实是一个从易到难发现问题,再寻找一种简单方法理解问题的过程。相对来说,比较困难的还是那个幂函数对称函数,Powersum symmetric functions,相关论文还是需要继续阅读,这篇文章忙中抽空写了差不多快4天,途中遇到了各种各样的问题,数学层面上的欠缺需要大量阅读来弥补,Turbo code 和 Shor code是接下来一段时间的阅读计划,欢迎各位关注shiyi-ale的github。</p>]]></content>
<tags>
<tag> 密码学 </tag>
</tags>
</entry>
<entry>
<title>「电子产品」Samsung 16g双通道内存组建安全下车</title>
<link href="/2022/10/30/Samsung-16g%E5%8F%8C%E9%80%9A%E9%81%93%E5%86%85%E5%AD%98%E7%BB%84%E5%BB%BA%E5%AE%89%E5%85%A8%E4%B8%8B%E8%BD%A6/"/>
<url>/2022/10/30/Samsung-16g%E5%8F%8C%E9%80%9A%E9%81%93%E5%86%85%E5%AD%98%E7%BB%84%E5%BB%BA%E5%AE%89%E5%85%A8%E4%B8%8B%E8%BD%A6/</url>
<content type="html"><![CDATA[<p>关于最近组了一个双通道16g3200MHZ的DRAM</p><blockquote><p>PDD下单,1天就送到了,采用机型Dell 5511 </p><p>花费不是很大可以说很香300RMB左右一条,600RMB拿下</p><p>原来那两条2BG海力士是凑合了</p></blockquote><h2 id="拆装教程"><a href="#拆装教程" class="headerlink" title="拆装教程"></a>拆装教程</h2><p><a href="https://www.bilibili.com/video/BV13h411m79S?share_source=copy_web">https://www.bilibili.com/video/BV13h411m79S?share_source=copy_web</a></p><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><p>记得在拆机前放放手上的静电,洗个手或者摸摸大铁门</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030170821916.png" alt="image-20221030170821916"></p><p>双面8颗粒三星相对来说对于3060laptop的释放要好很多</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030170843528.png" alt="image-20221030170843528"></p><p>下面是一些测试</p><p><img src="https://raw.githubusercontent.com/shiyi-ale/Image/main/Blog/image-20221030165931675.png" alt="image-20221030165931675"></p><h3 id="三星内存条不乏有手艺人的存在,从外观辨别可以看这个视频"><a href="#三星内存条不乏有手艺人的存在,从外观辨别可以看这个视频" class="headerlink" title="三星内存条不乏有手艺人的存在,从外观辨别可以看这个视频"></a>三星内存条不乏有手艺人的存在,从外观辨别可以看这个视频</h3><p><a href="https://www.bilibili.com/video/BV1SY4y1p7TL?share_source=copy_web">https://www.bilibili.com/video/BV1SY4y1p7TL?share_source=copy_web</a></p>]]></content>
<tags>
<tag> DRAM </tag>
</tags>
</entry>
</search>