Stereo Vision on VCSBC nano Z-RH-2 - PART I

Today, we are going to talk about a fabulous project: stereo vision on a zynq-7010 board.

1. VCSBC nano Z-RH-2

1.1 Hardware

We are using a VCSBC nano Z-RH-2 board for today’s experiment. The board adopted looks like the following:

Front Back Connector
VCSBC nano Z-RH-2 Front VCSBC nano Z-RH-2 Back VCSBC nano Z-RH-2 Connector

More detailed specifications, please refer to Vision Components’s official website.

1.2 Software

After you set up a static IP for this Vision Components SBC, it’s pretty straightforward to ssh into the system.

1
2
3
4
5
6
7
8
9
10
11
longervision-GT72-6QE% ssh user@192.168.1.79
user@192.168.1.79's password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Aug 29 18:17:49 2019 from 192.168.1.200
user@VC-Z:~$

Currently, VC provides Linux Kernel 3.14.79.

1
2
user@VC-Z:~$ uname -a
Linux VC-Z 3.14.79-vc-z #2 SMP PREEMPT Wed Apr 24 18:33:06 CEST 2019 armv7l GNU/Linux

And, let’s take a look at the dual ARMv7 CPUs on zynq-7010.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
user@VC-Z:~$ cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 0 (v7l)
BogoMIPS : 1725.23
Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x3
CPU part : 0xc09
CPU revision : 0

processor : 1
model name : ARMv7 Processor rev 0 (v7l)
BogoMIPS : 1725.23
Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x3
CPU part : 0xc09
CPU revision : 0

Hardware : Xilinx Zynq Platform
Revision : 0000
Serial : 0000000000000000

2. Stereo Vision

Sorry everybody. Today, I ONLY test stereo vision on ARM. I’ll try to figure out how to flash an open source IP of stereo vision onto zynq-7010, or write my own ASAP.

Hmmmmmmmm… It’s better I keep my code in dark???

😝

2.1 Classical Image Pairs

Let’s try out the stereo vision on some .pgm image pairs FIRST.

1
2
3
4
5
user@VC-Z:~/longervision$ ./pgmpair ../images/aloe_left.pgm ../images/aloe_right.pgm 
width= 1282
height= 1110
fps: 0.119696
process: 398651

My GOD… It’s UNBELIEVABLY SLOW.

aloe_left aloe_right
aloe_left aloe_right
aloe_left Stereo aloe_right Stereo
aloe_left Stereo aloe_right Stereo

2.2 Live Video Pairs

The BEST demo code to test Vision Componenets Stereo Vision is Eclipse_Example_Projects_VC_Z.

2.2.1 imageCaptureTest

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
#./imageCaptureTest 
0


-----------------------------------------------------------------------
VCCapt @0xbe87153c Sensor Count: 2
-----------------------------------------------------------------------

Camera Type : NANO Z RH Rev.0
Sensor 0 Type : E2V_EV76C560ABT_1_0
Sensor 1 Type : E2V_EV76C560ABT_1_0

Trigger Source : IMM

___________________________________________________________________
Sensor[ 0]: Shutter: 12345 us, Gain: 0.00

x0, y0 : ( 0, 0)
binX, binY : ( 1, 1)
subsmplX, subsmplY, flip: ( 1, 1,0x00)
(img) dx, dy, pitch: ( 1280, 1024), 1280

(img) st, ccmp1, ccmp2, type: 0xb6b03080, 0x00000000, 0x00000000, 0

Description
Sen dx, Sen dy, Sen pitch: 1280, 1024, 1280
Max dx, Max dy, Max pitch: 1280, 1024, 1280
Binning Max (dx, dy), Square: 2, 1, 1
Subsmpl Max (dx, dy), Square: 8, 8, 0
Init st,ccmp1,ccmp2: 0xb6b03080, 0x00000000, 0x00000000
Init Shutter, Gain, Type: 10000, 0.00, GREY (0)
FD, Port, Type: 4, 0, E2V_EV76C560ABT_1_0

Volatile Description
requestCaptID, State: 0, IDLE
captId, TimestampTicks: 0, 6476832867277

Externals Description
pos[0-3], angle[0-2]: [ 0.00, 0.00, 0.00],[ 0.0, 0.0]

