{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Measurement\n\nThis example shows how a typical measurement automation can be realized in ``itom``.\nLet's say a laser beam is detected by a camera. Different positions are to be approached\nwith a actuator stage and camera images are to be recorded.\nAfterwards the centroid position distribution of the beam is evaluated.\nFinally the result is plotted in three different ways using the ``itom.plot1``, ``matplotlib``\nand ``plotly`` plot engine. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from itom import actuator\nfrom itom import dataIO\nfrom itom import dataObject\nfrom itom import algorithms\nfrom itom import plot1\nfrom itom import plot2\n\nfrom itom import ui\nfrom itomUi import ItomUi\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport plotly.express as px" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is the main measurement class consisting of following methods:\n\n* **__init__** : Constructor of the class which opens the ``MeasureGUI``, connects to a camera ``DummyGrabber``,\n connects to a actuator stage ``DummyMotor``.\n\n* **on_pushButtonStart_clicked** : Start measurement methods which is connected to the signal ``clicked``\n of the button ``pushButtonStart`` of the GUI.\n\n* **measurementRoutine** : Measurement routine which moves the actuator ``DummyMotor`` to the given\n positions, captures the camera ``DummyGrabber`` images and evaluates the centroid distribution.\n Afterwards the live image of the camera is activated again.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class MeasureDemoGUI(ItomUi):\n def __init__(self):\n \"\"\"Constructor method of the MeasureDemoGUI class.\"\"\"\n # init the gui\n ItomUi.__init__(self, \"MeasureGUI.ui\", ui.TYPEWINDOW, deleteOnClose=True)\n\n # init cam and mot\n self.cam = dataIO(\"DummyGrabber\", imageType=\"gaussianSpot\")\n self.mot = actuator(\"DummyMotor\", numAxis=1)\n self.mot.setParam(\"speed\", 1000)\n\n # define widget values\n self.gui.spinBoxNumZSteps[\"value\"] = 100\n self.gui.doubleRangeWidgetZRange[\"minimum\"] = 0.0\n self.gui.doubleRangeWidgetZRange[\"maximum\"] = 1000.0\n self.gui.doubleRangeWidgetZRange[\"minimumValue\"] = 10.0\n self.gui.doubleRangeWidgetZRange[\"maximumValue\"] = 555.0\n\n # show liveimage\n self.cam.startDevice()\n self.gui.camPlot[\"camera\"] = self.cam\n self.gui.camPlot[\"colorMap\"] = \"OSIRainbow\"\n self.gui.camPlot[\"keepAspectRatio\"] = True\n\n # access motor controller\n self.gui.MotorAxisController[\"actuator\"] = self.mot\n self.gui.MotorAxisController[\"numAxis\"] = 1\n self.gui.MotorAxisController[\"defaultAxisType\"] = \"TypeLinear\"\n\n # connect\n # self.gui.pushButtonStart.connect(\"clicked()\", self.startMeasure)\n\n # define measure data object\n self.imageStack = None\n self.centroidData = None\n\n # connect stop button to interrupt\n self.gui.pushButtonStop.invokeKeyboardInterrupt(\"clicked()\")\n\n # show the gui\n self.gui.show()\n self.gui.call(\"statusBar\").call(\"showMessage\", \"Initialization finished.\", 5000)\n\n return\n\n @ItomUi.autoslot(\"\")\n def on_pushButtonStart_clicked(self):\n \"\"\"Function trigger by pushButtonStart\"\"\"\n self.gui.call(\"statusBar\").call(\"showMessage\", \"Start Measurement\", 5000)\n with self.disableGui([self.gui.pushButtonStart], showWaitCursor=False):\n minVal = self.gui.doubleRangeWidgetZRange[\"minimumValue\"]\n maxVal = self.gui.doubleRangeWidgetZRange[\"maximumValue\"]\n steps = self.gui.spinBoxNumZSteps[\"value\"]\n self.measurementRoutine(minVal, maxVal, steps)\n self.gui.call(\"statusBar\").call(\"showMessage\", \"Stop Measurement\", 5000)\n return\n\n def measurementRoutine(self, zMin: float, zMax: float, numZSteps: int):\n \"\"\"Measurement routine along input z range\n\n Args:\n zMin (float): Minimum z position\n zMax (float): Maximum z position\n numZSteps (int): Number of z positions\n \"\"\"\n # Create z positions vector\n zVec = np.linspace(zMin, zMax, num=numZSteps)\n\n # disable camera auto grabbing\n self.cam.disableAutoGrabbing()\n\n # define measurement data object\n bpp = self.cam.getParam(\"bpp\")\n if bpp == 8:\n dtype = \"uint8\"\n else:\n dtype = \"uint16\"\n self.imageStack = dataObject([len(zVec), self.cam.getParam(\"sizey\"), self.cam.getParam(\"sizex\")], dtype)\n self.centroidData = dataObject([2, len(zVec)], \"float32\")\n\n # centroidMarker dObj\n centroidMarker = dataObject([2, 1], \"float32\")\n\n # loop for all z positions\n for idx, z in enumerate(zVec):\n self.gui.call(\"statusBar\").call(\"showMessage\", \"z measurement posotion {}\".format(z), 5000)\n # goto new motor position\n self.mot.setPosAbs(0, z)\n\n # acquire image\n d = dataObject()\n self.cam.acquire()\n self.cam.copyVal(d)\n\n # eval the centroid\n cYI, cXI, cY, cX = algorithms.centroidXY(d)\n # add to data stack\n self.imageStack[idx, :, :] = d\n self.centroidData[0, idx] = cX\n self.centroidData[1, idx] = cY\n\n # plot current image and centroid\n self.gui.camPlot[\"source\"] = d\n centroidMarker[0, 0] = cX\n centroidMarker[1, 0] = cY\n self.gui.camPlot.call(\"deleteMarkers\")\n self.gui.camPlot.call(\"plotMarkers\", centroidMarker, \"w+25;2\", \"centroid\", 0)\n self.gui.progressBar[\"value\"] = idx / (len(zVec) - 1) * 100\n\n self.cam.enableAutoGrabbing()\n self.gui.camPlot.call(\"deleteMarkers\")\n self.gui.camPlot[\"camera\"] = self.cam\n\n # define imageStack\n self.imageStack.setAxisDescription(0, \"z axis of actuator\")\n self.imageStack.setAxisDescription(1, \"y axis\")\n self.imageStack.setAxisDescription(2, \"x axis\")\n self.imageStack.setAxisUnit(0, \"mm\")\n self.imageStack.setAxisUnit(1, \"\\xb5m\")\n self.imageStack.setAxisUnit(2, \"\\xb5m\")\n\n # calc meta info\n zScale = (zMax - zMin) / (numZSteps - 1)\n zOffset = -(zVec[0] / zScale)\n self.imageStack.setAxisScale(0, zScale)\n self.imageStack.setAxisOffset(0, zOffset)\n self.imageStack.setAxisScale(1, 17e-3) # pixel pitch of 17 \\xb5m\n self.imageStack.setAxisScale(2, 17e-3) # pixel pitch of 17 \\xb5m\n self.imageStack.valueDescription = \"intensity\"\n self.imageStack.valueUnit = \"counts\"\n\n # plot imagestack\n plot2(self.imageStack)\n self.centroidData.setAxisScale(1, zScale)\n self.centroidData.setAxisOffset(1, zOffset)\n self.centroidData.valueDescription = \"centroid position\"\n self.centroidData.valueUnit = \"mm\"\n self.centroidData.setTag(\"legendTitle0\", \"x centroid\")\n self.centroidData.setTag(\"legendTitle1\", \"y centroid\")\n\n # plot x, y as lines\n plot1(self.centroidData, properties={\"legendPosition\": \"Right\", \"grid\": \"GridMajorXY\"})\n\n # plot y vs. x\n yData = self.centroidData[0, :].squeeze()\n xData = self.centroidData[1, :].squeeze()\n yData.valueDescription = \"y centroid position\"\n xData.valueDescription = \"x centroid position\"\n plot1(\n yData,\n xData=xData,\n properties={\n \"keepAspectRatio\": True,\n \"grid\": \"GridMajorXY\",\n \"lineStyle\": \"NoPen\",\n \"lineSymbol\": \"XCross\",\n },\n )\n\n # plot using matplotlib\n xData = np.squeeze(np.array(xData))\n yData = np.squeeze(np.array(yData))\n\n plt.figure()\n plt.scatter(xData, yData)\n plt.xlabel(\"x centroid /mm\")\n plt.ylabel(\"y centroid /mm\")\n plt.show()\n\n # plot using plotly\n figly = px.scatter(x=xData, y=yData, labels={\"x\": \"x centroid /mm\", \"y\": \"y centroid /mm\"})\n figly.show()\n\n\n# -------------------------------\nif __name__ == \"__main__\":\n demo = MeasureDemoGUI()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" } }, "nbformat": 4, "nbformat_minor": 0 }