{ "info": { "author": "Maksym Balatsko", "author_email": "mbalatsko@gmail.com", "bugtrack_url": null, "classifiers": [ "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "# Basler PyPylon OpenCV viewer for Jupyter Notebook\n\n[![PyPI version](https://badge.fury.io/py/pypylon-opencv-viewer.svg)](https://badge.fury.io/py/pypylon-opencv-viewer)\n[![Downloads](https://pepy.tech/badge/pypylon-opencv-viewer)](https://pepy.tech/project/pypylon-opencv-viewer)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nEasy to use Jupyter notebook viewer connecting Basler Pylon images grabbing with OpenCV image processing.\nAllows to specify interactive Jupyter widgets to manipulate Basler camera features values, grab camera image and at\nonce get an OpenCV window on which raw camera output is displayed or you can specify an image processing function,\nwhich takes on the input raw camera output image and display your own output.\n\n## Installation\n\n```bash\npip install pypylon-opencv-viewer\n```\n\n## Initialization\n\nTo start working, launch Jupyter notebook and connect to Basler camera. Here is an example how we can do it:\n```python\nfrom pypylon import pylon \n\n# Pypylon get camera by serial number\nserial_number = '22716154'\ninfo = None\nfor i in pylon.TlFactory.GetInstance().EnumerateDevices():\n if i.GetSerialNumber() == serial_number:\n info = i\n break\nelse:\n print('Camera with {} serial number not found'.format(serial_number))\n\n# VERY IMPORTANT STEP! To use Basler PyPylon OpenCV viewer you have to call .Open() method on you camera\nif info is not None:\n camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateDevice(info))\n camera.Open()\n```\nWhen our camera is connected and open, we can initialize our viewer with it:\n\n```python\nfrom pypylon_opencv_viewer import BaslerOpenCVViewer\nviewer = BaslerOpenCVViewer(camera)\n```\n\n### Configuration\nNext step is to configure created viewer using method `set_configuration`, where passed value is dictionary with the following items: \n\n features : list of dicts (required)\n List of widgets configuration stored in\n dictionaries with items:\n name : str (required)\n Camera pylon feature name, example: \"GainRaw\"\n type : str (required)\n widget input type, allowed values are {\"int\", \"float\", \"bool\", \"int_text\", \"float_text\", \"choice_text\"}\n value : number or bool (optional, default: current camera feature value)\n widget input value\n max : number (optional, default: camera feature max value)\n maximum widget input value, only numeric widget types\n min : number (optional, default: camera feature min value)\n minimum widget input value, only numeric widget types\n step : number (optional, default: camera feature increment)\n step of allowed input value\n options: list, mandatory for type \"choice_text\",\n sets values in list as options for ToggleButtons\n unit: str (optional, default empty)\n string shown at the end of label in the form \"Label [unit]:\"\n dependency: dict, (optional, default empty)\n defines how other widgets must be set to be this widget enabled\n layout : dict (optional, default: {\"width\": '100%', \"height\": '50px', \"align_items\": \"center\"})\n values are passed to widget's layout\n style: dict, (optional, default {'description_width': 'initial'})\n values are passed to widget's style \n\n Example:\n \"features\": {\n \"name\": \"GainRaw\",\n \"type\": \"int\",\n \"value\": 20,\n \"max\": 63,\n \"min\": 10,\n \"step\": 1,\n \"layout\": {\"width\":\"99%\", \"height\": \"50px\") \n \"style\": {\"button_width\": \"90px\"}\n }\n features_layout: list of tuples (optional, default is one widget per row)\n List of features' widgets' name for reordering. Each tuple represents one row\n Example:\n \"* features_layout\": [\n (\"Height\", \"Width\"), \n (\"OffsetX\", \"CenterX\"), \n (\"ExposureAuto\", \"ExposureTimeAbs\"),\n (\"AcquisitionFrameCount\", \"AcquisitionLineRateAbs\")\n ],\n actions_layout: list of tuples (optional, default is one widget per row)\n List of actions' widgets' name for reordering. Each tuple represents one row.\n Available widgets are StatusLabel, SaveConfig, LoadConfig, ContinuousShot, SingleShot, \"UserSet\"\n * Example: \n \"action_layout\": [\n (\"StatusLabel\"), \n (\"SaveConfig\", \"LoadConfig\", \"ContinuousShot\", \"SingleShot\"), \n (\"UserSet\")\n ]\n default_user_set: string (optional, default is None)\n If value is None, widget for selecting UserSet is displayed. \n Otherwise is set to given value in [\"UserSet1\", \"UserSet2\", \"UserSet3\"] \n * Example: \n \"default_user_set\": \"UserSet3\"\n\nThe only required and also most important item in the dictionary above is a list of features you want to control. Their names can be found in [official Basler documentation](https://docs.baslerweb.com/#t=en%2Ffeatures.htm&rhsearch=sdk). \n\nExample configuration you can see below:\n\n```python\n# Example of configuration for basic RGB camera's features\nVIEWER_CONFIG_RGB_MATRIX = {\n \"features\": [\n {\n \"name\": \"GainRaw\",\n \"type\": \"int\",\n \"step\": 1,\n },\n {\n \"name\": \"Height\",\n \"type\": \"int\",\n \"value\": 1080,\n \"unit\": \"px\",\n \"step\": 2,\n },\n {\n \"name\": \"Width\",\n \"type\": \"int\",\n \"value\": 1920,\n \"unit\": \"px\",\n \"step\": 2,\n },\n {\n \"name\": \"CenterX\",\n \"type\": \"bool\",\n },\n {\n \"name\": \"CenterY\",\n \"type\": \"bool\",\n\n },\n {\n \"name\": \"OffsetX\",\n \"type\": \"int\",\n \"dependency\": {\"CenterX\": False},\n \"unit\": \"px\",\n \"step\": 2,\n },\n {\n \"name\": \"OffsetY\",\n \"type\": \"int\",\n \"dependency\": {\"CenterY\": False},\n \"unit\": \"px\",\n \"step\": 2,\n },\n {\n \"name\": \"AcquisitionFrameRateAbs\",\n \"type\": \"int\",\n \"unit\": \"fps\",\n \"dependency\": {\"AcquisitionFrameRateEnable\": True},\n \"max\": 150,\n \"min\": 1,\n },\n {\n \"name\": \"AcquisitionFrameRateEnable\",\n \"type\": \"bool\",\n },\n {\n \"name\": \"ExposureAuto\",\n \"type\": \"choice_text\",\n \"options\": [\"Off\", \"Once\", \"Continuous\"],\n \"style\": {\"button_width\": \"90px\"}\n },\n {\n \"name\": \"ExposureTimeAbs\",\n \"type\": \"int\",\n \"dependency\": {\"ExposureAuto\": \"Off\"},\n \"unit\": \"\u03bcs\",\n \"step\": 100,\n \"max\": 35000,\n \"min\": 500,\n },\n {\n \"name\": \"BalanceWhiteAuto\",\n \"type\": \"choice_text\",\n \"options\": [\"Off\", \"Once\", \"Continuous\"],\n \"style\": {\"button_width\": \"90px\"}\n },\n ],\n \"features_layout\": [\n (\"Height\", \"Width\"), \n (\"OffsetX\", \"CenterX\"), \n (\"OffsetY\", \"CenterY\"), \n (\"ExposureAuto\", \"ExposureTimeAbs\"),\n (\"AcquisitionFrameRateAbs\", \"AcquisitionFrameRateEnable\"),\n (\"BalanceWhiteAuto\", \"GainRaw\")\n ],\n \"actions_layout\": [\n (\"StatusLabel\"),\n (\"SaveConfig\", \"LoadConfig\", \"ContinuousShot\", \"SingleShot\"), \n (\"UserSet\")\n ],\n \"default_user_set\": \"UserSet3\",\n}\nviewer.set_configuration(VIEWER_CONFIG_RGB_MATRIX)\n\n```\n\n\n#### Image processing function\nWe can also define image processing function that we want to apply on grabbed images using method `set_impro_function`. If we don't specify one, we will get raw camera output.\n\nThe given function must either return processed image:\n```python\ndef impro(img):\n return np.hstack([img, (255-img)])\nviewer.set_impro_function(impro)\n```\nor display it using cv2.namedWindow. In this case we must specify `own_window=True` to disable showing of default window.\n```python\ndef impro(img):\n cv2.namedWindow('1', cv2.WINDOW_NORMAL | cv2.WINDOW_GUI_NORMAL)\n cv2.resizeWindow('1', 1080, 720)\n cv2.imshow(\"1\", np.hstack([img, (255-img)]))\nviewer.set_impro_function(impro, own_window=True)\n```\nIn both cases, DON'T DESTROY ALL OpenCV windows or wait for key pressed in it!\n\n#### Viewer\nWe have already created our viewer and set its configuration. Now we can display defined widgets using method `show_interactive_panel`\nwith parameters `image_folder` and `window_size`.\nThe panel contains 4 buttons:\n1. Save configuration - save current values of features to camera's inner memory (UserSet)\n1. Load configuration - load values of features from camera's inner memory (UserSet) to the widgets\n1. Continuous shot - start streaming frames from the camera\n1. Single shot - grab a one frame\n\nAlso we can press 's' key to save raw camera image or impro function return value (but only when own_window=False) to `image_folder`.\nTo close OpenCV windows just push 'q' on the keyboard. We don't have to launch this cell once more to try the same \nprocedure with the image, just change wanted values and push the button. That's it!\n\nFor configuration above we should see this interactive panel:\n![Basler OpenCV viewer](images/widget.png)\n\n#### Example\nWe can use our viewer along with more complex image processing function for detection of numbers: \n```python\ndef impro(img):\n img_rgb = img.copy()\n img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)\n _, img_gray = cv2.threshold(img_gray, 170, 255, cv2.THRESH_BINARY)\n img_gray = 255 - img_gray\n _, contours, _ = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n selected_contours = []\n for c in contours:\n contour_area = cv2.contourArea(c)\n x,y,w,h = cv2.boundingRect(c) \n bounding_rect_area = w*h\n if(contour_area > 80 and contour_area/bounding_rect_area < 0.75):\n selected_contours.append(c)\n\n cv2.drawContours(img_rgb, selected_contours, -1, (0,0,255), thickness=cv2.FILLED) \n img = cv2.putText(img, \"Original\", (10, 100), cv2.FONT_HERSHEY_SIMPLEX, 4, (255,0,0), 8)\n img_rgb = cv2.putText(img_rgb, \"Found numbers\", (10, 100), cv2.FONT_HERSHEY_SIMPLEX, 4, (255,0,0), 8)\n return np.hstack([img, img_rgb])\n```\n![Number detection](images/impro-function-example.png)\n\n#### Save or get image from camera\n\nIn previous steps we set up camera features parameters using widgets. Now we can save camera image on disc or get \nraw openCV image (impro function return value if specified).\n\n```python\n# Save image\nviewer.save_image('~/Documents/images/grabbed.png')\n\n# Get grabbed image\nimg = viewer.get_image()\n```", "description_content_type": "text/markdown", "docs_url": null, "download_url": "https://github.com/mbalatsko/pypylon-opencv-viewer/archive/1.1.0.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/mbalatsko/pypylon-opencv-viewer", "keywords": "basler,pypylon,opencv,jypyter,pypylon viewer,opencv pypylon", "license": "MIT License", "maintainer": "", "maintainer_email": "", "name": "pypylon-opencv-viewer", "package_url": "https://pypi.org/project/pypylon-opencv-viewer/", "platform": "", "project_url": "https://pypi.org/project/pypylon-opencv-viewer/", "project_urls": { "Download": "https://github.com/mbalatsko/pypylon-opencv-viewer/archive/1.1.0.tar.gz", "Homepage": "https://github.com/mbalatsko/pypylon-opencv-viewer" }, "release_url": "https://pypi.org/project/pypylon-opencv-viewer/1.1.0/", "requires_dist": null, "requires_python": "", "summary": "Impro function application while saving and getting image", "version": "1.1.0" }, "last_serial": 5861265, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "0aa8ae14bc88e1b024eab4f24b5d8d69", "sha256": "752cf11a3bcd9f347561aecb276888b5d118e9852e895168fb6802c19c785f56" }, "downloads": -1, "filename": "pypylon-opencv-viewer-1.00.tar.gz", "has_sig": false, "md5_digest": "0aa8ae14bc88e1b024eab4f24b5d8d69", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5769, "upload_time": "2018-09-28T20:58:50", "url": "https://files.pythonhosted.org/packages/9e/ce/ea9d03f712dbf352cb31cf82e330005eddddf833d70f205af16de50f26e4/pypylon-opencv-viewer-1.00.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "29f1b16500579732ba0244c8dd0e144d", "sha256": "d5b99075f9f23a760c6c7a493be6b12acf20624b8c5a0aad1b8adadb20fdfe77" }, "downloads": -1, "filename": "pypylon-opencv-viewer-1.0.1.0.tar.gz", "has_sig": false, "md5_digest": "29f1b16500579732ba0244c8dd0e144d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5985, "upload_time": "2018-10-02T12:44:16", "url": "https://files.pythonhosted.org/packages/46/2f/632e8a94f06986b2c2410aa65ea36aecf4880484e4a0c2fd031971c7758d/pypylon-opencv-viewer-1.0.1.0.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "24187294ceb9267ea3fd699e7059e246", "sha256": "d7c7ae849641b9759340b5ef11ed49ffde07ebcdd25be94a60b52f9a498dd35a" }, "downloads": -1, "filename": "pypylon-opencv-viewer-1.0.02.tar.gz", "has_sig": false, "md5_digest": "24187294ceb9267ea3fd699e7059e246", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6272, "upload_time": "2018-10-05T10:37:45", "url": "https://files.pythonhosted.org/packages/03/f9/55c8afb27098eb5b04d73a31e99b14a04afdff3463d81371b5c7855b7c7b/pypylon-opencv-viewer-1.0.02.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "255c1fcab85ea9657df3ad32c87807f7", "sha256": "a3fcb7f1d1a4c1ca571d966d4a1b14e7098daa1cde9f9b07b34eb955438fa739" }, "downloads": -1, "filename": "pypylon-opencv-viewer-1.0.3.0.tar.gz", "has_sig": false, "md5_digest": "255c1fcab85ea9657df3ad32c87807f7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6346, "upload_time": "2018-10-31T14:51:26", "url": "https://files.pythonhosted.org/packages/77/ee/23cc4d4d7ccf22943412a7e8edd44d79ece51fe903b7ecf0673c28ecab06/pypylon-opencv-viewer-1.0.3.0.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "92d3c82c7e679d20acb7a1e66978340c", "sha256": "2c9c1d3f32a29aae4dee1fed2276251f0d18aa85b467f435750ec85097e4a0e5" }, "downloads": -1, "filename": "pypylon-opencv-viewer-1.0.4.tar.gz", "has_sig": false, "md5_digest": "92d3c82c7e679d20acb7a1e66978340c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12447, "upload_time": "2019-09-20T10:43:13", "url": "https://files.pythonhosted.org/packages/4e/95/da0e4c9d1bd08595274edcca13f20b8df8f1b7f6b031563ec19c06815d18/pypylon-opencv-viewer-1.0.4.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "1e4c5df8d6e96c46adf2ae3aed2dade3", "sha256": "26811e42c892b6a6f60d4ee8d380b759393b8fff774c19100482d869b5b56255" }, "downloads": -1, "filename": "pypylon-opencv-viewer-1.1.0.tar.gz", "has_sig": false, "md5_digest": "1e4c5df8d6e96c46adf2ae3aed2dade3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12451, "upload_time": "2019-09-20T10:43:43", "url": "https://files.pythonhosted.org/packages/a1/37/0f4a664e9d3271bcc0565812653f269c1c8bd471b67706d9674f37788ce7/pypylon-opencv-viewer-1.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "1e4c5df8d6e96c46adf2ae3aed2dade3", "sha256": "26811e42c892b6a6f60d4ee8d380b759393b8fff774c19100482d869b5b56255" }, "downloads": -1, "filename": "pypylon-opencv-viewer-1.1.0.tar.gz", "has_sig": false, "md5_digest": "1e4c5df8d6e96c46adf2ae3aed2dade3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12451, "upload_time": "2019-09-20T10:43:43", "url": "https://files.pythonhosted.org/packages/a1/37/0f4a664e9d3271bcc0565812653f269c1c8bd471b67706d9674f37788ce7/pypylon-opencv-viewer-1.1.0.tar.gz" } ] }