___________________________________________________________________
Sensor[ 1]: Shutter: 10000 us, Gain: 0.00

x0, y0 : ( 0, 0)
binX, binY : ( 1, 1)
subsmplX, subsmplY, flip: ( 1, 1,0x00)
(img) dx, dy, pitch: ( 1280, 1024), 1280

(img) st, ccmp1, ccmp2, type: 0xb69c2080, 0x00000000, 0x00000000, 0

Description
Sen dx, Sen dy, Sen pitch: 1280, 1024, 1280
Max dx, Max dy, Max pitch: 1280, 1024, 1280
Binning Max (dx, dy), Square: 2, 1, 1
Subsmpl Max (dx, dy), Square: 8, 8, 0
Init st,ccmp1,ccmp2: 0xb69c2080, 0x00000000, 0x00000000
Init Shutter, Gain, Type: 10000, 0.00, GREY (0)
FD, Port, Type: 5, 1, E2V_EV76C560ABT_1_0

Volatile Description
requestCaptID, State: 0, IDLE
captId, TimestampTicks: 0, 6476832867284

Externals Description
pos[0-3], angle[0-2]: [ 0.00, 0.00, 0.00],[ 0.0, 0.0]

-----------------------------------------------------------------------
......

2.2.2 imageCaptFPS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
03:41:47[root@VC-Z] /home/user/vc/Eclipse_Example_Projects_VC_Z/imageCaptFPS
#./imageCaptFPS
dy= 1024 Clock=100000000 Acquisiton&Copy Duration: 28s 780685us for 1000 Cycles == 34.745525fps.
dy= 768 Clock=100000000 Acquisiton&Copy Duration: 28s 789899us for 1000 Cycles == 34.734402fps.
dy= 640 Clock=100000000 Acquisiton&Copy Duration: 28s 790000us for 1000 Cycles == 34.734283fps.
dy= 512 Clock=100000000 Acquisiton&Copy Duration: 28s 790012us for 1000 Cycles == 34.734268fps.
dy= 384 Clock=100000000 Acquisiton&Copy Duration: 28s 790005us for 1000 Cycles == 34.734280fps.
dy= 256 Clock=100000000 Acquisiton&Copy Duration: 28s 790000us for 1000 Cycles == 34.734283fps.
dy= 192 Clock=100000000 Acquisiton&Copy Duration: 28s 790021us for 1000 Cycles == 34.734257fps.
dy= 128 Clock=100000000 Acquisiton&Copy Duration: 28s 789984us for 1000 Cycles == 34.734303fps.
dy= 64 Clock=100000000 Acquisiton&Copy Duration: 28s 789987us for 1000 Cycles == 34.734299fps.
dy= 32 Clock=100000000 Acquisiton&Copy Duration: 28s 789997us for 1000 Cycles == 34.734287fps.
dy= 16 Clock=100000000 Acquisiton&Copy Duration: 28s 790017us for 1000 Cycles == 34.734264fps.
dy= 8 Clock=100000000 Acquisiton&Copy Duration: 28s 790002us for 1000 Cycles == 34.734280fps.
dy= 4 Clock=100000000 Acquisiton&Copy Duration: 28s 789985us for 1000 Cycles == 34.734303fps.
dy= 2 Clock=100000000 Acquisiton&Copy Duration: 28s 789997us for 1000 Cycles == 34.734287fps.
dy= 1 Clock=100000000 Acquisiton&Copy Duration: 28s 789994us for 1000 Cycles == 34.734291fps.

The above 2 examples are directly run on Vision Components’s board without display, for the given cable is of VGA connector, which is ALREADY outdated for many years. Therefore, in order to show the captured image pairs, in the next section, we’ll have to stream the captured data to a host computer, and display the real-time video pairs.

2.3 Stream/Display From Host Computer

Due to Vision Componenets’ Official documentation VCLinux_Getting_Started.pdf, images captured from camera can be displayed on a remote hosting PC.

2.3.1 Eclipse_Example_Projects_VC_Z (Not Preferred)

Eclipse_Example_Projects_VC_Z.zip provides some source code, which displays images captured from camera on the hosting PC’s Eclipse, by adding the camera as a Remote System to Eclipse. Anyway, by using this method, you need to prepare ALL the following software and packages in advance.

