{ "info": { "author": "Chris Spencer", "author_email": "chrisspen@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.2", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# laser-range-finder\nCalculates distance using images taken with a generic webcam and a low-power laser\n\n# Overview\n\nThis package implements a Python class that calculates distance from the camera given two images taken by the camera, where one image contains a laser line projection parallel to the camera's focal plane and the other image contains no laser projection.\n\nThis method is very similar to the approach described [here](https://sites.google.com/site/todddanko/home/webcam_laser_ranger), although it has been extended to apply to a line instead of a single point.\n\n# Installation\n\nRecommended installation is via pip (preferrably inside a virtualenv):\n\n pip install laser_range_finder\n\n# Usage\n\nBefore you can use the class, you'll need to calibrate your camera. Calculate your camera's:\n\n* vertical field of view in degrees\n* horizontal field of view in degrees\n* distance between camera center and laser center in millimeters\n* radian offset\n\nThen, pass these values when you instantiate the class:\n\n from laser_range_finder import LaserRangeFinder\n lrf = LaserRangeFinder(vert_fov_deg=50, horz_fov_deg=40, ro=0.01, h=30)\n\nThe package is agnostic to how the images are captured, but assumes you can provide them as either a filename or as a PIL Image instance:\n\n distances = lrf.get_distance(off_img='~/laser-off.png', on_img='~/laser-on.png')\n\nThe value returned by `get_distance()` will be a list equal in length to the pixel width of the source images and each element will be the estimated distance from the camera in millimeters. A value of -1 indicates that no reliable distance measurement could be made in the associated column.\n\nIf you don't need the specificity of a per-pixel distance measurement, but just want a more general estimate of distance in N blocks across the image, then you can pass these distances to the function `compress_list(lst, bins)`:\n\n from laser_range_finder.utils import compress_list\n distances = lrf.get_distance(off_img='~/laser-off.png', on_img='~/laser-on.png')\n distances = compress_list(distances, bins=10)\n\n# Methodology\n\nThe method assumes we start with two images, a reference image A known to contain no laser line, and an image B that definitely contains a laser line but possibly distorted. We could potentially just use the single image containing the laser line, but having a negative image greatly helps us remove noise. So we start with the following sample images:\n\n![Sample Image A](docs/images/sample-a-0.jpg) ![Sample Image B](docs/images/sample-b-0.jpg)\n\nNotice that the brightness differs considerably between the two images. Later, we'll want to isolate the laser line by finding the difference between the two images, but this difference in overall brightness will interfere with that. So we fix this by using `utils.normalize()`, giving us:\n\n![Sample Image A](docs/images/sample-a-1.jpg) ![Sample Image B](docs/images/sample-b-1.jpg)\n\nSince these images are RGB, but the laser is red, we remove some noise by stripping out the blue and green channels using `utils.only_red()`, giving us:\n\n![Sample Image A](docs/images/sample-a-2.jpg) ![Sample Image B](docs/images/sample-b-2.jpg)\n\nNow we calculate the difference of the images. If the only change between the images was the laser line, then the resulting image should be completely black with the laser appearing as bright white. In practice, there will still be considerable noise, but the difference will eliminate most of that, giving us:\n\n![Difference Image](docs/images/sample-diff-3.jpg)\n\nFinally, we make a \"best guess\" as to where the laser line is. Since we know the line will be roughly horizontal and the laser line should now correspond to the brightest pixels in the image, we scan each column and find the rows with the brightest pixel, giving us:\n\n![Line Estimate 1](docs/images/sample-line-1.jpg)\n\nNotice the estimate is pretty close, but there's still some noise, mostly on the left-hand side of the image where the laser line is absorbed by a matte black finish. We fix this by calculating the line's mean and standard deviation brightness, and ignore anything that's less than `mean - stddev`, giving us:\n\n![Line Estimate 2](docs/images/sample-line-2.jpg)\n\nThat's removed a lot of the noise, but notice there's still a tiny bit of noise in the top-left part of the image. For this setup, the laser was positioned below the camera, which means that the line should never appear above the middle row. So can assume any laser line pixels detected above the middle row are noise. That gives us our final image, which almost perfectly detects the laser projection:\n\n![Line Estimate 3](docs/images/sample-line-3.jpg)\n\nWe can then use a little trigonometry to convert the white pixel's offset from the middle row into a physical distance of the laser projection.\n\nFor reference, the source images used in this example were captured with a 5MP NoIR camera connected to a Raspberry Pi 2 and a 1mW 3V red laser line diode mounted 22.5 mm from the camera and controlled directly from a Raspberry Pi GPIO pin.\n\n# Testing\n\nTo run tests:\n\n tox\n\nor:\n\n py.test -s\n", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/chrisspen/laser_range_finder", "keywords": null, "license": "MIT License", "maintainer": null, "maintainer_email": null, "name": "laser_range_finder", "package_url": "https://pypi.org/project/laser_range_finder/", "platform": "OS Independent", "project_url": "https://pypi.org/project/laser_range_finder/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/chrisspen/laser_range_finder" }, "release_url": "https://pypi.org/project/laser_range_finder/0.1.0/", "requires_dist": null, "requires_python": null, "summary": "Calculates distance using images taken with a generic webcam and a low-power laser", "version": "0.1.0" }, "last_serial": 1780908, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "5c5086040667fa7f94a3742b81cf32d6", "sha256": "66e80b45e847a3adeb12dee8ca70e52bf201b8fe94f0c4abae017a58bd49d6c0" }, "downloads": -1, "filename": "laser_range_finder-0.1.0.tar.gz", "has_sig": false, "md5_digest": "5c5086040667fa7f94a3742b81cf32d6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6886, "upload_time": "2015-10-22T04:28:29", "url": "https://files.pythonhosted.org/packages/25/09/9665d114d65c15fb8eb4bb81f6a6120440e9536abaff6eb188f6d5665de2/laser_range_finder-0.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "5c5086040667fa7f94a3742b81cf32d6", "sha256": "66e80b45e847a3adeb12dee8ca70e52bf201b8fe94f0c4abae017a58bd49d6c0" }, "downloads": -1, "filename": "laser_range_finder-0.1.0.tar.gz", "has_sig": false, "md5_digest": "5c5086040667fa7f94a3742b81cf32d6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6886, "upload_time": "2015-10-22T04:28:29", "url": "https://files.pythonhosted.org/packages/25/09/9665d114d65c15fb8eb4bb81f6a6120440e9536abaff6eb188f6d5665de2/laser_range_finder-0.1.0.tar.gz" } ] }