-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
2057 lines (2057 loc) · 228 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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Obstacle detection based on binocular camera</title>
<url>/2018/10/18/Obstacle%20detection%20based%20on%20binocular%20camera/</url>
<content><![CDATA[<h1 id="Obstacle-detection-based-on-binocular-camera"><a href="#Obstacle-detection-based-on-binocular-camera" class="headerlink" title="Obstacle detection based on binocular camera"></a>Obstacle detection based on binocular camera</h1><blockquote>
<p>Preface: There are several related articles on the obstacle detection of binocular cameras and the obstacle detection based on OpenCV on CSDN and blog garden. However, a considerable part of the articles on obstacle detection tend to be theoretical, and there are few practical articles. Here, I will follow the examples I learned from the Internet to integrate and add my own understanding. I hope it can play a certain reference role for everyone in obstacle detection.</p>
</blockquote>
<span id="more"></span>
<blockquote>
<p><strong>Special thanks: <br/><a href="http://www.cnblogs.com/daihengchen/p/5686272.html">亦轩Dhc’s Blog</a><br/><a href="https://blog.csdn.net/zhouqianq/article/details/78580173">琪其齐奇旗棋’s Blog</a><br/><a href="https://blog.csdn.net/weixinhum/article/details/78161567">_寒潭雁影的’s Blog</a></strong></p>
</blockquote>
<h2 id="Now-let’s-get-to-the-main-topic"><a href="#Now-let’s-get-to-the-main-topic" class="headerlink" title="Now let’s get to the main topic!"></a>Now let’s get to the main topic!</h2><h3 id="Preliminary-preparation"><a href="#Preliminary-preparation" class="headerlink" title="Preliminary preparation:"></a>Preliminary preparation:</h3><ul>
<li>Here I am using a binocular camera to detect obstacles. The binocular camera is shown in the figure:<br><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/camera.png" alt=""></li>
</ul>
<h3 id="Preliminary-knowledge-points"><a href="#Preliminary-knowledge-points" class="headerlink" title="Preliminary knowledge points:"></a>Preliminary knowledge points:</h3><ul>
<li>Calibration of binocular camera</li>
<li>Use OpenCV to get pictures</li>
<li>Binocular correction</li>
<li>Stereo matching</li>
</ul>
<h4 id="Preliminary-knowledge-points-of-binocular-camera-calibration"><a href="#Preliminary-knowledge-points-of-binocular-camera-calibration" class="headerlink" title="Preliminary knowledge points of binocular camera calibration:"></a>Preliminary knowledge points of binocular camera calibration:</h4><blockquote>
<p>Here, the calibration method I use is <strong>Zhang Zhengyou Calibration Method</strong>。</p>
<ul>
<li>First of all, you need to be clear, for a camera, it is divided into <em>internal parameters</em> and <em>external parameters</em></li>
<li>There are five internal parameters:</li>
<li><ul>
<li>The mapping relationship between the object captured by the camera and the actual object on the x, y axis (two parameters).</li>
</ul>
</li>
<li><ul>
<li>The offset relationship between the center of the camera and the center of the image (two parameters).</li>
</ul>
</li>
<li><ul>
<li>The installation of the camera and the lens is not completely vertical, and there is an angular deviation. (One parameter).</li>
</ul>
</li>
<li>There are six external parameters: </li>
<li><ul>
<li>They are translation and rotation in the x, y, and z directions, respectively.<br>As long as we have the above two parameters, we basically know the correspondence between the image captured by the camera and the real thing. However, there will still be errors in “<strong>distortion</strong>“ between the image captured by the camera and the real thing. This is due to the 2D point shift caused by lens quality and other reasons.</li>
</ul>
</li>
</ul>
</blockquote>
<p><strong><em>Therefore, we use the Zhang Zhengyou calibration method to calibrate the camera’s internal and external parameters and distortion parameters.</em></strong></p>
<h2 id="张正友标定法"><a href="#张正友标定法" class="headerlink" title="张正友标定法"></a>张正友标定法</h2><blockquote>
<p>前言:张正友标定又称“张氏标定”。是张正友教授在1998年提出的单平面棋盘格的摄像机标定法。</p>
<ul>
<li>前期准备:</li>
<li><ul>
<li>标定板</li>
</ul>
</li>
<li><ul>
<li><blockquote>
<p>需要自定准备一个标定板,这标定板的长相大致如下:</p>
</blockquote>
</li>
</ul>
</li>
</ul>
</blockquote>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/Calibration_board.jpg" alt=""></p>
<ul>
<li><ul>
<li>实景拍摄的图像如下:</li>
</ul>
</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/True_Calibration_board.jpg" alt=""></p>
<ul>
<li>这种标定板有两种方式可以得到:</li>
<li><ul>
<li>第一种:直接从opencv官网上下载:<a href="https://docs.opencv.org/2.4/_downloads/pattern.png">官网标定板下载</a></li>
</ul>
</li>
<li><ul>
<li>第二种:使用Python+OpenCV生成棋盘格图片:<br>><blockquote>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">><span class="keyword">import</span> cv2 </span><br><span class="line">><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line">>width = <span class="number">350</span></span><br><span class="line">>height = <span class="number">500</span></span><br><span class="line">>length = <span class="number">50</span></span><br><span class="line"></span><br><span class="line">>image = np.zeros((width,height),dtype = np.uint8)</span><br><span class="line">><span class="built_in">print</span>(image.shape[<span class="number">0</span>],image.shape[<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line">><span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(height):</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(width):</span><br><span class="line"> <span class="keyword">if</span>((<span class="built_in">int</span>)(i/length) + (<span class="built_in">int</span>)(j/length))%<span class="number">2</span>:</span><br><span class="line"> image[i,j] = <span class="number">255</span>;</span><br><span class="line">>cv2.imwrite(<span class="string">"pic/chess.jpg"</span>,image)</span><br><span class="line">>cv2.imshow(<span class="string">"chess"</span>,image)</span><br><span class="line">>cv2.waitKey(<span class="number">0</span>)</span><br></pre></td></tr></table></figure>
<p><strong>所生成的图片和在OpenCV官网下载得到的图片是一样的规格的。</strong></p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h3 id="OpenCV下的张正友标定法"><a href="#OpenCV下的张正友标定法" class="headerlink" title="OpenCV下的张正友标定法"></a>OpenCV下的张正友标定法</h3><ul>
<li>角点提取</li>
</ul>
<p><strong>使用的函数1:</strong> <strong><em>bool findChessboardCorners(InputArray image,Size atternSIze,OutputArray corners,int flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE);</em></strong></p>
<blockquote>
<p><em>作用:用于提取标定板的内角点,也就是提取示例图中中每四个黑白格中间的那些角点。</em></p>
<ul>
<li>参数解析:</li>
<li><ul>
<li>image:拍摄到的棋盘图像;</li>
</ul>
</li>
<li><ul>
<li>patternSize:每个棋盘图上的内角点数。(如果是上图的话,内角点数Size(9,6),即:每行9个角点,每列9个角点);</li>
</ul>
</li>
<li><ul>
<li>corners:用于存储检测到的内角点的图像坐标位置。(一般用Point2f的向量来表示);</li>
</ul>
</li>
<li><ul>
<li>flags:用于定义棋盘图上的内角点查找的不同处理方式。</li>
</ul>
</li>
<li><ul>
<li><strong>返回值类型为bool,用以返回是否从图中找到角点。</strong></li>
</ul>
</li>
</ul>
</blockquote>
<p><strong>使用函数2:</strong> <strong><em>bool find4QuadCornerSubpix(InputArray img,InputOutputArray corners,Size region_size);</em></strong></p>
<blockquote>
<p><em>作用:用于在初步提取的角点信息上进一步提取亚像素信息,降低相机标定偏差,该方法专门用来获取棋盘图上内角点的精确位置。(<strong>有时候也会使用cornerSubPix函数</strong>)</em></p>
<ul>
<li>参数解析:</li>
<li><ul>
<li>img:输入的Mat矩阵,最好是8位灰度图像;</li>
</ul>
</li>
<li><ul>
<li>corners:初始的角点坐标向量,同时作为亚像素坐标位置的输出,所以需要的是浮点型数据,一般用Pointf2f/Point2d的向量来表示。<em>即输入上面findChessboardCorners函数的第三个参数</em>;</li>
</ul>
</li>
<li><ul>
<li>region_size:角点搜索窗口的尺寸;</li>
</ul>
</li>
<li><em>在一般情况下,其实我们用得较多的是cornerSubPix,但是我们这里用的是棋盘格,而<br>find4QuadCornerSubpix是专门用来获取棋盘图上内角点的精确位置的。</em></li>
</ul>
</blockquote>
<p><strong>使用函数3:</strong> <strong><em>drawChessboardCorners( InputOutputArray image, Size patternSize, InputArray corners, bool patternWasFound);</em></strong></p>
<blockquote>
<p><em>作用:在棋盘上绘制找到的内角点。</em></p>
<ul>
<li>参数解析:</li>
<li><ul>
<li>image:8位灰度或者彩色图像。</li>
</ul>
</li>
<li><ul>
<li>patternSize:每张标定棋盘上内角点的行列数,即findChessboardCorners的第二个参数;</li>
</ul>
</li>
<li><ul>
<li>corners:角点坐标向量,可用find4QuadCornerSubpix函数的第二个参数输出做输入;</li>
</ul>
</li>
<li><ul>
<li>patternWasFound:标志位,用来指示定义的棋盘内角点是否被完整的探测到,true表示被完整的探测到,函数会用直线依次连接所有的内角点,作为一个整体,false表示有未被探测到的内角点,这时候函数会以(红色)圆圈标记处检测到的内角点;</li>
</ul>
</li>
<li><ul>
<li>总查找角点的实力代码大致如下:<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">Mat imageInput = <span class="built_in">imread</span>(<span class="string">"chess.jpg"</span>);</span><br><span class="line">Size board_size = <span class="built_in">Size</span>(<span class="number">9</span>, <span class="number">6</span>);<span class="comment">//标定板上每行、列的角点数</span></span><br><span class="line">vector<Point2f> image_points_buf;<span class="comment">//缓存每幅图像上检测到的角点</span></span><br><span class="line"><span class="comment">/*提取角点*/</span></span><br><span class="line"><span class="keyword">if</span> (!<span class="built_in">findChessboardCorners</span>(imageInput, board_size, image_points_buf))</span><br><span class="line">{</span><br><span class="line"> cout << <span class="string">"can not find chessboard corners!\n"</span>; <span class="comment">//找不到角点 </span></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"> Mat view_gray;</span><br><span class="line"> <span class="built_in">cvtColor</span>(imageInput, view_gray, CV_RGB2GRAY);</span><br><span class="line"> <span class="comment">/*亚像素精确化*/</span></span><br><span class="line"> <span class="built_in">find4QuadCornerSubpix</span>(view_gray, image_points_buf, <span class="built_in">Size</span>(<span class="number">5</span>, <span class="number">5</span>)); <span class="comment">//对粗提取的角点进行精确化 </span></span><br><span class="line"> <span class="built_in">drawChessboardCorners</span>(view_gray, board_size, image_points_buf, <span class="literal">true</span>); <span class="comment">//用于在图片中标记角点 </span></span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"Camera Calibration"</span>, view_gray);<span class="comment">//显示图片 </span></span><br><span class="line"> <span class="built_in">waitKey</span>(<span class="number">0</span>); </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li>相机标定<blockquote>
<p>利用上面获取到的图像角点(理论上需要三张图像,即三组数据,事实上以10~20张为宜,因为这样误差会比较小),便可以用calibrateCamera函数做摄像头标定,计算出摄像头的内参、外参和畸变参数了。</p>
</blockquote>
</li>
</ul>
<p><strong>使用函数1:</strong> <strong><em>double calibrateCamera(InputArrays objectPoints,InputAttaysOfArrays imagePoints,Size imageSize,CV_OUT InputOutputArray cameraMatrix,CV_OUT InputOutputArray distCoeffs,OutputArrayOfArrays rvecs,OutputArrayOfArrays tvecs,int flags=0,TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,30,DBL_EPSILON));</em></strong></p>
<blockquote>
<ul>
<li>参数解析:</li>
<li><ul>
<li>objectPoints:为世界坐标系中的三维点。在使用时,应该输入一个三维坐标点的向量集合。一般我们假定标定板放在z=0的平面上,然后依据棋盘上单个黑白方块的大小(也可以直接都取10,如果不需要很准确的映射到现实事物的话)可以计算出每个内角点的世界坐标。</li>
</ul>
</li>
<li><ul>
<li>imagePoints:为每一个内角点对应的图像坐标点。也即是上面求得的各张图像的角点集合。</li>
</ul>
</li>
<li><ul>
<li>imageSize:为图像的像素尺寸大小,在计算相机的内参和畸变矩阵的时候需要用到的该参数。</li>
</ul>
</li>
<li><ul>
<li>cameraMatrix:为相机的内参矩阵。输入一个Mat cameraMatrix即可,如Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0))。</li>
</ul>
</li>
<li><ul>
<li>distCoeffs:为畸变矩阵。输入一个Mat distCoffs=Mat(1,5,CV_32FC1,Scalar::all(0));即可。</li>
</ul>
</li>
<li><ul>
<li>rvecs:旋转向量。应该输入一个Mat类型的vector,即vector<Mat>rvecs;</li>
</ul>
</li>
<li><ul>
<li>tvecs:位移向量。和rvecs一样,应该为vector<Mat> tvecs;</li>
</ul>
</li>
<li><ul>
<li>flags:标定时所采用的算法。flags有如下几个参数(直接不写则依据下面参数描述中没设参数的情况进行):</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>CV_CALIB_USE_INTRINSIC_GUESS:使用该参数时,在cameraMatrix矩阵中应该有fx,fy,u0,v0的估计值。否则的话,将初始化(u0,v0)图像的中心点,使用最小二乘估算出fx,fy。</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>CV_CALIB_FIX_PRINCIPAL_POINT:在进行优化时会固定光轴点。当CV_CALIB_USE_INTRINSIC_GUESS参数被设置,光轴点将保持在中心或者某个输入的值。</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值,只将fy作为可变量,进行优化计算。当CV_CALIB_USE_INTRINSIC_GUESS没有被设置,fx和fy将会被忽略。只有fx/fy的比值在计算中会被用到。</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>CV_CALIB_ZERO_TANGENT_DIST:设定切向畸变参数(p1,p2)为零。</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6:对应的径向畸变在优化中保持不变。</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li><ul>
<li>CV_CALIB_RATIONAL_MODEL:计算k4,k5,k6三个畸变参数。如果没有设置,则只计算其它5个畸变参数。</li>
</ul>
</li>
</ul>
</li>
<li><ul>
<li>criteria:最优迭代终止条件设定。</li>
</ul>
</li>
</ul>
<p><em>在使用该函数进行标定运算之前,需要对棋盘上每个角点的空间坐标系位置坐标进行初始化(就是对其进行赋值),算出相机内参矩阵、相机畸变、另外每张图片会生成属于自己的平移向量和旋转向量。</em></p>
<p><code>具体实现代码大致如下:</code><br><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">Size image_size;<span class="comment">//图像的尺寸</span></span><br><span class="line">Size board_size = <span class="built_in">Size</span>(<span class="number">9</span>, <span class="number">6</span>); <span class="comment">//标定板上每行、列的角点数</span></span><br><span class="line">vector<Point2f> image_points_buf; <span class="comment">//缓存每幅图像上检测到的角点</span></span><br><span class="line">vector<vector<Point2f>> image_points_seq; <span class="comment">//保存检测到的所有角点</span></span><br><span class="line"><span class="comment">/*提取角点*/</span></span><br><span class="line"><span class="keyword">char</span> filename[<span class="number">10</span>];</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">size_t</span> image_num = <span class="number">1</span>; image_num <= IMGCOUNT; image_num++)</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">sprintf_s</span>(filename, <span class="string">"%d.jpg"</span>, image_num);</span><br><span class="line"> Mat imageInput = <span class="built_in">imread</span>(filename);</span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">findChessboardCorners</span>(imageInput, board_size, image_points_buf))</span><br><span class="line"> {</span><br><span class="line"> cout << <span class="string">"can not find chessboard corners!\n"</span>;<span class="comment">//找不到角点 </span></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> Mat view_gray;</span><br><span class="line"> <span class="built_in">cvtColor</span>(imageInput, view_gray, CV_RGB2GRAY);</span><br><span class="line"> <span class="comment">/*亚像素精确化*/</span></span><br><span class="line"> <span class="built_in">find4QuadCornerSubpix</span>(view_gray, image_points_buf, <span class="built_in">Size</span>(<span class="number">5</span>, <span class="number">5</span>));<span class="comment">//对粗提取的角点进行精确化 </span></span><br><span class="line"> <span class="built_in">drawChessboardCorners</span>(view_gray, board_size, image_points_buf, <span class="literal">true</span>);<span class="comment">//用于在图片中标记角点 </span></span><br><span class="line"> image_points_seq.<span class="built_in">push_back</span>(image_points_buf);<span class="comment">//保存亚像素角点 </span></span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"Camera Calibration"</span>, view_gray);<span class="comment">//显示图片 </span></span><br><span class="line"> <span class="comment">//waitKey(500);//停半秒</span></span><br><span class="line"> }</span><br><span class="line"> image_size.width = imageInput.cols;</span><br><span class="line"> image_size.height = imageInput.rows;</span><br><span class="line"> imageInput.<span class="built_in">release</span>();</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*相机标定*/</span></span><br><span class="line">vector<vector<Point3f>> object_points; <span class="comment">//保存标定板上角点的三维坐标,为标定函数的第一个参数</span></span><br><span class="line">Size square_size = <span class="built_in">Size</span>(<span class="number">10</span>, <span class="number">10</span>);<span class="comment">//实际测量得到的标定板上每个棋盘格的大小,这里其实没测,就假定了一个值,感觉影响不是太大,后面再研究下</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> t = <span class="number">0</span>; t<IMGCOUNT; t++)</span><br><span class="line">{</span><br><span class="line"> vector<Point3f> tempPointSet;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i<board_size.height; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j<board_size.width; j++)</span><br><span class="line"> {</span><br><span class="line"> Point3f realPoint;</span><br><span class="line"> <span class="comment">//假设标定板放在世界坐标系中z=0的平面上</span></span><br><span class="line"> realPoint.x = i*square_size.width;</span><br><span class="line"> realPoint.y = j*square_size.height;</span><br><span class="line"> realPoint.z = <span class="number">0</span>;</span><br><span class="line"> tempPointSet.<span class="built_in">push_back</span>(realPoint);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> object_points.<span class="built_in">push_back</span>(tempPointSet);</span><br><span class="line">}</span><br><span class="line"><span class="comment">//内外参数对象</span></span><br><span class="line">Mat cameraMatrix = <span class="built_in">Mat</span>(<span class="number">3</span>, <span class="number">3</span>, CV_32FC1, Scalar::<span class="built_in">all</span>(<span class="number">0</span>));<span class="comment">//摄像机内参数矩阵</span></span><br><span class="line">vector<<span class="keyword">int</span>> point_counts;<span class="comment">// 每幅图像中角点的数量 </span></span><br><span class="line">Mat distCoeffs = <span class="built_in">Mat</span>(<span class="number">1</span>, <span class="number">5</span>, CV_32FC1, Scalar::<span class="built_in">all</span>(<span class="number">0</span>));<span class="comment">//摄像机的5个畸变系数:k1,k2,p1,p2,k3</span></span><br><span class="line">vector<Mat> tvecsMat;<span class="comment">//每幅图像的旋转向量</span></span><br><span class="line">vector<Mat> rvecsMat;<span class="comment">//每幅图像的平移向量</span></span><br><span class="line"><span class="built_in">calibrateCamera</span>(object_points, image_points_seq, image_size, cameraMatrix, distCoeffs, rvecsMat, tvecsMat, <span class="number">0</span>);<span class="comment">//摄像头标定</span></span><br></pre></td></tr></table></figure></p>
</blockquote>
<ul>
<li>图像矫正:<blockquote>
<p>现在已经通过标定,然后得到摄像头的各个参数,后面就可以用这些得到的参数来做摄像头的矫正了。</p>
</blockquote>
</li>
</ul>
<p><strong>使用函数:</strong> <strong><em>void undistort(InputArray src, OutputArray dst,InputArray cameraMatrix,InputArray distCoeffs,InputArray newCameraMatrix=noArray());</em></strong></p>
<blockquote>
<ul>
<li>参数解析:</li>
<li><ul>
<li>src:输入参数,代表畸变的原始图像;</li>
</ul>
</li>
<li><ul>
<li>dst:矫正后的输出图像,跟输入图像具有相同的类型和大小;</li>
</ul>
</li>
<li><ul>
<li>cameraMatrix:之前求得的相机内参矩阵;</li>
</ul>
</li>
<li><ul>
<li>distCoeffs:之前求得的相机畸变矩阵;</li>
</ul>
</li>
<li><ul>
<li>newCameraMatrix:默认跟cameraMatrix保持一致;</li>
</ul>
</li>
</ul>
<p><code>具体使用代码如下:</code><br><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="comment">/*用标定的结果矫正图像*/</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">size_t</span> image_num = <span class="number">1</span>; image_num <= IMGCOUNT; image_num++)</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">sprintf_s</span>(filename, <span class="string">"%d.jpg"</span>, image_num);</span><br><span class="line"> Mat imageSource = <span class="built_in">imread</span>(filename);</span><br><span class="line"> Mat newimage = imageSource.<span class="built_in">clone</span>();</span><br><span class="line"> <span class="built_in">undistort</span>(imageSource, newimage, cameraMatrix, distCoeffs);</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"source"</span>, imageSource);<span class="comment">//显示图片 </span></span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"drc"</span>, newimage);<span class="comment">//显示图片 </span></span><br><span class="line"> <span class="built_in">waitKey</span>(<span class="number">500</span>);<span class="comment">//停半秒</span></span><br><span class="line"> imageSource.<span class="built_in">release</span>();</span><br><span class="line"> newimage.<span class="built_in">release</span>();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
</blockquote>
<h3 id="matlab下的张正友标定法"><a href="#matlab下的张正友标定法" class="headerlink" title="matlab下的张正友标定法"></a>matlab下的张正友标定法</h3><blockquote>
<p>前期准备:<a href="http://www.vision.caltech.edu/bouguetj/calib_doc/download/index.html">工具箱下载</a></p>
<p>安装:</p>
<ul>
<li>将下载的工具箱文件toolbox_calib.zip解压缩,将目录toolbox_calib拷贝到Matlab的目录下,也可以放在其他目录。</li>
<li>运行Matlab并添加文件夹TOOLBOX_calib的位置到matlab路径path中。</li>
<li>具体操作为:File->SetPath->Add Folder To Path,然后找到刚刚存放的文件夹<br>TOOLBOX_calib,save一下就OK了。</li>
<li>采集图像:采集的图像统一命名后,拷贝到toolbox_calib目录中。命名规则为基本名和编号,基本名在前,后面直接跟着数字编号。编号最多为3位十进制数字。<h4 id="单目标定"><a href="#单目标定" class="headerlink" title="单目标定"></a>单目标定</h4></li>
<li>准备工作</li>
</ul>
<p>将双目摄像机拍摄的左右图像的文件夹作为matlab的当前文件夹:我的图像名称类似L1,L2……,R1,R2……(注:图像的命名格式:字母+数字,即字母在前,数字在后。)</p>
<ul>
<li>matlab中命令窗口输入calib_gui,回车后弹出如下窗口:</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ToolBox.jpg" alt=""></p>
<ul>
<li>选择第一个选项<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/StandardVersion.jpg" alt="">,弹出下面的主窗口:</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ToolBoxStandard.jpg" alt=""></p>
<ul>
<li><p><code>备注:</code></p>
</li>
<li><ul>
<li>“Image names”键:指定图像的基本名(Basename)和图像格式,并将相应的图像读入内存。</li>
</ul>
</li>
<li><ul>
<li>“Read names”键:将指定基本名和格式的图像读入内存。</li>
</ul>
</li>
<li><ul>
<li>“Extract grid corners”键:提取网格角点。</li>
</ul>
</li>
<li><ul>
<li>“Calibration”键:内参数标定。</li>
</ul>
</li>
<li><ul>
<li>“Show Extrinsic”键:以图形方式显示摄像机与标定靶标之间的关系。</li>
</ul>
</li>
<li><ul>
<li>“Project on images”键:按照摄像机的内参数以及摄像机的外参数(即靶标坐标系相对于摄像机坐标系的变换关系),根据网格点的笛卡尔空间坐标,将网格角点反投影到图像空间。 </li>
</ul>
</li>
<li><ul>
<li>“Analyse error”键:图像空间的误差分析</li>
</ul>
</li>
<li><ul>
<li>“Recomp. corners”键:重新提取网格角点。</li>
</ul>
</li>
<li><ul>
<li>“Add/Suppress images”键:增加/删除图像。</li>
</ul>
</li>
<li><ul>
<li>“Save”键:保存标定结果。将内参数标定结果以及摄像机与靶标之间的外参数保存为m文件Calib_results.m,存放于toolbox_calib目录中。</li>
</ul>
</li>
<li><ul>
<li>“Load”键:读入标定结果。从存放于toolbox_calib目录中的标定结果文件Calib_results.mat读入。</li>
</ul>
</li>
<li><ul>
<li>“Exit”键:退出标定。</li>
</ul>
</li>
<li><ul>
<li>“Comp. Extrinsic”键:计算外参数。 </li>
</ul>
</li>
<li><ul>
<li>“Undistort image”键:生成消除畸变后的图像并保存。 </li>
</ul>
</li>
<li><ul>
<li>“Export calib data”键:输出标定数据。分别以靶标坐标系中的平面坐标和图像中的图像坐标,将每一幅靶标图像的角点保存为两个tex文件。</li>
</ul>
</li>
<li><ul>
<li>“Show calib results”键:显示标定结果。</li>
</ul>
</li>
<li><p>选择第一个按钮<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ImageNames.jpg" alt="">,在命令窗口中会出现当前文件夹中的所有信息:</p>
</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/Calib_Results.jpg" alt=""></p>
<p>并提示你输入“Basename camera calibration images (without number norsuffix):”,对于我的图像名称做左图的标定时输入:L。图像格式的选择 j。回车后,显示load的所有图像。</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/LoadImage.jpg" alt=""></p>
<p>共读入20幅图像</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/20Images.jpg" alt=""></p>
<ul>
<li>回到主窗口,选择第三个选项<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ExtractGridCorners.jpg" alt="">,命令窗口有如下提示:选择默认,敲击回车即可:</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/Wintx_Winty.png" alt=""></p>
<ul>
<li><code>备注:</code></li>
<li><ul>
<li>a:“wintx ([] = 5) =”和“winty ([] = 5) =”输入行中输入角点提取区域的窗口半宽m和半高n。m和n为正整数,单位为像素,缺省值为5个像素。选定m和n后,命令窗口显示角点提取区域的窗口尺寸(2n+1)x(2m+1)。例如,选择缺省时角点提取区域的窗口尺寸为11x11像素。</li>
</ul>
</li>
<li><ul>
<li>b:”Do you want to use the automatic square counting mechanism (0=[]=default) or do you always want to enter the number of squares manually (1,other)? “时,选择缺省值0表示自动计算棋盘格靶标选定区域内的方格行数和列数,选择值1表示人工计算并输入棋盘格靶标选定区域内的方格行数和列数。</li>
</ul>
</li>
<li><p>回车敲完后,显示第一幅棋盘格,进行角点的提取工作:用鼠标单击棋盘格外围4个角点,点击的第一个点是原点O,顺序(逆序)点击其他点,过程如图:</p>
</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ClickOnTheFourExtemeCorners.jpg" alt=""> <img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ExtremeCorners.jpg" alt=""></p>
<ul>
<li><p><code>注意:</code></p>
</li>
<li><ul>
<li>1)、 这里有的要求标定内角点,如图所示。查阅多方资料并未见明确要求,但通过比较,我个人认为是因标定板而异。</li>
</ul>
</li>
<li><ul>
<li><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/WrongPicture.jpg" alt=""></li>
</ul>
</li>
<li><ul>
<li>2)、所形成的四边形的边应与棋盘格靶标的网格线基本平行。否则,影响角点提取精度,甚至导致角点提取错误。</li>
</ul>
</li>
<li><p>回到命令窗口,输入棋盘信息:</p>
</li>
</ul>
<p>“Number of squares along the X direction ([]=10) =”输入X方向方格数目:7</p>
<p>“Number of squares along the Y direction ([]=10) =”输入X方向方格数目:9</p>
<p>“Size dX of each square along the X direction ([]=100mm) =”输入X方向方格长度(mm):29;我的棋盘格X、Y方向长度相同均是29mm</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/CornerExtraction.jpg" alt=""></p>
<p>回车后,显示角点提取结果:(我的棋盘是打印后贴在纸盒上的,棋盘并不是绝对的平面,所以有些角点的位置与真实位置有些出入)</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/Feature2.jpg" alt=""></p>
<ul>
<li><code>备注:</code></li>
</ul>
<p>在Matlab命令窗口出现“Need of an initial guess for distortion? ([]=no, other=yes) ”时,如果选择no则不输入畸变初始值,如果选择yes则输入畸变初始值。输入的畸变初始值,将同时赋值给需要估计的5个畸变系数,即径向畸变系数kc(1)、kc(2)、kc(5)和切向畸变系数kc(3)、kc(4)。如果不估计6阶径向畸变系数kc(5),则kc(5)被赋值为0</p>
<ul>
<li>依次循环标定后面的图像(eg.我的是20幅)</li>
</ul>
<p>注意:当第一幅图像的信息填好后,第二幅会以第一幅的信息为缺省值,只需回车即可。但是,要注意XY两个方向只与你点击的第一个角点有关,举例说明:</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/Feature1.jpg" alt=""><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/feature3.jpg" alt=""></p>
<p>两图棋盘方向相同(横向),但是,我点击的第一个角点不同,原点O不同,XY的方向也不同。所以,为了不用每次都重新填写棋盘信息,第一个角点选择同一个位置的点(如果所拍摄的棋盘方向不同<横向、纵向都有>,则第一个点是相对于棋盘位置相同的点,说多了又是泪)</p>
<ul>
<li>角点提取完成以后进行标定处理,文件夹中出现.mat文件。(此处最好将其更名为 calib_data_left.mat,以免后面对右图像进行标定时将此结果覆盖。)</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/calib_data.png" alt=""></p>
<p>回归主窗口,选择第四个选项<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/calibration.jpg" alt="">:</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/calibrationResult.jpg" alt=""></p>
<ul>
<li>显示摄像机与标定板间的关系:</li>
</ul>
<p>主窗口点击<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ShowExtrinsic.jpg" alt="">,即可在新的图形窗口显示摄像机与标定靶标之间的关系:</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/IO.jpg" alt=""></p>
<ul>
<li>误差分析:</li>
</ul>
<p>点击<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/AnalyseError.jpg" alt="">,即可在新的图形窗口显示出标定使用的所有角点反投影到图像空间的图像坐标误差,如图所示:</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/Error.jpg" alt=""></p>
<p>在图所示的图形窗口,利用鼠标移动十字标尺可以选择角点,即可在命令窗口显示出该角点的信息,包括该角点所属图像、索引号、以方格为单位的坐标、图像坐标、反投影后的图像坐标误差、角点提取区域的窗口半宽m和半高n。</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/WindowSize.jpg" alt=""></p>
<ul>
<li>点击<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/save.jpg" alt="">,文件夹中出现如下文件:</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/CalibResults.jpg" alt=""></p>
<ul>
<li><p><code>注:</code> Result.mat件在双目标定中能够用到。将”Calib_Results.mat”改成”Calib_Results_left.mat “</p>
</li>
<li><p>点击“Undistort image”对图像进行去畸变处理,选择对某一张图像还是所有图像进行处理,默认是all。随后,保存所有畸变处理后的图像。</p>
</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/UndistortImage.jpg" alt=""></p>
<h4 id="双目测定"><a href="#双目测定" class="headerlink" title="双目测定"></a>双目测定</h4><ul>
<li>用同样的办法处理右相机拍摄的图像。</li>
</ul>
<p>标定结果:</p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/RightResults.jpg" alt=""></p>
<ul>
<li>单独得到摄像头标定完成以后就可以进行立体标定了。在matlab命令窗口中输入<code>stereo_gui</code>,弹出如下窗口:</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/StereoCameraToolbox.jpg" alt=""></p>
<ul>
<li>点击<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/LoadLeftRightFiles.jpg" alt="">,命令行窗口提示.mat文件的名称,默认的文件名(Calib_Result_left.mat和Calib_Result_right.mat),直接回车即可,或者输入自己的文件名称。</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/LoadingFiles.png" alt=""></p>
<ul>
<li>load文件后,命令窗口显示左右摄像机的参数信息,</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/LoadResults.jpg" alt=""></p>
<ul>
<li><p><code>备注:</code></p>
</li>
<li><p>fc_left是左摄像机的放大系数,即焦距归一化成像平面上的成像点坐标到图像坐标的放大系数。cc_left为左摄像机的主点坐标,单位为像素。alpha_c_left是对应于左摄像机的实际y轴与理想y轴之间的夹角,单位为弧度,默认值为0弧度。kc_left为左摄像机的畸变系数。fc_right是右摄像机的放大系数,即焦距归一化成像平面上的成像点坐标到图像坐标的放大系数。cc_right为右摄像机的主点坐标,单位为像素。alpha_c_right是对应于右摄像机的实际y轴与理想y轴之间的夹角,单位为弧度,默认为0弧度。kc_right为右摄像机的畸变系数。om为左摄像机相对于右摄像机的姿态矩阵的rodrigues旋转向量,利用函数rodrigues可以转换为姿态矩阵。T为左摄像机相对于右摄像机的位移向量,即左摄像机坐标系原点在右摄像机坐标系中的位移向量,单位mm。</p>
</li>
<li><p>点击<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/RunStereoCalibration.png" alt="">,计算优化后的外参数。命令窗口输出左、右摄像机的内参数和优化后的外参数。输出结果如下所示:</p>
</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/StereoCalibrationResults.jpg" alt=""></p>
<ul>
<li>点击<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ShowExtrinsicsOfStereoRig.jpg" alt="">,显示标定靶面相对于双目摄像机的位置:</li>
</ul>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/ExtrinsicParameters.jpg" alt=""></p>
<ul>
<li><p>点击<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/SaveStereoCalibResults.png" alt="">,将标定结果保存为文件<img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/CalibResultsStereo.png" alt=""></p>
</li>
<li><p><code>备注:</code></p>
</li>
<li><p>双目标定各个按钮功能:</p>
</li>
<li><ul>
<li>“Load left and right calibration files”键:读入左、右摄像机的标定结果,并对左摄像机相对于右摄像机的位姿进行初步标定。</li>
</ul>
</li>
<li><ul>
<li>“Run stereo calibration”键:计算优化后的外参数。 </li>
</ul>
</li>
<li><ul>
<li>“Show Extrinsics of stereo rig”键:显示靶标相对于摄像机的位姿。</li>
</ul>
</li>
<li><ul>
<li>“Show Intrinsic parameters”键:在Matlab的命令窗口显示左、右摄像机的内参数和优化后的外参数。</li>
</ul>
</li>
<li><ul>
<li>“Save stereo calib results”键:将标定结果保存为文件Calib_Results_stereo.mat,存放于toolbox_calib目录中。</li>
</ul>
</li>
<li><ul>
<li>“Load stereo calib results”键:读入标定结果。从存放于toolbox_calib目录中的标定结果文件Calib_Results_stereo.mat读入。</li>
</ul>
</li>
<li><ul>
<li>“Rectify the calibration images”键:按照畸变系数对左、右摄像机采集的所有靶标图像进行处理,生成消除畸变后的图像并保存在toolbox_calib目录中。生成的消除畸变后的图像,以原图像的文件名在基本名和编号之间插入_rectified作为其文件名。</li>
</ul>
</li>
<li><ul>
<li>“Exit”键:退出立体视觉标定。</li>
</ul>
</li>
</ul>
<h4 id="总结:"><a href="#总结:" class="headerlink" title="总结:"></a>总结:</h4><p><code>Matlab工具箱标定,注意问题:</code></p>
<ul>
<li>内参数标定需要注意的问题 </li>
<li><ul>
<li>制作棋盘格靶标时应特别注意,黑色方格与白色方格尺寸需要相同,而且所有方格的尺寸必须严格一致。靶标的方格数量不宜太小,行数和列数以大于10为宜。方格的尺寸不宜太大或太小,采集的整幅靶标图像中方格的边长尺寸不小于20像素。</li>
</ul>
</li>
<li><ul>
<li>采集靶标图像时应特别注意,需要在不同的角度不同的位置采集靶标的多幅图像。采集到的图像必须清晰,靶标图像尺寸以占整幅图像尺寸的1/3~3/4为宜。靶标图像最好在整幅图像的不同位置都有分布,不宜过于集中于同一区域。靶标放置位置与摄像机之间的距离最好为视觉系统的主要工作距离。靶标相对于摄像机的角度应有较大范围的变化,应包含绕三个轴较大角度的旋转,最好不小于30度。采集的靶标图像数量不应太少,建议以10~20幅靶标图像为宜。 </li>
</ul>
</li>
<li><ul>
<li>采集图像过程中,摄像机的焦距不能调整。因为焦距属于摄像机的内参数,不同焦距下采集的图像隐含了不同的内参数,这些图像放在一起进行标定不能得到正确的结果。 </li>
</ul>
</li>
<li><ul>
<li>采集的靶标图像统一命名,由基本名和编号构成,如Image1~Image15。靶标图像的数据格式必须相同。 </li>
</ul>
</li>
<li><ul>
<li>提取角点时,在图形窗口利用鼠标点击设定棋盘格靶标的选定区域。点击的第一个角点作为靶标坐标系的原点,顺序点击4个角点形成四边形。相邻两次点击的角点应在同一条网格线上,使得所形成的四边形的边应与棋盘格靶标的网格线基本平行。为提高点击的角点的精度,建议将显示靶标图像的图像窗口放大到最大,利用鼠标的十字标线尽可能准确的点击4个角点。</li>
</ul>
</li>
<li><ul>
<li>摄像机的实际y轴与理想y轴之间的夹角ac是否标定,由est_alpha标志位设定。est_alpha=1时对alpha_c进行标定,est_alpha=0时不对alpha_c进行标定。</li>
</ul>
</li>
<li><ul>
<li>数组est_dist(1:5)是畸变系数kc(1:5)是否标定的标志,只对标志取值为1的畸变系数标定,标志取值为0的畸变系数不标定。默认值为est_dist(1:5)=[1 1 1 1 0],即对畸变系数kc1~kc4进行标定,对kc5不进行标定,kc5=0。</li>
</ul>
</li>
<li><ul>
<li>运行calib_gui指令后,Matlab处于busy状态,Matlab命令窗口不再响应其它命令。只有在点击标定工具箱的“Exit”键退出标定后,Matlab命令窗口才能恢复响应其它命令。</li>
</ul>
</li>
<li>外参数标定需要注意的问题 </li>
<li><ul>
<li>方格尺寸必须输入实际尺寸</li>
</ul>
</li>
<li><ul>
<li>提取角点时,在图形窗口利用鼠标点击的第一个角点作为靶标坐标系的原点,得到的外参数是靶标坐标系在摄像机坐标系中的位姿</li>
</ul>
</li>
<li><ul>
<li>rodrigues旋转向量omc_ext与姿态矩阵Rc_ext可以利用rodrigues函数进行转换。omc_ext=rodrigues(Rc_ext),Rc_ext=rodrigues(omc_ext)</li>
</ul>
</li>
<li>立体视觉标定需要注意的问题</li>
<li><ul>
<li>提取角点时,在图形窗口利用鼠标点击的第一个角点作为靶标坐标系的原点,左右摄像机对应的靶标图像对需要选择相同的第一个角点作为原点。其他的3个角点在左右摄像机的靶标图像中也应相同。</li>
</ul>
</li>
<li><ul>
<li>左右摄像机采集的图像数量必须相同。相同的编号的左右摄像机采集的图像是靶标在同一位姿时左右摄像机采集的图像,构成一组立体视觉的靶标图像对。</li>
</ul>
</li>
<li><ul>
<li>得到的外参数是左摄像机相对于右摄像机的位姿,即左摄像机坐标系在右摄像机坐标系中的位姿。</li>
</ul>
</li>
<li><ul>
<li>运行stereo_gui指令后,Matlab命令窗口可以响应其它命令。</li>
</ul>
</li>
</ul>
</blockquote>
<h2 id="OpenCV获取图片"><a href="#OpenCV获取图片" class="headerlink" title="OpenCV获取图片"></a>OpenCV获取图片</h2><blockquote>
<p>使用OpenCV获取图片有两种代码,一种是使用Python,另外一种是使用C++,但是道理其实是一样的。<code>先读取视频,然后再取帧</code>。</p>
</blockquote>
<ul>
<li>Python代码:</li>
<li><code>注意:保存路径需要根据自己的电脑进行配置,我这里只是使用我在我的电脑上使用的路径进行的拍照、保存功能</code>。<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> cv2</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">shot</span>(<span class="params">pos, frame</span>):</span></span><br><span class="line"> <span class="keyword">global</span> counter</span><br><span class="line"> path = folder + pos + <span class="string">"_"</span> + <span class="built_in">str</span>(counter) + <span class="string">".jpg"</span></span><br><span class="line"> cv2.imwrite(path, frame)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"snapshot saved into: "</span> + path)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"></span><br><span class="line"> AUTO = <span class="literal">True</span> <span class="comment"># 自动拍照,或手动按s键拍照</span></span><br><span class="line"> INTERVAL = <span class="number">1</span> <span class="comment"># 自动拍照间隔</span></span><br><span class="line"></span><br><span class="line"> cv2.namedWindow(<span class="string">"middle"</span>)</span><br><span class="line"> cv2.moveWindow(<span class="string">"middle"</span>, <span class="number">400</span>, <span class="number">0</span>)</span><br><span class="line"> middle_camera = cv2.VideoCapture(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> counter = <span class="number">0</span></span><br><span class="line"> utc = time.time()</span><br><span class="line"> pattern = (<span class="number">12</span>, <span class="number">8</span>) <span class="comment"># 棋盘格尺寸</span></span><br><span class="line"> folder = <span class="string">"F:/PyCharm_code/OpenCVDemo/snapshot/"</span> <span class="comment"># 拍照文件目录(请根据自己的路径进行更改)</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> <span class="comment"># ret, left_frame = left_camera.read()</span></span><br><span class="line"> ret, middle_frame = middle_camera.read()</span><br><span class="line"></span><br><span class="line"> <span class="comment"># cv2.imshow("left", left_frame)</span></span><br><span class="line"> cv2.imshow(<span class="string">"middle"</span>, middle_frame)</span><br><span class="line"></span><br><span class="line"> now = time.time()</span><br><span class="line"> <span class="keyword">if</span> AUTO <span class="keyword">and</span> now - utc >= INTERVAL:</span><br><span class="line"> shot(<span class="string">"middle"</span>, middle_frame)</span><br><span class="line"> img = Image.<span class="built_in">open</span>(folder + <span class="string">"middle"</span> + <span class="string">"_"</span> + <span class="built_in">str</span>(counter) + <span class="string">".jpg"</span>)</span><br><span class="line"> width, height = img.size</span><br><span class="line"> w = width * <span class="number">0.5</span></span><br><span class="line"> right_box = (<span class="number">0</span>, <span class="number">0</span>, w, height)</span><br><span class="line"> left_box = (w, <span class="number">0</span>, width, height)</span><br><span class="line"> right_region = img.crop(right_box)</span><br><span class="line"> left_region = img.crop(left_box)</span><br><span class="line"> right_region.save(folder + <span class="string">"RightTest"</span> + <span class="string">"/"</span> + <span class="built_in">str</span>(counter) + <span class="string">".jpg"</span>)</span><br><span class="line"> left_region.save(folder + <span class="string">"LeftTest"</span> + <span class="string">"/"</span> + <span class="built_in">str</span>(counter) + <span class="string">".jpg"</span>)</span><br><span class="line"></span><br><span class="line"> counter += <span class="number">1</span></span><br><span class="line"> utc = now</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> key = cv2.waitKey(<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">if</span> key == <span class="built_in">ord</span>(<span class="string">"q"</span>):</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="keyword">elif</span> key == <span class="built_in">ord</span>(<span class="string">"s"</span>):</span><br><span class="line"> shot(<span class="string">"middle"</span>, middle_frame)</span><br><span class="line"> counter += <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> middle_camera.release()</span><br><span class="line"> cv2.destroyWindow(<span class="string">"middle"</span>)</span><br></pre></td></tr></table></figure>
<blockquote>
<ul>
<li><code>备注:</code>由于我使用的双目摄像头拍照的时候所呈现的是左、右摄像头显示在同一个屏幕上,所以我中间有一个分割图像的过程。分割图像代码如下所示:</li>
</ul>
</blockquote>
</li>
</ul>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">img = Image.<span class="built_in">open</span>(folder + <span class="string">"middle"</span> + <span class="string">"_"</span> + <span class="built_in">str</span>(counter) + <span class="string">".jpg"</span>)</span><br><span class="line">width, height = img.size</span><br><span class="line">w = width * <span class="number">0.5</span></span><br><span class="line">right_box = (<span class="number">0</span>, <span class="number">0</span>, w, height)</span><br><span class="line">left_box = (w, <span class="number">0</span>, width, height)</span><br><span class="line">right_region = img.crop(right_box)</span><br><span class="line">left_region = img.crop(left_box)</span><br><span class="line">right_region.save(folder + <span class="string">"RightTest"</span> + <span class="string">"/"</span> + <span class="built_in">str</span>(counter) + <span class="string">".jpg"</span>)</span><br><span class="line">left_region.save(folder + <span class="string">"LeftTest"</span> + <span class="string">"/"</span> + <span class="built_in">str</span>(counter) + <span class="string">".jpg"</span>)</span><br></pre></td></tr></table></figure>
<blockquote>
<ul>
<li>读取图片然后再进行分割,之后保存。</li>
<li>C++代码:<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"> <span class="function">VideoCapture <span class="title">capture</span><span class="params">(<span class="number">0</span>)</span></span>;</span><br><span class="line">Mat frame;</span><br><span class="line"><span class="keyword">if</span> (!capture.<span class="built_in">isOpened</span>())</span><br><span class="line">{</span><br><span class="line"> cout << <span class="string">"摄像头打开失败"</span> << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">char</span> key;</span><br><span class="line"><span class="keyword">char</span> filename[<span class="number">200</span>] = <span class="string">"F:\VisualStudioProject\OpencvTest\srcPicture"</span>;<span class="comment">//此路径需要根据自己电脑进行设置</span></span><br><span class="line"><span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">namedWindow</span>(<span class="string">"【视频】"</span>, <span class="number">1</span>);</span><br><span class="line"><span class="built_in">namedWindow</span>(<span class="string">"【图片】"</span>, <span class="number">1</span>);</span><br><span class="line"><span class="keyword">while</span> (<span class="number">1</span>) {</span><br><span class="line"> key = <span class="built_in">waitKey</span>(<span class="number">30</span>);</span><br><span class="line"> capture >> frame;</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"【视频】"</span>, frame);</span><br><span class="line"> <span class="comment">/*imwrite(filename, frame);*/</span></span><br><span class="line"> <span class="keyword">if</span> (key == <span class="number">27</span>)</span><br><span class="line"> <span class="keyword">break</span>;<span class="comment">//按ESC键退出程序 </span></span><br><span class="line"> <span class="keyword">if</span> (key == <span class="number">32</span>)<span class="comment">//按空格键进行拍照 </span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">sprintf_s</span>(filename, <span class="string">"%d.jpg"</span>, ++count);</span><br><span class="line"> cout << <span class="string">"执行完毕"</span> << endl;</span><br><span class="line"> <span class="built_in">imwrite</span>(filename, frame);<span class="comment">//图片保存到本工程目录中 </span></span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"【图片】"</span>, frame);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="对图片进行立体矫正"><a href="#对图片进行立体矫正" class="headerlink" title="对图片进行立体矫正"></a>对图片进行立体矫正</h2></li>
</ul>
</blockquote>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="comment">/*立体校正*/</span></span><br><span class="line"><span class="built_in">Rodrigues</span>(rec, R); <span class="comment">//Rodrigues变换</span></span><br><span class="line"><span class="built_in">stereoRectify</span>(cameraMatrixL, distCoeffL, cameraMatrixR, distCoeffR,imageSize, R, T, Rl, Rr, Pl, Pr, Q, CALIB_ZERO_DISPARITY,<span class="number">0</span>, imageSize, &validROIL, &validROIR);</span><br><span class="line"><span class="built_in">initUndistortRectifyMap</span>(cameraMatrixL, distCoeffL,Rl,Pr,imageSize,CV_32FC1, mapLx, mapLy);</span><br><span class="line"><span class="built_in">initUndistortRectifyMap</span>(cameraMatrixR, distCoeffR,Rr,Pr,imageSize,CV_32FC1, mapRx, mapRy);</span><br></pre></td></tr></table></figure>
<h2 id="立体匹配"><a href="#立体匹配" class="headerlink" title="立体匹配"></a>立体匹配</h2><blockquote>
<p>采用Block Matching算法进行立体匹配,Block Matching用的是SAD方法,速度比较快,但效果一般。</p>
</blockquote>
<p><code>参数设置:</code></p>
<ul>
<li>MinDisparity设置为0,因为两个摄像头是前向平行放置,相同的物体在左图中一定比在右图中偏右。如果为了追求更大的双目重合区域而将两个摄像头向内偏转的话,这个参数是需要考虑的。 </li>
<li>UniquenessRatio主要可以防止误匹配,此参数对于最后的匹配结果是有很大的影响。立体匹配中,宁愿区域无法匹配,也不要误匹配。如果有误匹配的话,碰到障碍检测这种应用,就会很麻烦。该参数不能为负值,一般5-15左右的值比较合适,int型。</li>
<li>BlockSize:SAD窗口大小,容许范围是[5,255],一般应该在 5x5..21x21 之间,参数必须为奇数值, int型。</li>
<li>NumDisparities:视差窗口,即最大视差值与最小视差值之差,窗口大小必须是 16的整数倍,int型。 </li>
<li>在BM算法的参数中,对视差生成效果影响较大的主要参数是BlockSize、NumDisparities和UniquenessRatio三个,一般只需对这三个参数进行调整,其余参数按默认设置即可。 </li>
</ul>
<p><code>双目摄像头的原理:</code></p>
<p><img src="https://raw.githubusercontent.com/kentanvictor/STUDY/Image/StereoPhoto.png" alt=""></p>
<blockquote>
<p>BM算法计算出的视差disp是CV_16S格式,通过disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.))变换才能得到真实的视差值。<br>然后通过reprojectImageTo3D这个函数将视差矩阵转换成实际的物理坐标矩阵。在实际求距离时,reprojectImageTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。 </p>
</blockquote>
<ul>
<li>立体匹配代码:<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="comment">/*****立体匹配*****/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">stereo_match</span><span class="params">(<span class="keyword">int</span>, <span class="keyword">void</span>*)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> bm-><span class="built_in">setBlockSize</span>(<span class="number">2</span> * blockSize + <span class="number">5</span>); <span class="comment">//SAD窗口大小,5~21之间为宜</span></span><br><span class="line"> bm-><span class="built_in">setROI1</span>(validROIL);</span><br><span class="line"> bm-><span class="built_in">setROI2</span>(validROIR);</span><br><span class="line"> bm-><span class="built_in">setPreFilterCap</span>(<span class="number">31</span>);</span><br><span class="line"> bm-><span class="built_in">setMinDisparity</span>(<span class="number">0</span>); <span class="comment">//最小视差,默认值为0, 可以是负值,int型</span></span><br><span class="line"> bm-><span class="built_in">setNumDisparities</span>(numDisparities * <span class="number">16</span> + <span class="number">16</span>);<span class="comment">//视差窗口,即最大视差值与最小视差值之差,窗口大小必须是16的整数倍,int型</span></span><br><span class="line"> bm-><span class="built_in">setTextureThreshold</span>(<span class="number">10</span>);</span><br><span class="line"> bm-><span class="built_in">setUniquenessRatio</span>(uniquenessRatio);<span class="comment">//uniquenessRatio主要可以防止误匹配</span></span><br><span class="line"> bm-><span class="built_in">setSpeckleWindowSize</span>(<span class="number">100</span>);</span><br><span class="line"> bm-><span class="built_in">setSpeckleRange</span>(<span class="number">32</span>);</span><br><span class="line"> bm-><span class="built_in">setDisp12MaxDiff</span>(<span class="number">-1</span>);</span><br><span class="line"> Mat disp, disp8,copyImage;</span><br><span class="line"> bm-><span class="built_in">compute</span>(rectifyImageL, rectifyImageR, disp);<span class="comment">//输入图像必须为灰度图</span></span><br><span class="line"> disp.<span class="built_in">convertTo</span>(disp8, CV_8U, <span class="number">255</span> / ((numDisparities * <span class="number">16</span> + <span class="number">16</span>)*<span class="number">16.</span>));<span class="comment">//计算出的视差是CV_16S格式</span></span><br><span class="line"> <span class="built_in">reprojectImageTo3D</span>(disp, xyz, Q, <span class="literal">true</span>); <span class="comment">//在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。</span></span><br><span class="line"> xyz = xyz * <span class="number">16</span>;</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"disparity"</span>, disp8);</span><br><span class="line"> copyImage = disp8.<span class="built_in">clone</span>();</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"contour"</span>, copyImage);</span><br><span class="line"> <span class="comment">//根据现有的视差图进行凸包的绘制</span></span><br><span class="line"> Mat threshold_output;</span><br><span class="line"> vector<vector<Point> > contours;</span><br><span class="line"> vector<Vec4i> hierarchy;</span><br><span class="line"> <span class="function">RNG <span class="title">rng</span><span class="params">(<span class="number">12345</span>)</span></span>;</span><br><span class="line"> <span class="built_in">threshold</span>(copyImage, threshold_output, <span class="number">20</span>, <span class="number">255</span>, CV_THRESH_BINARY);<span class="comment">//二值化</span></span><br><span class="line"> <span class="built_in">findContours</span>(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, <span class="built_in">Point</span>(<span class="number">0</span>, <span class="number">0</span>));<span class="comment">//寻找轮廓</span></span><br><span class="line"> <span class="comment">/// 对每个轮廓计算其凸包</span></span><br><span class="line"> vector<vector<Point> ><span class="built_in">hull</span>(contours.<span class="built_in">size</span>());</span><br><span class="line"> vector<vector<Point> > result;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < contours.<span class="built_in">size</span>(); i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">convexHull</span>(<span class="built_in">Mat</span>(contours[i]), hull[i], <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/// 绘出轮廓及其凸包</span></span><br><span class="line"> Mat drawing = Mat::<span class="built_in">zeros</span>(threshold_output.<span class="built_in">size</span>(), CV_8UC3);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< contours.<span class="built_in">size</span>(); i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">contourArea</span>(contours[i]) < <span class="number">500</span>)<span class="comment">//面积小于area的凸包,可忽略</span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> result.<span class="built_in">push_back</span>(hull[i]);</span><br><span class="line"> Scalar color = <span class="built_in">Scalar</span>(rng.<span class="built_in">uniform</span>(<span class="number">0</span>, <span class="number">255</span>), rng.<span class="built_in">uniform</span>(<span class="number">0</span>, <span class="number">255</span>), rng.<span class="built_in">uniform</span>(<span class="number">0</span>, <span class="number">255</span>));</span><br><span class="line"> <span class="built_in">drawContours</span>(drawing, contours, i, color, <span class="number">1</span>, <span class="number">8</span>, vector<Vec4i>(), <span class="number">0</span>, <span class="built_in">Point</span>());</span><br><span class="line"> <span class="built_in">drawContours</span>(drawing, hull, i, color, <span class="number">1</span>, <span class="number">8</span>, vector<Vec4i>(), <span class="number">0</span>, <span class="built_in">Point</span>());</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"contours"</span>, drawing);<span class="comment">//凸包大小</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="总结:-1"><a href="#总结:-1" class="headerlink" title="总结:"></a>总结:</h2><blockquote>
<p>使用MatLab或者OpenCV进行内参以及外参的设定,然后将测出的数据填入到代码中,再使用立体矫正以及立体匹配,这样就可以得到深度图,使用深度图再进行视差运算,得到视差图。</p>
<ul>
<li>完整代码如下:<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><opencv2\opencv.hpp></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"opencv2/imgproc/imgproc.hpp"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><opencv2/core/core.hpp></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><opencv2/highgui/highgui.hpp></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> cv;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> imageWidth = <span class="number">320</span>; <span class="comment">//摄像头的分辨率 </span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> imageHeight = <span class="number">240</span>;</span><br><span class="line">Size imageSize = <span class="built_in">Size</span>(imageWidth, imageHeight);</span><br><span class="line"></span><br><span class="line">Mat rgbImageL, grayImageL;</span><br><span class="line">Mat rgbImageR, grayImageR;</span><br><span class="line">Mat rectifyImageL, rectifyImageR;</span><br><span class="line"></span><br><span class="line">Rect validROIL;<span class="comment">//图像校正之后,会对图像进行裁剪,这里的validROI就是指裁剪之后的区域 </span></span><br><span class="line">Rect validROIR;</span><br><span class="line"></span><br><span class="line">Mat mapLx, mapLy, mapRx, mapRy; <span class="comment">//映射表 </span></span><br><span class="line">Mat Rl, Rr, Pl, Pr, Q; <span class="comment">//校正旋转矩阵R,投影矩阵P 重投影矩阵Q</span></span><br><span class="line">Mat xyz; <span class="comment">//三维坐标</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Point origin; <span class="comment">//鼠标按下的起始点</span></span><br><span class="line">Rect selection; <span class="comment">//定义矩形选框</span></span><br><span class="line"><span class="keyword">bool</span> selectObject = <span class="literal">false</span>; <span class="comment">//是否选择对象</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> blockSize = <span class="number">7</span>, uniquenessRatio = <span class="number">20</span>, numDisparities = <span class="number">0</span>;</span><br><span class="line">Ptr<StereoBM> bm = StereoBM::<span class="built_in">create</span>(<span class="number">16</span>, <span class="number">9</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">事先标定好的相机的参数</span></span><br><span class="line"><span class="comment">fx 0 cx</span></span><br><span class="line"><span class="comment">0 fy cy</span></span><br><span class="line"><span class="comment">0 0 1</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">Mat cameraMatrixL = (Mat_<<span class="keyword">double</span>>(<span class="number">3</span>, <span class="number">3</span>) << <span class="number">248.32797</span>, <span class="number">0</span>, <span class="number">248.24842</span>,</span><br><span class="line"> <span class="number">0</span>, <span class="number">150.87402</span>, <span class="number">114.30813</span>,</span><br><span class="line"> <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>);</span><br><span class="line">Mat distCoeffL = (Mat_<<span class="keyword">double</span>>(<span class="number">5</span>, <span class="number">1</span>) << <span class="number">0.04477</span>, <span class="number">-0.10081</span>, <span class="number">0.01026</span>, <span class="number">0.00132</span>, <span class="number">0.00000</span>);</span><br><span class="line"></span><br><span class="line">Mat cameraMatrixR = (Mat_<<span class="keyword">double</span>>(<span class="number">3</span>, <span class="number">3</span>) << <span class="number">248.74867</span>, <span class="number">0</span>, <span class="number">248.84978</span>,</span><br><span class="line"> <span class="number">0</span>, <span class="number">152.62972</span>, <span class="number">98.07575</span>,</span><br><span class="line"> <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>);</span><br><span class="line">Mat distCoeffR = (Mat_<<span class="keyword">double</span>>(<span class="number">5</span>, <span class="number">1</span>) << <span class="number">-0.04158</span>, <span class="number">0.08338</span>, <span class="number">-0.00584</span>, <span class="number">0.00611</span>, <span class="number">0.00000</span>);</span><br><span class="line"></span><br><span class="line">Mat T = (Mat_<<span class="keyword">double</span>>(<span class="number">3</span>, <span class="number">1</span>) << <span class="number">182.44004</span>, <span class="number">0.20804</span>, <span class="number">0.41865</span>);<span class="comment">//T平移向量</span></span><br><span class="line">Mat rec = (Mat_<<span class="keyword">double</span>>(<span class="number">3</span>, <span class="number">1</span>) << <span class="number">-0.05347</span>, <span class="number">-0.00229</span>, <span class="number">-0.00203</span>);<span class="comment">//rec旋转向量</span></span><br><span class="line">Mat R;<span class="comment">//R 旋转矩阵</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*****立体匹配*****/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">stereo_match</span><span class="params">(<span class="keyword">int</span>, <span class="keyword">void</span>*)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> bm-><span class="built_in">setBlockSize</span>(<span class="number">2</span> * blockSize + <span class="number">5</span>); <span class="comment">//SAD窗口大小,5~21之间为宜</span></span><br><span class="line"> bm-><span class="built_in">setROI1</span>(validROIL);</span><br><span class="line"> bm-><span class="built_in">setROI2</span>(validROIR);</span><br><span class="line"> bm-><span class="built_in">setPreFilterCap</span>(<span class="number">31</span>);</span><br><span class="line"> bm-><span class="built_in">setMinDisparity</span>(<span class="number">0</span>); <span class="comment">//最小视差,默认值为0, 可以是负值,int型</span></span><br><span class="line"> bm-><span class="built_in">setNumDisparities</span>(numDisparities * <span class="number">16</span> + <span class="number">16</span>);<span class="comment">//视差窗口,即最大视差值与最小视差值之差,窗口大小必须是16的整数倍,int型</span></span><br><span class="line"> bm-><span class="built_in">setTextureThreshold</span>(<span class="number">10</span>);</span><br><span class="line"> bm-><span class="built_in">setUniquenessRatio</span>(uniquenessRatio);<span class="comment">//uniquenessRatio主要可以防止误匹配</span></span><br><span class="line"> bm-><span class="built_in">setSpeckleWindowSize</span>(<span class="number">100</span>);</span><br><span class="line"> bm-><span class="built_in">setSpeckleRange</span>(<span class="number">32</span>);</span><br><span class="line"> bm-><span class="built_in">setDisp12MaxDiff</span>(<span class="number">-1</span>);</span><br><span class="line"> Mat disp, disp8,copyImage;</span><br><span class="line"> bm-><span class="built_in">compute</span>(rectifyImageL, rectifyImageR, disp);<span class="comment">//输入图像必须为灰度图</span></span><br><span class="line"> disp.<span class="built_in">convertTo</span>(disp8, CV_8U, <span class="number">255</span> / ((numDisparities * <span class="number">16</span> + <span class="number">16</span>)*<span class="number">16.</span>));<span class="comment">//计算出的视差是CV_16S格式</span></span><br><span class="line"> <span class="built_in">reprojectImageTo3D</span>(disp, xyz, Q, <span class="literal">true</span>); <span class="comment">//在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。</span></span><br><span class="line"> xyz = xyz * <span class="number">16</span>;</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"disparity"</span>, disp8);</span><br><span class="line"> copyImage = disp8.<span class="built_in">clone</span>();</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"contour"</span>, copyImage);</span><br><span class="line"> <span class="comment">//根据现有的视差图进行凸包的绘制</span></span><br><span class="line"> Mat threshold_output;</span><br><span class="line"> vector<vector<Point> > contours;</span><br><span class="line"> vector<Vec4i> hierarchy;</span><br><span class="line"> <span class="function">RNG <span class="title">rng</span><span class="params">(<span class="number">12345</span>)</span></span>;</span><br><span class="line"> <span class="built_in">threshold</span>(copyImage, threshold_output, <span class="number">20</span>, <span class="number">255</span>, CV_THRESH_BINARY);<span class="comment">//二值化</span></span><br><span class="line"> <span class="built_in">findContours</span>(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, <span class="built_in">Point</span>(<span class="number">0</span>, <span class="number">0</span>));<span class="comment">//寻找轮廓</span></span><br><span class="line"> <span class="comment">/// 对每个轮廓计算其凸包</span></span><br><span class="line"> vector<vector<Point> ><span class="built_in">hull</span>(contours.<span class="built_in">size</span>());</span><br><span class="line"> vector<vector<Point> > result;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < contours.<span class="built_in">size</span>(); i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">convexHull</span>(<span class="built_in">Mat</span>(contours[i]), hull[i], <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/// 绘出轮廓及其凸包</span></span><br><span class="line"> Mat drawing = Mat::<span class="built_in">zeros</span>(threshold_output.<span class="built_in">size</span>(), CV_8UC3);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< contours.<span class="built_in">size</span>(); i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">contourArea</span>(contours[i]) < <span class="number">500</span>)<span class="comment">//面积小于area的凸包,可忽略</span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> result.<span class="built_in">push_back</span>(hull[i]);</span><br><span class="line"> Scalar color = <span class="built_in">Scalar</span>(rng.<span class="built_in">uniform</span>(<span class="number">0</span>, <span class="number">255</span>), rng.<span class="built_in">uniform</span>(<span class="number">0</span>, <span class="number">255</span>), rng.<span class="built_in">uniform</span>(<span class="number">0</span>, <span class="number">255</span>));</span><br><span class="line"> <span class="built_in">drawContours</span>(drawing, contours, i, color, <span class="number">1</span>, <span class="number">8</span>, vector<Vec4i>(), <span class="number">0</span>, <span class="built_in">Point</span>());</span><br><span class="line"> <span class="built_in">drawContours</span>(drawing, hull, i, color, <span class="number">1</span>, <span class="number">8</span>, vector<Vec4i>(), <span class="number">0</span>, <span class="built_in">Point</span>());</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"contours"</span>, drawing);<span class="comment">//凸包大小</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*****描述:鼠标操作回调*****/</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">onMouse</span><span class="params">(<span class="keyword">int</span> event, <span class="keyword">int</span> x, <span class="keyword">int</span> y, <span class="keyword">int</span>, <span class="keyword">void</span>*)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (selectObject)</span><br><span class="line"> {</span><br><span class="line"> selection.x = <span class="built_in">MIN</span>(x, origin.x);</span><br><span class="line"> selection.y = <span class="built_in">MIN</span>(y, origin.y);</span><br><span class="line"> selection.width = std::<span class="built_in">abs</span>(x - origin.x);</span><br><span class="line"> selection.height = std::<span class="built_in">abs</span>(y - origin.y);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in"><span class="keyword">switch</span></span> (event)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">case</span> EVENT_LBUTTONDOWN: <span class="comment">//鼠标左按钮按下的事件</span></span><br><span class="line"> origin = <span class="built_in">Point</span>(x, y);</span><br><span class="line"> selection = <span class="built_in">Rect</span>(x, y, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> selectObject = <span class="literal">true</span>;</span><br><span class="line"> cout << origin << <span class="string">"in world coordinate is: "</span> << xyz.at<Vec3f>(origin) << endl;</span><br><span class="line"> <span class="comment">/*cout << origin << "深度信息为:" << xyz.at<Vec3f>(origin) << endl;*/</span></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> EVENT_LBUTTONUP: <span class="comment">//鼠标左按钮释放的事件</span></span><br><span class="line"> selectObject = <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">if</span> (selection.width > <span class="number">0</span> && selection.height > <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="function">VideoCapture <span class="title">capture</span><span class="params">(<span class="number">0</span>)</span></span>;</span><br><span class="line"> Mat frame;</span><br><span class="line"> <span class="keyword">if</span> (!capture.<span class="built_in">isOpened</span>())</span><br><span class="line"> {</span><br><span class="line"> cout << <span class="string">"摄像头打开失败"</span> << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">char</span> key;</span><br><span class="line"> <span class="keyword">char</span> filename[<span class="number">200</span>] = <span class="string">"F:\VisualStudioProject\OpencvTest\srcPicture"</span>;</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">namedWindow</span>(<span class="string">"【视频】"</span>, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">namedWindow</span>(<span class="string">"【图片】"</span>, <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>) {</span><br><span class="line"> key = <span class="built_in">waitKey</span>(<span class="number">30</span>);</span><br><span class="line"> capture >> frame;</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"【视频】"</span>, frame);</span><br><span class="line"> <span class="comment">/*imwrite(filename, frame);*/</span></span><br><span class="line"> <span class="keyword">if</span> (key == <span class="number">27</span>)</span><br><span class="line"> <span class="keyword">break</span>;<span class="comment">//按ESC键退出程序 </span></span><br><span class="line"> <span class="keyword">if</span> (key == <span class="number">32</span>)<span class="comment">//按空格键进行拍照 </span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">sprintf_s</span>(filename, <span class="string">"%d.jpg"</span>, ++count);</span><br><span class="line"> cout << <span class="string">"执行完毕"</span> << endl;</span><br><span class="line"> <span class="built_in">imwrite</span>(filename, frame);<span class="comment">//图片保存到本工程目录中 </span></span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"【图片】"</span>, frame);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> 立体校正</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="built_in">Rodrigues</span>(rec, R); <span class="comment">//Rodrigues变换</span></span><br><span class="line"> <span class="built_in">stereoRectify</span>(cameraMatrixL, distCoeffL, cameraMatrixR, distCoeffR, imageSize, R, T, Rl, Rr, Pl, Pr, Q, CALIB_ZERO_DISPARITY,</span><br><span class="line"> <span class="number">0</span>, imageSize, &validROIL, &validROIR);</span><br><span class="line"> <span class="built_in">initUndistortRectifyMap</span>(cameraMatrixL, distCoeffL, Rl, Pr, imageSize, CV_32FC1, mapLx, mapLy);</span><br><span class="line"> <span class="built_in">initUndistortRectifyMap</span>(cameraMatrixR, distCoeffR, Rr, Pr, imageSize, CV_32FC1, mapRx, mapRy);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> 读取图片</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> string left_test = <span class="string">"F:\\VisualStudioProject\\OpencvTest\\LeftPicture\\LDemo.jpg"</span>;</span><br><span class="line"> string right_test = <span class="string">"F:\\VisualStudioProject\\OpencvTest\\RightPicture\\RDemo.jpg"</span>;</span><br><span class="line"> rgbImageL = <span class="built_in">imread</span>(left_test, CV_LOAD_IMAGE_COLOR);</span><br><span class="line"> <span class="built_in">cvtColor</span>(rgbImageL, grayImageL, CV_BGR2GRAY);</span><br><span class="line"> rgbImageR = <span class="built_in">imread</span>(right_test, CV_LOAD_IMAGE_COLOR);</span><br><span class="line"> <span class="built_in">cvtColor</span>(rgbImageR, grayImageR, CV_BGR2GRAY);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"ImageL Before Rectify"</span>, grayImageL);</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"ImageR Before Rectify"</span>, grayImageR);</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> 经过remap之后,左右相机的图像已经共面并且行对准了</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="built_in">remap</span>(grayImageL, rectifyImageL, mapLx, mapLy, INTER_LINEAR);</span><br><span class="line"> <span class="built_in">remap</span>(grayImageR, rectifyImageR, mapRx, mapRy, INTER_LINEAR);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> 把校正结果显示出来</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> Mat rgbRectifyImageL, rgbRectifyImageR;</span><br><span class="line"> <span class="built_in">cvtColor</span>(rectifyImageL, rgbRectifyImageL, CV_GRAY2BGR); <span class="comment">//伪彩色图</span></span><br><span class="line"> <span class="built_in">cvtColor</span>(rectifyImageR, rgbRectifyImageR, CV_GRAY2BGR);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//单独显示</span></span><br><span class="line"> <span class="comment">//rectangle(rgbRectifyImageL, validROIL, Scalar(0, 0, 255), 3, 8);</span></span><br><span class="line"> <span class="comment">//rectangle(rgbRectifyImageR, validROIR, Scalar(0, 0, 255), 3, 8);</span></span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"ImageL After Rectify"</span>, rgbRectifyImageL);</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"ImageR After Rectify"</span>, rgbRectifyImageR);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//显示在同一张图上</span></span><br><span class="line"> Mat canvas;</span><br><span class="line"> <span class="keyword">double</span> sf;</span><br><span class="line"> <span class="keyword">int</span> w, h;</span><br><span class="line"> sf = <span class="number">600.</span> / <span class="built_in">MAX</span>(imageSize.width, imageSize.height);</span><br><span class="line"> w = <span class="built_in">cvRound</span>(imageSize.width * sf);</span><br><span class="line"> h = <span class="built_in">cvRound</span>(imageSize.height * sf);</span><br><span class="line"> canvas.<span class="built_in">create</span>(h, w * <span class="number">2</span>, CV_8UC3); <span class="comment">//注意通道</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//左图像画到画布上</span></span><br><span class="line"> Mat canvasPart = <span class="built_in">canvas</span>(<span class="built_in">Rect</span>(w * <span class="number">0</span>, <span class="number">0</span>, w, h)); <span class="comment">//得到画布的一部分 </span></span><br><span class="line"> <span class="built_in">resize</span>(rgbRectifyImageL, canvasPart, canvasPart.<span class="built_in">size</span>(), <span class="number">0</span>, <span class="number">0</span>, INTER_AREA); <span class="comment">//把图像缩放到跟canvasPart一样大小 </span></span><br><span class="line"> <span class="function">Rect <span class="title">vroiL</span><span class="params">(cvRound(validROIL.x*sf), cvRound(validROIL.y*sf), <span class="comment">//获得被截取的区域 </span></span></span></span><br><span class="line"><span class="params"><span class="function"> cvRound(validROIL.width*sf), cvRound(validROIL.height*sf))</span></span>;</span><br><span class="line"> <span class="comment">//rectangle(canvasPart, vroiL, Scalar(0, 0, 255), 3, 8); //画上一个矩形 </span></span><br><span class="line"> cout << <span class="string">"Painted ImageL"</span> << endl;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//右图像画到画布上</span></span><br><span class="line"> canvasPart = <span class="built_in">canvas</span>(<span class="built_in">Rect</span>(w, <span class="number">0</span>, w, h)); <span class="comment">//获得画布的另一部分 </span></span><br><span class="line"> <span class="built_in">resize</span>(rgbRectifyImageR, canvasPart, canvasPart.<span class="built_in">size</span>(), <span class="number">0</span>, <span class="number">0</span>, INTER_LINEAR);</span><br><span class="line"> <span class="function">Rect <span class="title">vroiR</span><span class="params">(cvRound(validROIR.x * sf), cvRound(validROIR.y*sf),</span></span></span><br><span class="line"><span class="params"><span class="function"> cvRound(validROIR.width * sf), cvRound(validROIR.height * sf))</span></span>;</span><br><span class="line"> <span class="comment">//rectangle(canvasPart, vroiR, Scalar(0, 0, 255), 3, 8);</span></span><br><span class="line"> cout << <span class="string">"Painted ImageR"</span> << endl;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//画上对应的线条</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < canvas.rows; i += <span class="number">16</span>)</span><br><span class="line"> <span class="built_in">line</span>(canvas, <span class="built_in">Point</span>(<span class="number">0</span>, i), <span class="built_in">Point</span>(canvas.cols, i), <span class="built_in">Scalar</span>(<span class="number">0</span>, <span class="number">255</span>, <span class="number">0</span>), <span class="number">1</span>, <span class="number">8</span>);</span><br><span class="line"> <span class="built_in">imshow</span>(<span class="string">"rectified"</span>, canvas);</span><br><span class="line"> <span class="comment">//find_obstacle(grayImageL, 20, 255, 500);</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> 立体匹配</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="built_in">namedWindow</span>(<span class="string">"disparity"</span>, CV_WINDOW_AUTOSIZE);</span><br><span class="line"> <span class="comment">// 创建SAD窗口 Trackbar</span></span><br><span class="line"> <span class="built_in">createTrackbar</span>(<span class="string">"BlockSize:\n"</span>, <span class="string">"disparity"</span>, &blockSize, <span class="number">8</span>, stereo_match);</span><br><span class="line"> <span class="comment">// 创建视差唯一性百分比窗口 Trackbar</span></span><br><span class="line"> <span class="built_in">createTrackbar</span>(<span class="string">"UniquenessRatio:\n"</span>, <span class="string">"disparity"</span>, &uniquenessRatio, <span class="number">50</span>, stereo_match);</span><br><span class="line"> <span class="comment">// 创建视差窗口 Trackbar</span></span><br><span class="line"> <span class="built_in">createTrackbar</span>(<span class="string">"NumDisparities:\n"</span>, <span class="string">"disparity"</span>, &numDisparities, <span class="number">16</span>, stereo_match);</span><br><span class="line"> <span class="comment">//鼠标响应函数setMouseCallback(窗口名称, 鼠标回调函数, 传给回调函数的参数,一般取0)</span></span><br><span class="line"> <span class="built_in">setMouseCallback</span>(<span class="string">"disparity"</span>, onMouse, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">stereo_match</span>(<span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">waitKey</span>(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
</blockquote>
<p><code>备注:</code></p>
<ul>
<li>上面的代码中,需要自己填入的数据有:</li>
<li><ul>
<li>测定的摄像头的内参以及外参</li>
</ul>
</li>
<li><ul>
<li>保存以及读取图片的路径</li>
</ul>
</li>
</ul>
]]></content>
<categories>
<category>Computer Vision</category>
</categories>
<tags>
<tag>Computer Vision</tag>
</tags>
</entry>
<entry>
<title>Tile Geotiff Format File</title>
<url>/2022/10/14/Research%20of%20Geotiff%20Format%20File%20Tile/</url>
<content><![CDATA[<h1 id="Research-of-Geotiff-Format-File-Tile"><a href="#Research-of-Geotiff-Format-File-Tile" class="headerlink" title="Research of Geotiff Format File Tile"></a>Research of Geotiff Format File Tile</h1><blockquote>
<p>It is relatively easy to slice GeoTiff type files using the python language, and the main investigation and research here is an attempt to slice Geotiff using the Java language.</p>
</blockquote>
<h2 id="What-is-GeoTiff-File"><a href="#What-is-GeoTiff-File" class="headerlink" title="What is GeoTiff File?"></a>What is GeoTiff File?</h2><h2 id="Implementations-of-Geotiff-File-Tile"><a href="#Implementations-of-Geotiff-File-Tile" class="headerlink" title="Implementations of Geotiff File Tile"></a>Implementations of Geotiff File Tile</h2><h3 id="ImageMagick"><a href="#ImageMagick" class="headerlink" title="ImageMagick"></a>ImageMagick</h3><h3 id="Gdal"><a href="#Gdal" class="headerlink" title="Gdal"></a>Gdal</h3><h3 id="Geotools"><a href="#Geotools" class="headerlink" title="Geotools"></a>Geotools</h3>]]></content>
<tags>
<tag>Map</tag>
</tags>
</entry>
<entry>
<title>The analysis of android lifecycle</title>
<url>/2022/10/14/The%20analysis%20of%20android%20lifecycle/</url>
<content><![CDATA[<h1 id="The-analysis-of-android-lifecycle"><a href="#The-analysis-of-android-lifecycle" class="headerlink" title="The analysis of android lifecycle"></a>The analysis of android lifecycle</h1><ul>
<li><p>The lifecycle of activity is divided into two parts</p>
<ul>
<li><p>Typical lifecycle</p>
<blockquote>
<p>During normal user use, the lifecycle of Android activity will change</p>
</blockquote>
</li>
<li><p>Lifecycle under abnormal conditions</p>
<blockquote>
<p>Refers to the activity being recycled by the system or the activity being destroyed and rebuilt due to the current device Configuration change</p>
</blockquote>
</li>
</ul>
<span id="more"></span>
</li>
</ul>
<h2 id="Lifecycle-Analysis-in-Typical-Scenarios"><a href="#Lifecycle-Analysis-in-Typical-Scenarios" class="headerlink" title="Lifecycle Analysis in Typical Scenarios"></a>Lifecycle Analysis in Typical Scenarios</h2><h3 id="Normal-life-cycle-analysis"><a href="#Normal-life-cycle-analysis" class="headerlink" title="Normal life cycle analysis"></a>Normal life cycle analysis</h3><p>Under normal circumstances, an activity will go through the following life cycle</p>
<ul>
<li>onCreate: Indicates that the activity is being created.</li>
</ul>
<blockquote>
<ul>
<li>This is the first method of the life cycle. In this method, we can do some initialization work, such as calling setContentView to load interface layout resources, initialize the data required by activity, etc.</li>
<li>By overriding the onCreate(Bundle) method, the activity can preprocess the following UI related work:</li>
<li>Instantiate components and place them on screen (call setContentView(int) method)</li>
<li>reference to the instantiated component</li>
<li>Set up listeners for components to handle user interactions</li>
<li>access external model data</li>
</ul>
<ul>
<li>onRestart: Indicates that the activity is starting.<br>In general, onRestart is called when the current activity is changed from invisible to visible again. <strong>This situation is generally caused by the user. When the user presses the Home button to switch to the desktop or the user opens a new activity, the current activity will be paused, that is, onPause and onStop are executed, and then the user restarts. Back to this activity, this will happen</strong></li>
<li>onStart: Indicates that the activity is being started and is about to start.<br>At this time, the activity is already visible, but it has not yet appeared in the foreground and cannot interact with the user. At this time, it can actually be understood that the activity has been displayed, but we can’t see it yet</li>
<li>onResume: Indicates that the activity is already visible, and appears in the foreground and starts the activity.<br>Pay attention to the contrast between this and onStart. Both onStart and onResume indicate that the activity is already visible, but the activity is still in the background when onStart, and the activity is displayed in the foreground when onResume.</li>
<li>onPause: Indicates that the activity is being stopped. Under normal circumstances, onStop will be called immediately.<br>In special cases, if you quickly return to the current activity at this time, then onResume will be called. It can be understood that this is an extreme situation, and it is difficult for user operations to reproduce this scenario. At this time, you can do some work such as storing data, stopping animation, etc., but be careful not to take too long, because this will affect the display of the new activity, onPause must be executed first, and the onPause of the new activity will be executed.</li>
<li>onStop: Indicates that the activity is about to stop, you can do some heavyweight recycling work, and it can’t be too time-consuming.</li>
<li>onDestroy: Indicates that the activity is about to be destroyed.<br>This is the last callback in the activity’s life cycle, where we can do some recycling and final resource release.</li>
</ul>
</blockquote>
<p><img src="https://github.com/kentanvictor/STUDY/blob/Image/old_image/activity.png?raw=true" alt=""></p>
<p><code>Note:</code></p>
<ul>
<li>When an <strong>activity</strong> starts for the first time, the callback procedure is as follows: onCreate()->onStart()->onResume()</li>
<li>When the user opens a <strong>new activity</strong> or <strong>switches back to the desktop</strong>, the callback is as follows: onPause()->onStop()</li>
<li>The user <strong>returns to the original activity</strong>, the callback is as follows; onRestart()->onStart()->onResume()</li>
<li><strong>back key</strong> When going back, the callback is as follows: onPause()->onStop()->onDestroy()</li>
</ul>
<p><code>From the whole life cycle:</code>onCreate() is paired with onDestroy().</p>
<p><code>In terms of whether the activity is visible:</code>onStart() is paired with onStop().</p>
<p><code>From whether the activity is in the foreground:</code>onResume() and onPause() are paired.</p>
<hr>
<p><code>Question:</code>Assuming that it is currently activity A, if the user opens an activity B at this time, is B’s onResume() executed first or A’s onPause() executed first?</p>
<p><code>Conclusion:</code>OnPause() in the old activity is called first, and onResume() in the new activity is executed.</p>
<h2 id="Lifecycle-Analysis-in-Exceptional-Situations"><a href="#Lifecycle-Analysis-in-Exceptional-Situations" class="headerlink" title="Lifecycle Analysis in Exceptional Situations"></a>Lifecycle Analysis in Exceptional Situations</h2><h3 id="Resource-related-system-configuration-changes-cause-the-activity-to-be-killed-and-rebuilt"><a href="#Resource-related-system-configuration-changes-cause-the-activity-to-be-killed-and-rebuilt" class="headerlink" title="Resource-related system configuration changes cause the activity to be killed and rebuilt"></a>Resource-related system configuration changes cause the activity to be killed and rebuilt</h3><blockquote>
<p>By default, if we don’t do special handling of the activity, then when the system configuration or resources change, the activity will be destroyed and rebuilt. Such as: rotating the phone screen, etc.</p>
</blockquote>
<p><code>Note:</code></p>
<ul>
<li>The activity is killed and rebuilt abnormally, and onPause(), onStop(), and onDestroy() in the activity will be called.</li>
<li>The system will call the <strong>onSaveInstanceState()</strong> method to save the state of the current activity. The calling position is before onStop(), <strong>sequence has nothing to do with onPause()</strong>.</li>
<li>In terms of timing, <strong>onRestoreInstanceState()</strong> is after onStart().</li>
</ul>
<p>An example diagram is shown in the figure:<br><img src="https://github.com/kentanvictor/STUDY/blob/Image/Android%E5%BC%80%E5%8F%91%E6%8E%A2%E7%B4%A2/%E5%BC%82%E5%B8%B8%E6%83%85%E5%86%B5%E4%B8%8Bactivity%E9%87%8D%E5%BB%BA%E8%BF%87%E7%A8%8B.png?raw=true" alt=""></p>
<ul>
<li>When transferring data through onSaveInstanceState and onRestoreInstanceState, there are two locations for receiving parameters passed by onSaveInstanceState: 1. onRestoreInstanceState; 2. onCreate<ul>
<li><code>Note: If</code>onCreate is started normally, <strong> its parameter Bundle savedInstanceState is null, </strong> you need to judge whether savedInstanceState is empty.</li>
</ul>
</li>
</ul>
<h3 id="Insufficient-resource-memory-causes-low-priority-activity-to-be-killed"><a href="#Insufficient-resource-memory-causes-low-priority-activity-to-be-killed" class="headerlink" title="Insufficient resource memory causes low priority activity to be killed"></a>Insufficient resource memory causes low priority activity to be killed</h3><blockquote>
<p>Activity priority situation, from high to low, can be divided into:</p>
</blockquote>
<ul>
<li>foreground activity - the activity that is interacting with the user - the highest priority</li>
<li>Visible but not foreground activity - such as popping up a Dialog causing the activity to be visible but not interactive</li>
<li>Background activity - suspended activity - lowest priority</li>
</ul>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>重构-App研发</title>
<url>/2020/09/28/%E9%87%8D%E6%9E%84-App%E7%A0%94%E5%8F%91/</url>
<content><![CDATA[<h1 id="重构,夜未眠"><a href="#重构,夜未眠" class="headerlink" title="重构,夜未眠"></a>重构,夜未眠</h1><h2 id="为Activity定义新的生命周期"><a href="#为Activity定义新的生命周期" class="headerlink" title="为Activity定义新的生命周期"></a>为Activity定义新的生命周期</h2><p>重点:<code>单一职责</code>->一个类或者方法,只做一件事情</p>
<span id="more"></span>
<h3 id="重构一:"><a href="#重构一:" class="headerlink" title="重构一:"></a>重构一:</h3><ul>
<li>原来的代码结构:</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginActivity</span> <span class="keyword">extends</span> <span class="title">Activity</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">onClickListener</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle saveInstanceState)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.activity_main);</span><br><span class="line"></span><br><span class="line"> Bundle bundle = getIntent().getExtras();</span><br><span class="line"> String strEmail = bundle.getString(AppConstants.Email);</span><br><span class="line"></span><br><span class="line"> etEmail = (EditText) findViewById(R.id.email);</span><br><span class="line"> etEmail.setText(strEmail);</span><br><span class="line"> etPassword = (EditText) findViewById(R.id.password);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//登录事件</span></span><br><span class="line"> Button btnLogin = (Button) findViewById(R.id.sign_in_button);</span><br><span class="line"> btnLogin.setOnClickListener(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取2个MobileAPI,获取天气数据,获取城市数据</span></span><br><span class="line"> loadWeatherData();</span><br><span class="line"> loadCityData();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>从上面的Oncreate()方法中,可以看出,需要做的事情太多了,其实可以简化成三块:</p>
<ul>
<li><p>initVariables</p>
</li>
<li><p>initViews</p>
</li>
<li><p>loadData</p>
</li>
</ul>
<p>代码如下:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">BaseActivity</span> <span class="keyword">extends</span> <span class="title">Activity</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle saveInstanceState)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"></span><br><span class="line"> initVariables();</span><br><span class="line"> initViews(savedInstanceState);</span><br><span class="line"> loadData();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">initVariables</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">initViews</span><span class="params">(Bundle savedInstanceState)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">loadData</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="重构二:"><a href="#重构二:" class="headerlink" title="重构二:"></a>重构二:</h3><p>一般的,对点击事件的监听方式可以有以下两种:</p>
<ul>
<li>第一种:</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginActivity</span> <span class="keyword">extends</span> <span class="title">Activity</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span></span>{</span><br><span class="line"> <span class="comment">//省略代码</span></span><br><span class="line"></span><br><span class="line"> Button btnLogin = (Button)findViewById(R.id.sign_in_button);</span><br><span class="line"> btnLogin.setOnClickListener(<span class="keyword">this</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View v)</span></span>{</span><br><span class="line"> <span class="keyword">switch</span>(v.getId()){</span><br><span class="line"> <span class="keyword">case</span> R.id.sign_in_button:</span><br><span class="line"> Intent intent = <span class="keyword">new</span> Intent(LoginActivity.<span class="keyword">this</span>,PersonCenterActivity.class);</span><br><span class="line"> startActivity(intent);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>第二种:</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">//登录事件</span></span><br><span class="line">btnLogin = (Button) findViewById(R.id.sign_in_button);</span><br><span class="line">btnLogin.setOnClickListener(<span class="keyword">new</span> View.OnClickListener{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View v)</span></span>{</span><br><span class="line"> getoLoginActivity();</span><br><span class="line"> }</span><br><span class="line">});</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>书中更推荐使用<code>第二种</code>方式进行实现,其给出的原因是:</p>
<p>第二种相比较于第一种:</p>
<ul>
<li>直接在btnLogin这个按钮对象上增加点击事件,是面向对象的写法。</li>
<li>将onClick方面的实现,封装成一个gotoLoginActivity方法。</li>
</ul>
<h2 id="实体化编程"><a href="#实体化编程" class="headerlink" title="实体化编程"></a>实体化编程</h2>]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>C++并发的世界</title>
<url>/2020/07/15/C++%E5%B9%B6%E5%8F%91%E7%9A%84%E4%B8%96%E7%95%8C/</url>
<content><![CDATA[<h1 id="C-的并发世界"><a href="#C-的并发世界" class="headerlink" title="C++的并发世界"></a>C++的并发世界</h1><p>主要内容:</p>
<ul>
<li>什么是并发和多线程?</li>
<li>为什么用并发和多线程?</li>
<li>如何用并发和多线程?</li>
</ul>
<span id="more"></span>
<h2 id="什么是并发?"><a href="#什么是并发?" class="headerlink" title="什么是并发?"></a>什么是并发?</h2><p>两个或更多独立的活动同时进行。在计算机领域中表现为:<strong>单个系统中同时执行多个独立的任务。</strong></p>
<h3 id="单核任务切换VS多核硬件并发"><a href="#单核任务切换VS多核硬件并发" class="headerlink" title="单核任务切换VS多核硬件并发"></a>单核任务切换VS多核硬件并发</h3><ul>
<li>单核任务切换</li>
</ul>
<p><img src="https://github.com/kentanvictor/STUDY/blob/Image/C%2B%2B%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%AE%9E%E6%88%98/%E5%8D%95%E6%A0%B8%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2.png?raw=true" alt="单核切换"></p>
<ul>
<li>多核硬件并发</li>
</ul>
<p><img src="https://github.com/kentanvictor/STUDY/blob/Image/C%2B%2B%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%AE%9E%E6%88%98/%E5%A4%9A%E6%A0%B8%E7%A1%AC%E4%BB%B6%E5%B9%B6%E5%8F%91.png?raw=true" alt="多核硬件并发"></p>
<h3 id="多进程并发"><a href="#多进程并发" class="headerlink" title="多进程并发"></a>多进程并发</h3><p>独立进程可通过进程间常规的通信渠道传递信息(信号、套接字、文件、管道等等)。</p>
<p>缺点之一:运行进程所需的固定开销:需要时间启动进程,操作系统需要内部资源来管理进程等等。</p>
<p>独立进程实现并发的额外优势:可通过远程连接在不同的机器上运行独立的进程。</p>
<h3 id="多线程并发"><a href="#多线程并发" class="headerlink" title="多线程并发"></a>多线程并发</h3><p>每个线程相互独立运行,并共享地址空间,因此线程可以通过共享内存进行通信。</p>
<p><strong>如果数据要被多个线程访问,那么必须保证每个线程所访问到的数据是一致的</strong></p>
]]></content>
<categories>
<category>C&C++</category>
</categories>
<tags>
<tag>C&C++</tag>
</tags>
</entry>
<entry>
<title>Android mental journey</title>
<url>/2020/07/04/Android%E5%BF%83%E8%B7%AF%E5%8E%86%E7%A8%8B/</url>
<content><![CDATA[<h1 id="Android-learning-journey"><a href="#Android-learning-journey" class="headerlink" title="Android learning journey"></a>Android learning journey</h1><p>Foreword:</p>
<p>Since joining the Android Lab in 2016, I have been exposed to Android programming and purchased the first book “The First Line of Code” related to Android development. I am deeply attracted by Android development. It can be said that in my mental process of learning programming, Android development can be said to be the middle line, which runs through my learning career.</p>
<span id="more"></span>
<p><img src="https://github.com/kentanvictor/STUDY/blob/Image/Android%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF.png?raw=true" alt="Android Learning Roadmap"></p>
<p><code>Android development resources:</code></p>
<ul>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/%E7%AC%AC%E4%B8%80%E8%A1%8C%E4%BB%A3%E7%A0%81%EF%BC%88%E7%AC%AC2%E7%89%88%EF%BC%89.pdf">first line of code</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/Android%E9%9D%A2%E8%AF%95%E6%8C%87%E5%8D%97.pdf">Android Interview Guide</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/Android%E7%BE%A4%E8%8B%B1%E4%BC%A0.pdf">Android Legends</a></p>
</li>
</ul>
<h2 id="2016"><a href="#2016" class="headerlink" title="2016"></a>2016</h2><ul>
<li><p>When I first entered the school in my freshman year, I was curious about everything. At that time, my advisor, who was already a junior at that time, learned about the school’s Android lab with us. As the vice chairman of the Youth League Committee of the college, he Possess exceptional personal abilities. Under his propaganda, I also entered the Android Lab with a curious attitude to study.</p>
</li>
<li><p>When I entered the Android Lab in 2016, through a week of training, I briefly learned the C language, but I still need to consolidate the school curriculum. Through Mr. Jing Chao’s explanation in the class, I really understood and understood the path of programming.</p>
</li>
<li><p>In 2016, I not only learned C language, but also gradually came into contact with Java programming and development, because Android development is actually written in Java language (in the beginning, now there is kotlin). So I continue to learn Java development while following the weekly training in Android Labs. In the last winter vacation, the laboratory’s requirement for every freshman and sophomore is to write an app independently, and I also implemented an app of my own during the winter vacation.</p>
</li>
</ul>
<p><code>Java Basics:</code></p>
<ul>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/Head%20First%20Java%EF%BC%88%E4%B8%AD%E6%96%87%E7%89%88%EF%BC%89.pdf">Head First Java</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/Java%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%AE%9E%E6%88%98%EF%BC%88%E4%B8%AD%E6%96%87%E7%89%88%EF%BC%89.pdf">Java concurrent programming practice</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/Effective%2BJava%2B%E4%B8%AD%E6%96%87%E7%AC%AC%E4%BA%8C%E7%89%88.pdf">Effective Java</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/Java%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3.pdf">Thinking in Java</a></p>
</li>
</ul>
<h2 id="2017"><a href="#2017" class="headerlink" title="2017"></a>2017</h2><ul>
<li><p>During 2017, it should be regarded as the year that I made the most rapid progress in Android learning. During this year, the course of the school also opened the course of Java programming, so I not only followed the learning progress of the laboratory, but also passed the school. The courses solidified my foundation. During this period, I also tried through the ghostwriting group of a treasure, and made a fortune by writing code for the first time. <strong>I still do not recommend individuals to take up such outsourcing projects during school, because in this way, your taste for learning will change.</strong></p>
</li>
<li><p>While writing the code of the Android client, I also learned courses such as database, data structure, C++, etc., and also learned multi-threading and Android custom controls. I have tried to imitate others to write one by myself. own project. Such as: <a href="https://github.com/kentanvictor/AirScraftDemo">Aircraft War</a>, <a href="https://github.com/kentanvictor/CoolWeather">Weather app</a> and so on.</p>
</li>
</ul>
<p><code>Programmer must:</code></p>
<ul>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/GitHub%E5%85%A5%E9%97%A8%E4%B8%8E%E5%AE%9E%E8%B7%B5.pdf">GitHub Getting Started and Practice</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/%E7%A6%BB%E6%95%A3%E6%95%B0%E5%AD%A6%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8.pdf">discrete mathematics and its applications</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E6%95%B0%E5%AD%A6.pdf">math for programmers</a></p>
</li>
</ul>
<h2 id="2018"><a href="#2018" class="headerlink" title="2018"></a>2018</h2><ul>
<li><p>When I was in my third year of college, I was exposed to the lower-level things of Android development. I also learned courses such as computer network, operating system, computer composition principle, software engineering and other courses through school courses. Implement small ideas by writing code. I also try to open my eyes to different programming languages or other fun things, such as: <a href="https://github.com/kentanvictor/DjangoTest">Django local server</a>. But Android still maintains learning and practice, such as: <a href="https://github.com/kentanvictor/CarRepair">Car Mall</a>.</p>
</li>
<li><p>I have also been involved in the development of Android sensors. During this period, I also completed an Android sensor-related development project: <a href="https://github.com/kentanvictor/SensorMonitor">Android Sensor</a></p>
</li>
</ul>
<p><code>基础:</code></p>
<ul>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/%E5%A4%A7%E8%AF%9D%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.pdf">大话设计模式</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/%E5%95%8A%E5%93%88%EF%BC%81%E7%AE%97%E6%B3%95%EF%BC%81.pdf">啊哈!算法!</a></p>
</li>
<li><p><a href="https://github.com/kentanvictor/STUDY/blob/master/PDF/%E7%AE%97%E6%B3%95%EF%BC%88%E7%AC%AC%E5%9B%9B%E7%89%88%EF%BC%89.pdf">算法</a></p>
</li>
</ul>
<h2 id="2019年"><a href="#2019年" class="headerlink" title="2019年"></a>2019年</h2><ul>
<li><p>2019年,我跟随着学校的课程,在井超老师的教导下学会了Java企业级应用开发,也接触到了Spring、SpringMVC、Mybatis、Springboots等用于后端开发的工具。我也能够更好的去为我的Android客户端项目进行一个整体的完善。Android相当于前端,而JavaEE去编写的,是后端服务器中的内容。</p>
</li>
<li><p>同年,我也在学习了网络编程的课程后,了解到了socket套接字通信,这让我在软硬件交互上更能够去进行交互,这也让我最终能够去接触到硬件相关的知识与开发。因为实验室需要参加比赛的缘故,我接触到了计算机视觉的相关知识,学习了OpenCV的使用与其中关于双目立体视觉的算法。</p>
</li>
</ul>
<h2 id="2020年"><a href="#2020年" class="headerlink" title="2020年"></a>2020年</h2><ul>
<li>我依旧在学习,在学习新知识的同时不断地回顾以前学习过的基础,作为一名程序员,最最重要的是数据结构、算法与编程语言的运用,从最初编程语言基础的学习,到进阶学习这门编程语言的独特之处,最终涉及到其底层的数据结构与算法相关的理解。慢慢地就会发现,原来编程是这么有趣的一件事情。</li>
</ul>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>C++_正则表达式</title>
<url>/2020/06/30/C++%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/</url>
<content><![CDATA[<h1 id="正则表达式"><a href="#正则表达式" class="headerlink" title="正则表达式"></a>正则表达式</h1><p>正则表达式是一种字符串匹配的一种模式,可以用于检测一个字符串是否包含某串、将匹配的字符串进行替换或者从一个字符串中提取符合某个条件的的子串等等</p>
<p><code>注:</code>在C++中使用正则表达式进行字符串操作的时候,需要添加头文件 <code>#include<regex></code> </p>
<span id="more"></span>
<h2 id="正则表达式中匹配的字符"><a href="#正则表达式中匹配的字符" class="headerlink" title="正则表达式中匹配的字符"></a>正则表达式中匹配的字符</h2><h3 id="特殊字符"><a href="#特殊字符" class="headerlink" title="特殊字符"></a>特殊字符</h3><div class="table-container">
<table>
<thead>
<tr>
<th>特别字符</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>$</td>
<td>匹配输入字符串的结尾位置</td>
</tr>
<tr>
<td>( )</td>
<td>标记一个子表达式的开始和结束位置</td>
</tr>
<tr>
<td>*</td>
<td>匹配前面的子表达式零次或多次</td>
</tr>
<tr>
<td>+</td>
<td>匹配前面的子表达式一次或多次</td>
</tr>
</tbody>
</table>
</div>
<h3 id="限定符"><a href="#限定符" class="headerlink" title="限定符"></a>限定符</h3><div class="table-container">
<table>
<thead>
<tr>
<th>字符</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>*</td>
<td>匹配前面的子表达式零次或多次。例如,zo<em> 能匹配 “z” 以及 “zoo”。</em> 等价于{0,}</td>
</tr>
<tr>
<td>+</td>
<td>匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}</td>
</tr>
<tr>
<td>?</td>
<td>匹配前面的子表达式零次或一次。例如,”do(es)?” 可以匹配 “do” 、 “does” 中的 “does” 、 “doxy” 中的 “do” 。? 等价于 {0,1}</td>
</tr>
<tr>
<td>{n}</td>
<td>n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o</td>
</tr>
<tr>
<td>{n,}</td>
<td>n 是一个非负整数。至少匹配n 次。例如,’o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。’o{1,}’ 等价于 ‘o+’。’o{0,}’ 则等价于 ‘o*’</td>
</tr>
<tr>
<td>{n,m}</td>
<td>m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,”o{1,3}” 将匹配 “fooooood” 中的前三个 o。’o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格</td>
</tr>
</tbody>
</table>
</div>
<h2 id="regex-match"><a href="#regex-match" class="headerlink" title="regex_match"></a>regex_match</h2><ul>
<li>match为全文匹配,要求整个字符串符合匹配规则。</li>
<li>返回值为bool值,匹配成功返回1。</li>
</ul>