diff --git a/README.md b/README.md index df4f3f12..37c4ef93 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,12 @@ # Horus - [![License](http://img.shields.io/:license-gpl-blue.svg?style=flat)](http://opensource.org/licenses/GPL-2.0) [![Build Status](https://travis-ci.org/bq/horus.svg)](https://travis-ci.org/bq/horus) [![Google Group](https://img.shields.io/badge/-Google%20Group-lightgrey.svg)](https://groups.google.com/forum/?hl=en#!forum/ciclop-3d-scanner) +## News of these fork: + +01 - Ago - 2015 .- Never more change the possition of the patther on calibration! Just put in front of the camera, adjust camera and the calibration engine will do the rest. + +## Whay is Horus? + Horus is a general solution for 3D scanning. It provides graphic user interfaces for connection, configuration, control, calibration and scanning. It is ready to use with Open Source [Ciclop 3D Scanner](https://github.com/bq/ciclop). This project has been developed in [Python](https://www.python.org/) language and it is distributed under [GPL v2](https://www.gnu.org/licenses/gpl-2.0.html) license. @@ -16,6 +21,15 @@ More interest links are shown below: * [Documentation](http://diwo.bq.com/en/documentation-ciclop-and-horus/) [[es](http://diwo.bq.com/documentation-ciclop-and-horus/)] +## What's these fork? + +These fork is my interpretation of what should be, and how should it work Horus, a fantastis software for controlling laser scanner based on Ciclops by BQ. + +At the moment I'm working on get the finest calibration possible, and make Horus more cominicative to try to understand it better. + +Also I'm working on porting Horus to Synology NAS and Raspberry Pi. I have both working, but I have to finish the instrucctions. + + ## Installation ###### Last stable version: 0.1.2.4 @@ -34,7 +48,7 @@ More interest links are shown below: |:------------------:|:---------:|:--------:|:------------------------------------:| | ![][debian-logo] | Debian | 8 | [link](doc/installation/debian.md) | | ![][raspbian-logo] | Raspbian | RPi2 | [link](doc/installation/raspbian.md) | - +| ![][synology-logo] | Synology | DSM 5.0 | [link](doc/installation/synology.md) | ## Development @@ -65,4 +79,5 @@ NOTE: *dmg* packages only can be generated in Mac OS X [windows-logo]: doc/images/windows.png [macosx-logo]: doc/images/macosx.png [debian-logo]: doc/images/debian.png -[raspbian-logo]: doc/images/raspbian.png \ No newline at end of file +[raspbian-logo]: doc/images/raspbian.png +[synology-logo]: doc/images/synology.png diff --git a/doc/images/synology.png b/doc/images/synology.png new file mode 100644 index 00000000..f8e8203d Binary files /dev/null and b/doc/images/synology.png differ diff --git a/doc/installation/synology.md b/doc/installation/synology.md new file mode 100644 index 00000000..884ab8a7 --- /dev/null +++ b/doc/installation/synology.md @@ -0,0 +1,153 @@ +# Horus installation in Synology DSM ![][synology-logo] + +[return to Home](../../README.md) + +Firts of all, you need a Synology Nas updated, with ssh access with root credentials. [Guide](http://forum.synology.com/wiki/index.php/Enabling_the_Command_Line_Interface) + +Then, you have to Install [Debian Chroot](https://synocommunity.com/package/debian-chroot) adding the Synocomunity repo. As they says: + +Step 1:- Log into your NAS as administrator and go to Main Menu → Package Center → Settings and set Trust Level to Synology Inc. and trusted publishers. + +Step 2:- In the Package Sources tab, click Add, type SynoCommunity as Name and http://packages.synocommunity.com/ as Location and then press OK to validate. + +Step 3:- Go back to the Package Center and enjoy SynoCommunity's packages in the Community tab. + + +At these point, we have two methods to install: + + +### The easy one (Automatic and recomended) + +Open a ssh connection with your synology Nas and follow these instrucctions: + +```bash +ssh root@.local -p XXXX + +/var/packages/debian-chroot/scripts/start-stop-status chroot + +### Now we are in the console of Debian Chroot + +cd +wget https://github.com/javivi001/horus/blob/develop/syno-horus.sh +bash syno-horus.sh + +### Make coffe and take patience, but everything will work with only a pair of cuestions at beginig +``` +Enjoy Horus!!! + + + + +### The manual one + + +Open a ssh connection as the other method: + +```bash +ssh root@.local -p XXXX + +/var/packages/debian-chroot/scripts/start-stop-status chroot + +... Now we are in the console of Debian Chroot ... +``` + + +Update packages: + +```bash +apt-get update && apt-get upgrade -y && apt-get dist-upgrade -y +``` + + +Install Locales and configure it: + +```bash +apt-get install locales +dpkg-reconfigure locales +``` + + +Install Basic comands and eviroment dependences: + +```bash +apt-get install git gitk -y +apt-get install python2.7 python-pip python-wxgtk3.0 python-serial python-opengl python-pyglet python-numpy python-scipy python-matplotlib libdc1394-utils libdc1394-22 -y +pip install -U pip setuptools +``` + + +Install a desktop suite: + +```bash +apt-get install lxde -y +``` + + +Install request for compilling Open CV: + +```bash +apt-get install build-essential cmake make git gcc g++ gfortran libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev python-dev python-numpy \ +libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev libv4l-dev libeigen3-dev -y +``` + +Install an VNC Server that allow OpenGL over X11 + +```bash +apt-get install vnc4server libgl1-mesa-swx11-dev-y + +Start:$ vncserver -geometry 10280x1024 -depth 24 :1 && export DISPLAY=':1' +Stop:$ vncserver -kill :1 +``` + + +Let's start compilling and installing custom OpenCV: + +```bash +cd /root/ +git clone https://github.com/bq/opencv.git +cd opencv +mkdir release +cd release +cmake -D CMAKE_C_FLAGS=-m32 -D CMAKE_CXX_FLAGS=-m32 -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON \ +-D WITH_V4L=ON -D WITH_FFMPEG=OFF -D WITH_OPENGL=OFF -D BUILD_opencv_gpu=OFF -D BUILD_opencv_gpu=OFF -D BUILD_opencv_ocl=OFF -D BUILD_opencv_nonfree=OFF \ +-D BUILD_opencv_stitching=OFF -D BUILD_opencv_superres=OFF -D BUILD_opencv_ts=OFF -D BUILD_opencv_videostab=OFF .. +make +make install +``` + + +And now it's time to Horus: + +```bash +cd /root/ +git clone https://github.com/bq/horus.git + +or if you prefer my fort: + +git clone https://github.com/javivi001/horus.git +cd horus +python src/horus.py +``` + +Enjoy Horus!!! + + +### IMPORTANT : Check yor kernel modules if you have in /lib/modules + +You will nedd to add modules (in these order, very important!): + + /lib/modules/videodev.ko + /lib/modules/v4l2-int-device.ko + /lib/modules/v4l2-common.ko + /lib/modules/uvcvideo.ko + /lib/modules/usbserial.ko + /lib/modules/ftdi_sio.ko + +If you don't have it, you can crosscompile in other pc with the synology chaintools or try to croscompile in the Debian Chroot (these work for me) + +Ask me your questions!!! + + +Regards!!! + +[synology-logo]: ../images/synology.png diff --git a/res/images/pattern-position-center.jpg b/res/images/pattern-position-center.jpg new file mode 100644 index 00000000..17cb3ee5 Binary files /dev/null and b/res/images/pattern-position-center.jpg differ diff --git a/src/horus/engine/calibration.py b/src/horus/engine/calibration.py index 7aa721a1..a7d49dbe 100644 --- a/src/horus/engine/calibration.py +++ b/src/horus/engine/calibration.py @@ -208,6 +208,8 @@ def setImage(self, image): def _start(self, progressCallback, afterCallback): XL = None XR = None + planol = 0 + planor = 0 if sys.isWindows(): flush = 2 @@ -226,13 +228,16 @@ def _start(self, progressCallback, afterCallback): board.setRightLaserOff() ##-- Setup motor - step = 5 + step = 2 angle = 0 board.setSpeedMotor(1) board.enableMotor() board.setSpeedMotor(150) board.setAccelerationMotor(150) - time.sleep(0.1) + time.sleep(0.2) + board.setRelativePosition(-90) + board.moveMotor() + time.sleep(0.2) if progressCallback is not None: progressCallback(0) @@ -243,6 +248,7 @@ def _start(self, progressCallback, afterCallback): progressCallback(1.11*abs(angle/2.)) angle += step + print '> ',angle,' deg <' camera.setExposure(profile.getProfileSettingNumpy('exposure_calibration')) @@ -253,7 +259,7 @@ def _start(self, progressCallback, afterCallback): ret = self.getPatternPlane(imageRaw) if ret is not None: - step = 4 #2 + step = 1 #2 d, n, corners = ret @@ -262,7 +268,9 @@ def _start(self, progressCallback, afterCallback): #-- Image laser acquisition imageRawLeft = camera.captureImage(flush=True, flushValue=flush) board.setLeftLaserOn() + #time.sleep(0.2) imageLeft = camera.captureImage(flush=True, flushValue=flush) + #time.sleep(0.2) board.setLeftLaserOff() self.image = imageLeft if imageLeft is None: @@ -270,7 +278,9 @@ def _start(self, progressCallback, afterCallback): imageRawRight = camera.captureImage(flush=True, flushValue=flush) board.setRightLaserOn() + #time.sleep(0.2) imageRight = camera.captureImage(flush=True, flushValue=flush) + #time.sleep(0.2) board.setRightLaserOff() self.image = imageRight if imageRight is None: @@ -294,25 +304,32 @@ def _start(self, progressCallback, afterCallback): XL = xL else: XL = np.concatenate((XL,xL)) + planol += 1 + print 'Plano Izquierdo registrado ',planol,' veces' xR = self.getPointCloudLaser(uR, vR, d, n) if xR is not None: if XR is None: XR = xR else: XR = np.concatenate((XR,xR)) + planor += 1 + print 'Plano Derecho registrado ',planol,' veces' else: - step = 5 + step = 2 self.image = imageRaw + print 'No se ha detectado el patron' board.setRelativePosition(step) board.moveMotor() - time.sleep(0.1) + time.sleep(0.2) # self.saveScene('XL.ply', XL) # self.saveScene('XR.ply', XR) #-- Compute planes + print '>>> Computando plano Izquierdo <<<' dL, nL, stdL = self.computePlane(XL, 'l') + print '>>> Computando plano Derecho <<<' dR, nR, stdR = self.computePlane(XR, 'r') ##-- Switch off lasers @@ -320,6 +337,9 @@ def _start(self, progressCallback, afterCallback): board.setRightLaserOff() #-- Disable motor + board.setRelativePosition(-90) + board.moveMotor() + time.sleep(0.2) board.disableMotor() #-- Restore camera exposure @@ -396,9 +416,9 @@ def computePlane(self, X, side): Xm = X.sum(axis=1)/n M = np.array(X-Xm) - #begin = datetime.datetime.now() + begin = datetime.datetime.now() U = linalg.svds(M, k=2)[0] - #print "nº {0} time {1}".format(n, datetime.datetime.now()-begin) + print "nº {0} time {1}".format(n, datetime.datetime.now()-begin) s, t = U.T n = np.cross(s, t) if n[2] < 0: @@ -413,15 +433,15 @@ def computePlane(self, X, side): std = distance_vector.std() final_points=np.where(abs(distance_vector) ',angle,' deg <' break distanceAnt = distance angle = np.max(((distance-epsilon) * 30, 5)) @@ -623,6 +644,7 @@ def getPatternDepth(self, board, camera, progressCallback): if self.isCalibrating: board.setRelativePosition(angle) board.moveMotor() + print '> ',angle,' deg <' if progressCallback is not None: if distance < np.inf: @@ -643,7 +665,7 @@ def getPatternDepth(self, board, camera, progressCallback): if progressCallback is not None: progressCallback(90) - #print "Distance: {0} Angle: {1}".format(round(distance,3), round(angle,3)) + print "Distance: {0} Angle: {1}".format(round(distance,3), round(angle,3)) return t, n, corners @@ -717,9 +739,10 @@ def __init__(self): Calibration.__init__(self) self.criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001) self.image = None + self.patron = 0 def setExtrinsicsStep(self, step): - self.extrinsicsStep = step + self.extrinsicsStep = -2 def setIntrinsics(self, cameraMatrix, distortionVector): self.cameraMatrix = cameraMatrix @@ -758,6 +781,9 @@ def _start(self, progressCallback, afterCallback): board = self.driver.board camera = self.driver.camera + board.setRelativePosition(90) + board.moveMotor() + time.sleep(0.2) x = [] y = [] @@ -781,10 +807,11 @@ def _start(self, progressCallback, afterCallback): while self.isCalibrating and abs(angle) < 180: angle += step + print '> ',angle,' deg <' t = self.getPatternPosition(step, board, camera) if progressCallback is not None: progressCallback(1.1*abs(angle/2.)) - time.sleep(0.1) + time.sleep(0.2) if t is not None: x += [t[0][0]] y += [t[1][0]] @@ -811,6 +838,9 @@ def _start(self, progressCallback, afterCallback): t = center - self.patternDistance * np.array(normal) #-- Disable motor + board.setRelativePosition(90) + board.moveMotor() + time.sleep(0.2) board.disableMotor() if self.isCalibrating and t is not None and np.linalg.norm(t-[5,80,320]) < 100: @@ -841,10 +871,12 @@ def getPatternPosition(self, step, board, camera): self.image = image ret = self.solvePnp(image, self.objpoints, self.cameraMatrix, self.distortionVector, self.patternColumns, self.patternRows) if ret is not None: + self.patron += 1 if ret[0]: t = ret[2] board.setRelativePosition(step) board.moveMotor() + print 'Patron leido ',self.patron,' veces' return t def solvePnp(self, image, objpoints, cameraMatrix, distortionVector, patternColumns, patternRows): @@ -910,4 +942,8 @@ def fitCircle(self, point, normal, data): synthetic = [list(centerPoint+ RiF*np.cos(phi)*self.r+RiF*np.sin(phi)*self.s) for phi in np.linspace(0, 2*np.pi,50)] [cxTupel,cyTupel,czTupel] = [ x for x in zip(*synthetic)] + # Muestra al final las veces que se ha leido si no se quiere que lo diga en cada paso + # print 'Patron leido ',self.patron,' veces' + self.patron = 0 + print 'Centro: ', centerPoint, ' Rotacion: ', R return centerPoint, R, [cxTupel,cyTupel,czTupel] diff --git a/src/horus/engine/scan.py b/src/horus/engine/scan.py index 8735bb23..21d154e0 100644 --- a/src/horus/engine/scan.py +++ b/src/horus/engine/scan.py @@ -327,6 +327,7 @@ class SimpleScan(Scan): def _captureThread(self): """""" + linea = 0 if sys.isWindows() or sys.isDarwin(): flush_both = 3 flush_single = 1 @@ -352,22 +353,26 @@ def _captureThread(self): #-- Left laser if self.pcg.useLeftLaser and not self.pcg.useRightLaser: imageLaserLeft = self.driver.camera.captureImage(flush=True, flushValue=flush_single) + linea += 1 #-- Right laser if not self.pcg.useLeftLaser and self.pcg.useRightLaser: imageLaserRight = self.driver.camera.captureImage(flush=True, flushValue=flush_single) + linea += 1 ##-- Both laser if self.pcg.useLeftLaser and self.pcg.useRightLaser: self.driver.board.setLeftLaserOn() self.driver.board.setRightLaserOff() imgLaserLeft = self.driver.camera.captureImage(flush=True, flushValue=flush_both) + linea += 1 self.driver.board.setRightLaserOn() self.driver.board.setLeftLaserOff() imgLaserRight = self.driver.camera.captureImage(flush=True, flushValue=flush_both) + linea += 1 - print "> {0} deg <".format(self.theta * 180.0 / np.pi) + print "> {0} deg < > {1} lin <".format(self.theta * 180.0 / np.pi,linea) self.theta -= self.pcg.degrees * self.pcg.rad #-- Move motor @@ -461,6 +466,7 @@ class TextureScan(Scan): def _captureThread(self): """""" + linea = 0 imgRaw = None imgLaserLeft = None imgLaserRight = None @@ -490,6 +496,7 @@ def _captureThread(self): imgRaw = self.driver.camera.capture.read()[1] self.driver.board.setLeftLaserOn() self.driver.camerareading = False + linea += 1 if imgRaw is None or imgLaserLeft is None: self.driver.camera._fail() @@ -511,6 +518,7 @@ def _captureThread(self): imgRaw = self.driver.camera.capture.read()[1] self.driver.board.setRightLaserOn() self.driver.camerareading = False + linea += 1 if imgRaw is None or imgLaserRight is None: self.driver.camera._fail() @@ -536,6 +544,7 @@ def _captureThread(self): self.driver.board.setRightLaserOff() imgRaw = self.driver.camera.capture.read()[1] self.driver.camerareading = False + linea += 2 if imgRaw is None or imgLaserLeft is None or imgLaserRight is None: self.driver.camera._fail() @@ -567,6 +576,7 @@ def _captureThread(self): self.driver.board.setLeftLaserOn() self.driver.board.setRightLaserOff() imgLaserLeft = self.driver.camera.captureImage(flush=True, flushValue=flush) + linea += 1 else: imgLaserLeft = None @@ -574,10 +584,11 @@ def _captureThread(self): self.driver.board.setRightLaserOn() self.driver.board.setLeftLaserOff() imgLaserRight = self.driver.camera.captureImage(flush=True, flushValue=flush) + linea += 1 else: imgLaserRight = None - print "> {0} deg <".format(self.theta * 180.0 / np.pi) + print "> {0} deg < > {1} lin <".format(self.theta * 180.0 / np.pi,linea) self.theta -= self.pcg.degrees * self.pcg.rad #-- Move motor diff --git a/src/horus/gui/workbench/calibration/pages.py b/src/horus/gui/workbench/calibration/pages.py index edd2c90d..59c7d66b 100644 --- a/src/horus/gui/workbench/calibration/pages.py +++ b/src/horus/gui/workbench/calibration/pages.py @@ -349,7 +349,7 @@ def __init__(self, parent, afterCancelCallback=None, afterCalibrationCallback=No #-- Image View imageView = ImageView(self._panel) - imageView.setImage(wx.Image(resources.getPathForImage("pattern-position-right.jpg"))) + imageView.setImage(wx.Image(resources.getPathForImage("pattern-position-center.jpg"))) #-- Video View self.videoView = VideoView(self._panel, self.getFrame, 50) @@ -587,7 +587,7 @@ def __init__(self, parent, afterCancelCallback=None, afterCalibrationCallback=No #-- Image View imageView = ImageView(self._panel) - imageView.setImage(wx.Image(resources.getPathForImage("pattern-position-right.jpg"))) + imageView.setImage(wx.Image(resources.getPathForImage("pattern-position-center.jpg"))) #-- Video View self.videoView = VideoView(self._panel, self.getFrame, 50) @@ -775,7 +775,7 @@ def __init__(self, parent, afterCancelCallback=None, afterCalibrationCallback=No #-- Image View imageView = ImageView(self._panel) - imageView.setImage(wx.Image(resources.getPathForImage("pattern-position-left.jpg"))) + imageView.setImage(wx.Image(resources.getPathForImage("pattern-position-center.jpg"))) #-- Video View self.videoView = VideoView(self._panel, self.getFrame, 50) @@ -960,4 +960,4 @@ def add(self, args): self.Layout() def clear(self): - self.ax.cla() \ No newline at end of file + self.ax.cla() diff --git a/syno-horus.sh b/syno-horus.sh new file mode 100644 index 00000000..c40b4148 --- /dev/null +++ b/syno-horus.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +apt-get update && apt-get upgrade -y && apt-get dist-upgrade -y +apt-get install locales +dpkg-reconfigure locales +apt-get install git gitk -y +apt-get install python2.7 python-pip python-wxgtk3.0 python-serial python-opengl python-pyglet python-numpy python-scipy python-matplotlib libdc1394-utils libdc1394-22 -y +pip install -U pip setuptools +apt-get install make cmake gcc g++ gfortran -y +apt-get install lxde -y +apt-get install build-essential cmake make git gcc g++ gfortran libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev python-dev python-numpy \ +libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev libv4l-dev libeigen3-dev -y +apt-get install vnc4server libgl1-mesa-swx11-dev-y + +cd /root/ +git clone https://github.com/bq/opencv.git +cd opencv +mkdir release +cd release +cmake -D CMAKE_C_FLAGS=-m32 -D CMAKE_CXX_FLAGS=-m32 -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON \ +-D WITH_V4L=ON -D WITH_FFMPEG=OFF -D WITH_OPENGL=OFF -D BUILD_opencv_gpu=OFF -D BUILD_opencv_gpu=OFF -D BUILD_opencv_ocl=OFF -D BUILD_opencv_nonfree=OFF \ +-D BUILD_opencv_stitching=OFF -D BUILD_opencv_superres=OFF -D BUILD_opencv_ts=OFF -D BUILD_opencv_videostab=OFF .. +make +make install + +cd /root/ +git clone https://github.com/javivi001/horus.git +cd horus