2.3.2 vcimgnetclient.py

Besides the above method, a much more straightforward method is to adopt python script vcimgnetclient.py provided by Vision Components. However, vcimgnetclient.py is ONLY python2 compatible, and Vision Components has NO plan to provide a python3 compatible version of vcimgnetclient.py.

Therefore, the KEY to use the 2nd method is to make vcimgnetclient.py python3 compatible.

2.3.2.1 2to3

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
longervision-GT72-6QE% 2to3 vcimgnetclient.py
RefactoringTool: Skipping optional fixer: buffer
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: set_literal
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored vcimgnetclient.py
--- vcimgnetclient.py (original)
+++ vcimgnetclient.py (refactored)
@@ -274,11 +274,11 @@
if(chk_rgb_true):
dy /= 3
#img_data_packed = bytearray(chain.from_iterable(izip(mv_img_data[2 * pitch * dy:], mv_img_data[1 * pitch * dy:], mv_img_data[0 * pitch * dy:])))
- img_data_packed = bytearray(chain.from_iterable(zip(mv_img_data[2 * pitch * dy:], mv_img_data[1 * pitch * dy:], mv_img_data[0 * pitch * dy:])))
+ img_data_packed = bytearray(chain.from_iterable(list(zip(mv_img_data[2 * pitch * dy:], mv_img_data[1 * pitch * dy:], mv_img_data[0 * pitch * dy:]))))
else:
dy /= 1
#img_data_packed = bytearray(chain.from_iterable(izip(mv_img_data[0 * pitch * dy:], mv_img_data[0 * pitch * dy:], mv_img_data[0 * pitch * dy:])))
- img_data_packed = bytearray(chain.from_iterable(zip(mv_img_data[0 * pitch * dy:], mv_img_data[0 * pitch * dy:], mv_img_data[0 * pitch * dy:])))
+ img_data_packed = bytearray(chain.from_iterable(list(zip(mv_img_data[0 * pitch * dy:], mv_img_data[0 * pitch * dy:], mv_img_data[0 * pitch * dy:]))))
cpb = Gdk.pixbuf_new_from_data(buffer(img_data_packed), Gdk.COLORSPACE_RGB, False, 8, dx, dy, 3*pitch)
cpb.save(path, "png")

@@ -589,16 +589,16 @@
dy /= 3
mv_img_data = memoryview(img['data'])
#img_data_packed = bytearray(chain.from_iterable(izip(mv_img_data[2 * pitch * dy:], mv_img_data[1 * pitch * dy:], mv_img_data[0 * pitch * dy:])))
- img_data_packed = bytearray(chain.from_iterable(zip(mv_img_data[2 * pitch * dy:], mv_img_data[1 * pitch * dy:], mv_img_data[0 * pitch * dy:])))
+ img_data_packed = bytearray(chain.from_iterable(list(zip(mv_img_data[2 * pitch * dy:], mv_img_data[1 * pitch * dy:], mv_img_data[0 * pitch * dy:]))))
self.area.window.draw_rgb_image(gc, 0,0, dx,dy, Gdk.RGB_DITHER_NONE, buffer(img_data_packed),3*pitch,0,0)
else:
if('flscol'==self.how_select):
mv_img_data = memoryview(img['data']).tolist()
- r_data = map(falsecolor_r,mv_img_data[0 * pitch * dy:])
- g_data = map(falsecolor_g,mv_img_data[0 * pitch * dy:])
- b_data = map(falsecolor_b,mv_img_data[0 * pitch * dy:])
+ r_data = list(map(falsecolor_r,mv_img_data[0 * pitch * dy:]))
+ g_data = list(map(falsecolor_g,mv_img_data[0 * pitch * dy:]))
+ b_data = list(map(falsecolor_b,mv_img_data[0 * pitch * dy:]))
#img_data_packed = bytearray(chain.from_iterable(izip(r_data, g_data, b_data)))
- img_data_packed = bytearray(chain.from_iterable(zip(r_data, g_data, b_data)))
+ img_data_packed = bytearray(chain.from_iterable(list(zip(r_data, g_data, b_data))))
self.area.window.draw_rgb_image(gc, 0,0, dx,dy, Gdk.RGB_DITHER_NONE, buffer(img_data_packed),3*pitch,0,0)
else: #grey
self.area.window.draw_gray_image(gc, 0,0,
RefactoringTool: Files that need to be modified:
RefactoringTool: vcimgnetclient.py

2.3.2.2 pygi-convert

Please refer to General Porting Tips

1
2
longervision-GT72-6QE% ./pygi-convert.sh vcimgnetclient.py
longervision-GT72-6QE%

2.3.2.3 Try Running

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
longervision-GT72-6QE% python vcimgnetclient.py 
vcimgnetclient.py:330: PyGTKDeprecationWarning: Using positional arguments with the GObject constructor has been deprecated. Please specify keyword(s) for "type" or use a class specific constructor. See: https://wiki.gnome.org/PyGObject/InitializerDeprecations
self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
vcimgnetclient.py:628: PyGTKDeprecationWarning: Using positional arguments with the GObject constructor has been deprecated. Please specify keyword(s) for "label" or use a class specific constructor. See: https://wiki.gnome.org/PyGObject/InitializerDeprecations
mfQuit = Gtk.MenuItem("Quit")
vcimgnetclient.py:629: PyGIDeprecationWarning: Using non GObject arguments for connect_object() is deprecated, use: connect_data(signal, callback, data, connect_flags=GObject.ConnectFlags.SWAPPED)
mfQuit.connect_object("activate", lambda a: Gtk.main_quit(), "mfQuit")
vcimgnetclient.py:637: PyGTKDeprecationWarning: Using positional arguments with the GObject constructor has been deprecated. Please specify keyword(s) for "label" or use a class specific constructor. See: https://wiki.gnome.org/PyGObject/InitializerDeprecations
bmf = Gtk.MenuItem("File")
vcimgnetclient.py:646: PyGTKDeprecationWarning: Using positional arguments with the GObject constructor has been deprecated. Please specify keyword(s) for "label" or use a class specific constructor. See: https://wiki.gnome.org/PyGObject/InitializerDeprecations
mhAbout = Gtk.MenuItem("About")
vcimgnetclient.py:654: PyGTKDeprecationWarning: Using positional arguments with the GObject constructor has been deprecated. Please specify keyword(s) for "label" or use a class specific constructor. See: https://wiki.gnome.org/PyGObject/InitializerDeprecations
bmh = Gtk.MenuItem("Help")
Traceback (most recent call last):
File "vcimgnetclient.py", line 812, in <module>
Main()
File "vcimgnetclient.py", line 719, in __init__
Frontend.__init__(self, self.img_access)
File "vcimgnetclient.py", line 301, in __init__
self.winMain = self.WinMain(arg_img_access, self.dialog)
File "vcimgnetclient.py", line 341, in __init__
vbox.pack_start(self.menu_bar, False, False)
TypeError: Gtk.Box.pack_start() takes exactly 5 arguments (4 given)

2.3.2.4

For ALL vbox.pack_start, add one parameter 0 at the end for each case. For instance: vbox.pack_start(self.menu_bar, False, False) to vbox.pack_start(self.menu_bar, False, False, 0)

Oh my god … There are STILL SO MANY things to do, in order to make vcimgnetclient.py Python3 compatible. Therefore, I implement my own vcimgnetclient_qt.py based on PyQt5.

2.3.3 Longer Vision’s vcimgnetclient_qt.py

2.3.3.1 Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
22:42:22[root@VC-Z] /home/user
#whoami
root

22:42:24[root@VC-Z] /home/user
#vcimgnetsrv &
[1] 896

22:42:30[root@VC-Z] /home/user
#ps -e | grep vcimgnetsrv
896 pts/0 00:00:00 vcimgnetsrv

22:42:40[root@VC-Z] /home/user
#vctp
Acquisiton&Copy Duration: 4s 39644us for 100 Cycles == 24.754656fps.

Acquisiton&Copy Duration: 4s 34709us for 100 Cycles == 24.784935fps.
......

2.3.3.2 Client

Sorry, I’m NOT going to show my code, but the performance can be demonstrated as follows:

LVT VC PyQt5 GUI