├── .gitignore ├── LICENSE ├── README.md ├── READMECN.md ├── __init__.py ├── doc ├── Chinese │ ├── menus │ │ ├── Filter Demo │ │ │ └── Gaussian Demo.md │ │ └── Start Here │ │ │ ├── Hello World.md │ │ │ └── Who Are You.md │ └── tools │ │ └── DemoTool │ │ └── Pencil Demo.md ├── English │ ├── attention.md │ ├── document.md │ ├── filter.md │ ├── free.md │ ├── macros.md │ ├── markdown.md │ ├── menus │ │ ├── Filter Demo │ │ │ └── Gaussian Demo.md │ │ └── Start Here │ │ │ ├── Hello World.md │ │ │ └── Who Are You.md │ ├── publish.md │ ├── report.md │ ├── simple.md │ ├── start.md │ ├── table.md │ ├── tool.md │ ├── tools │ │ └── DemoTool │ │ │ └── Pencil Demo.md │ ├── widget.md │ └── workflow.md └── chinese │ ├── attention.md │ ├── document.md │ ├── filter.md │ ├── free.md │ ├── macros.md │ ├── markdown.md │ ├── publish.md │ ├── report.md │ ├── simple.md │ ├── start.md │ ├── table.md │ ├── tool.md │ ├── widget.md │ └── workflow.md ├── lang └── Chinese │ └── demoplugin.dic ├── menus ├── Demos │ ├── Filter Demo │ │ ├── __init__.py │ │ └── filtersdemo_plgs.py │ ├── Free Demo │ │ ├── __init__.py │ │ └── freedemo_plgs.py │ ├── Macros Demo │ │ ├── Macros Coins Segment.mc │ │ ├── Macros Gaussian Invert.mc │ │ └── __init__.py │ ├── Markdown Demo │ │ ├── MarkDown Demo.md │ │ └── __init__.py │ ├── Report Demo │ │ ├── Coins Report.rpt │ │ ├── Personal Information.rpt │ │ └── __init__.py │ ├── Simple Demo │ │ ├── __init__.py │ │ └── simpledemo_plgs.py │ ├── Start Here │ │ ├── __init__.py │ │ └── start_plg.py │ ├── Table Demo │ │ ├── __init__.py │ │ └── tabledemo_plg.py │ ├── Widget Demo │ │ ├── __init__.py │ │ └── widgetdemo_wgt.py │ ├── Workflow Demo │ │ ├── Workflow Coins Demo.wf │ │ └── __init__.py │ └── __init__.py └── __init__.py ├── requirements.txt ├── tools ├── DemoTool │ ├── __init__.py │ ├── tooldemo.gif │ └── tooldemo_tol.py └── __init__.py └── widgets ├── DemoWidgets └── widgetdemo_wgt.py └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, ImagePy 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Demo Plugin 2 | 3 | **Path:** https://github.com/Image-Py/demoplugin 4 | 5 | **Version:** 0.1 6 | 7 | **Author:** YXDragon 8 | 9 | **Email:** yxdragon@imagepy.org 10 | 11 | **Keyword:** demo, tutorial 12 | 13 | **Description:** a friendly development tutorial. 14 | 15 | **[English Document](README.md) | [中文文档](READMECN.md)** 16 | 17 | *This is a demo project to show How to write ImagePy plugin. Including the usage of all kinds of plugin, with document wrote in detail. Developers can take this project as example.* 18 | 19 | 20 | 21 | ## Install 22 | 23 | ImagePy Menu:`Plugins > Manager > Plugins Manager` input `demo`, and select the `Demo Plugin`, then click `Install/Update`. When complete the installing, the user interface would be changed. New plugins' menu, tool, and widget would be loaded in place. 24 | 25 | ![06](http://idoc.imagepy.org/demoplugin/06.png) 26 |
Install DemoPlugin

27 | 28 | ## [Basic](doc/start.md) 29 | 30 | **[Start here](doc/start.md)** 31 | 32 | 1. [What is plugin](doc/start.md#What-is-plugin) 33 | 2. [Hello World(my first plugin)](doc/start.md#Hello-World) 34 | 3. [Who Are You(interactive)](doc/start.md#Who-Are-You) 35 | 4. [Questionnaire(parameter dialog in detail)](doc/start.md#Questionnaire) 36 | 5. [Multi plugin in one file](doc/start.md#Implement-multi-plugins-in-one-file) 37 | 38 | 39 | 40 | ## Plugin development 41 | 42 | **[Markdown: document](doc/markdown.md)** 43 | 44 | 1. [Markdown Demo](doc/markdown.md#MarkDown-Demo) 45 | 46 | **[Macros: serialise existing function](doc/macros.md#Macros)** 47 | 48 | 1. [Gaussian blur - Invert](doc/macros.md#Gaussian-Blur-Then-Invert) 49 | 2. [Coins Segmentation Macros](doc/macros.md#Coins-Segmentation) 50 | 51 | **[Workflow: interactive macros](doc/workflow.md)** 52 | 53 | 1. [Coins Segment Workflow](doc/workflow.md#Coins-Segmentation-Workflow) 54 | 55 | **[Report: generate report](doc/report.md)** 56 | 57 | 1. [Personal Information](doc/report.md#Personal-Information) 58 | 2. [Coins Report: report for coins segment](doc/report.md#Coins-Segmentation) 59 | 3. [Rule of Report design](doc/report.md#Report-template-design-principles) 60 | 61 | **[Filter: image filter in 2d](doc/filter.md)** 62 | 63 | 1. [Invert Demo: without parameter](doc/filter.md#Invert) 64 | 2. [Gaussian Demo: with parameter](doc/filter.md#Gaussian) 65 | 3. [Filter operating mechanism](doc/filter.md#Filter-operating-mechanism) 66 | 67 | **[Simple: treat sequence and other attributes](doc/simple.md)** 68 | 69 | 1. [Gaussian 3D Demo: filter in 3d](doc/simple.md#Gaussian3D) 70 | 2. [Red Lut Demo: operate color lookup table](doc/simple.md#SetLUT) 71 | 3. [ROI Inflate Demo: operate ROI](doc/simple.md#Inflate-ROI) 72 | 4. [Unit Demo: set unit and scale](doc/simple.md#Set-Scale-And-Unit) 73 | 5. [Draw Mark Demo: Set Mark](doc/simple.md#Mark) 74 | 6. [Simple operating mechanism](doc/simple.md#Simple-operating-mechanism) 75 | 76 | **[Table: treat dataframe](doc/table.md)** 77 | 78 | 1. [Generate Table Demo: generate table](doc/table.md#Generate-score-list) 79 | 2. [Sort By Key Demo: sort](doc/table.md#Sort-by-field) 80 | 3. [Table Plot Demo: plot](doc/table.md#Bar-Chart) 81 | 4. [Table operation mechanism](doc/table.md#Table-operation-mechanism) 82 | 83 | **[Free: depend on nothing](doc/free.md)** 84 | 85 | 1. [New Image Demo: creat image](doc/free.md#Create-image) 86 | 2. [About Demo: the about dialog](doc/free.md#About-dialog-box) 87 | 3. [Close Demo: quit program](doc/free.md#Quit) 88 | 4. [Free operating mechanism](doc/free.md#Free-operating-mechanism) 89 | 90 | **[Tool: mouse interaction](doc/tool.md)** 91 | 92 | 1. [Painter Demo: draw with mouse](doc/tool.md#Brush-Tool) 93 | 2. [Tool operating mechanism](doc/tool.md#Tool-operating-mechanism) 94 | 95 | **[Widget: customed panel](doc/widget.md)** 96 | 97 | 1. [Widget Demo](doc/widget.md#Widget-Demo) 98 | 2. [Widget opterating mechanism](doc/widget.md#Widget-opterating-mechanism) 99 | 100 | 101 | 102 | ## [Plugin Release](doc/publish.md) 103 | 104 | **[Function Organization](doc/publish.md#Function-organization)** 105 | 106 | 1. [Functional partitioning](doc/publish.md#Function-organization) 107 | 2. [Set Order](doc/publish.md#Set-Order) 108 | 109 | **[Plugin project creation](doc/publish.md#Plugin-project-creation)** 110 | 111 | 1. [Create a plugin project repository](doc/publish.md#Plugin-project-creation) 112 | 2. [Write requirements](doc/publish.md#Plugin-project-creation) 113 | 3. [Write readme](doc/publish.md#Plugin-project-creation) 114 | 4. [Install Plugin](doc/publish.md#Plugin-project-creation) 115 | 116 | **[Release to ImagePy](doc/publish.md#Release-to-ImagePy)** 117 | 118 | 1. [Send Pull Request to ImagePy](doc/publish.md#Release-to-ImagePy) 119 | 2. [About the top-level menu](doc/publish.md#Release-to-ImagePy) 120 | 121 | 122 | 123 | ## [Write Document](doc/document.md) 124 | 125 | **[Write The Opteration Manual](doc/document.md#Write-The-Opteration-Manual)** 126 | 127 | **[View The Operation Manual](doc/document.md#View-Operation-Manual)** 128 | 129 | 130 | 131 | ## [Attention](doc/attention.md#注意事项) 132 | 133 | **[User Friendliness](doc/attention.md#User-Friendliness)** 134 | 135 | **[Developer Friendliness](doc/attention.md#Developer-Friendliness)** 136 | 137 | **[Communicate Timely](doc/attention.md#Communicate-Timely)** 138 | 139 | 140 | 141 | **This document introduces how to write ImagePy plugin. More questions not exhaustive here,please post in [forum.Image.sc](https://forum.image.sc/)** 142 | 143 | -------------------------------------------------------------------------------- /READMECN.md: -------------------------------------------------------------------------------- 1 | # Demo Plugin 2 | 3 | **Path:** https://github.com/Image-Py/demoplugin 4 | 5 | **Version:** 0.1 6 | 7 | **Author:** YXDragon 8 | 9 | **Email:** yxdragon@imagepy.org 10 | 11 | **Keyword:** demo, tutorial 12 | 13 | **Description:** a friendly develop tutorial. 14 | 15 | **[English Document](README.md) | [中文文档](READMECN.md)** 16 | 17 | *这是一个ImagePy插件项目,里面覆盖了各类插件的编写方法和用法,并配有详细的文档,ImagePy的插件开发者可以以此为参考* 18 | 19 | 20 | 21 | ## 安装 22 | 23 | ImagePy菜单:`Plugins > Manager > Plugins Manager` 在输入框内输入demo进行查询,选中Demo Plugin,点击`Install`,完成后菜单栏出现Demo菜单,工具栏会加入Demo工具,组件栏也会加入Demo组件。 24 | 25 | ![06](http://idoc.imagepy.org/demoplugin/06.png) 26 |
Install DemoPlugin

27 | 28 | ## [基础预备](doc/chinese/start.md) 29 | 30 | **[从这里开始](doc/chinese/start.md)** 31 | 32 | 1. [什么是插件](doc/chinese/start.md#什么是插件) 33 | 2. [Hello World(第一个插件)](doc/chinese/start.md#Hello-World) 34 | 3. [Who Are You(带有交互)](doc/chinese/start.md#Who-Are-You) 35 | 4. [Questionnaire(参数对话框详解)](doc/chinese/start.md#Questionnaire) 36 | 5. [一个文件内实现多个插件](doc/chinese/start.md#一个文件内实现多个插件) 37 | 38 | 39 | 40 | ## 插件开发 41 | 42 | **[Markdown: 文档提示](doc/chinese/markdown.md)** 43 | 44 | 1. [Markdown Demo](doc/chinese/markdown.md#MarkDown-Demo) 45 | 46 | **[Macros: 用宏串联已有功能](doc/chinese/macros.md#Macros)** 47 | 48 | 1. [高斯模糊再求反](doc/chinese/macros.md#高斯模糊再求反) 49 | 2. [Coins Segment Macros:硬币分割](doc/chinese/macros.md#分割硬币) 50 | 51 | **[Workflow: 可交互的宏](doc/chinese/workflow.md)** 52 | 53 | 1. [Coins Segment Workflow:按照指引进行硬币分割](doc/chinese/workflow.md#硬币分割工作流) 54 | 55 | **[Report: 生成报表](doc/chinese/report.md)** 56 | 57 | 1. [Personal Information:填写个人信息](doc/chinese/report.md#个人信息) 58 | 2. [Coins Report:硬币分割成果](doc/chinese/report.md#硬币分割) 59 | 3. [Report 插件的设计原则](doc/chinese/report.md#报表模板设计原则) 60 | 61 | **[Filter: 二维图像滤波器](doc/chinese/filter.md)** 62 | 63 | 1. [Invert Demo:无参数的插件](doc/chinese/filter.md#Invert) 64 | 2. [Gaussian Demo:带有参数的插件](doc/chinese/filter.md#Gaussian) 65 | 3. [Filter 的运行机制](doc/chinese/filter.md#Filter-运行机制) 66 | 67 | **[Simple: 图像整体操作](doc/chinese/simple.md)** 68 | 69 | 1. [Gaussian 3D Demo:三维滤波](doc/chinese/simple.md#Gaussian3D) 70 | 2. [Red Lut Demo:设定索引色](doc/chinese/simple.md#SetLUT) 71 | 3. [ROI Inflate Demo:操作ROI](doc/chinese/simple.md#Inflate-ROI) 72 | 4. [Unit Demo: 设置比例尺及单位](doc/chinese/simple.md#SEt-Scale-And-Unit) 73 | 5. [Draw Mark Demo: 设置Overlay Mark](doc/chinese/simple.md#Mark) 74 | 6. [Simple 的运行机制](doc/chinese/simple.md#Simple-运行机制) 75 | 76 | **[Table: 表格数据](doc/chinese/table.md)** 77 | 78 | 1. [Generate Table Demo:数据表生成](doc/chinese/table.md#生成成绩单) 79 | 2. [Sort By Key Demo:排序](doc/chinese/table.md#根据某科成绩排序) 80 | 3. [Table Plot Demo:绘图](doc/chinese/table.md#绘制柱状图) 81 | 4. [Table 运行机制](doc/chinese/table.md#Table-运行机制) 82 | 83 | **[Free: 没有任何依赖的插件](doc/chinese/free.md)** 84 | 85 | 1. [New Image Demo: 创建图像](doc/chinese/free.md#创建图像) 86 | 2. [About Demo:关于对话框](doc/chinese/free.md#关于对话框) 87 | 3. [Close Demo:退出软件](doc/chinese/free.md#退出软件) 88 | 4. [Free 的运行机制](doc/chinese/free.md#Free-的运行机制) 89 | 90 | **[Tool: 鼠标交互工具](doc/chinese/tool.md)** 91 | 92 | 1. [Painter Demo:画笔工具](doc/chinese/tool.md#画笔工具) 93 | 2. [Tool的运行机制](doc/chinese/tool.md#Tool-的运行机制) 94 | 95 | **[Widget: 桌面小部件](doc/chinese/widget.md)** 96 | 97 | 1. [Widget Demo:桌面小部件演示](doc/chinese/widget.md#桌面组件演示) 98 | 2. [Tool的运行机制](doc/chinese/widget.md#widget-的运行机制) 99 | 100 | 101 | 102 | ## [插件项目发布](doc/chinese/publish.md) 103 | 104 | **[插件的组织方式](doc/chinese/publish.md#功能组织)** 105 | 106 | 1. [功能划分](doc/chinese/publish.md#功能组织) 107 | 2. [顺序设定](doc/chinese/publish.md#功能组织) 108 | 109 | **[插件项目创建](doc/chinese/publish.md#插件项目创建)** 110 | 111 | 1. [创建插件项目仓库](doc/chinese/publish.md#插件项目创建) 112 | 2. [编写requirements](doc/chinese/publish.md#插件项目创建) 113 | 3. [编写readme](doc/chinese/publish.md#插件项目创建) 114 | 4. [插件的安装](doc/chinese/publish.md#插件项目创建) 115 | 116 | **[发布到 ImagePy](doc/chinese/publish.md#发布到-ImagePy)** 117 | 118 | 1. [给ImagePy发Pull Request](doc/chinese/publish.md#发布到-ImagePy) 119 | 2. [关于顶级菜单](doc/chinese/publish.md#发布到-ImagePy) 120 | 121 | 122 | 123 | ## [文档编写](doc/chinese/document.md) 124 | 125 | **[编写操作手册](doc/chinese/document.md#编写操作手册)** 126 | 127 | **[查阅操作手册](doc/chinese/document.md#查阅操作手册)** 128 | 129 | 130 | 131 | ## [注意事项](doc/chinese/attention.md#注意事项) 132 | 133 | **[用户友好性](doc/chinese/attention.md#用户友好性)** 134 | 135 | **[开发者友好性](doc/chinese/attention.md#开发者友好性)** 136 | 137 | **[及时沟通](doc/chinese/attention.md#及时沟通)** 138 | 139 | 140 | 141 | **本篇文档相对系统的介绍了ImagePy的插件开发,但是依然无法详尽,关于更多ImagePy使用,开发上的问题请在[forum.Image.sc](https://forum.image.sc/)行进行讨论** -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/__init__.py -------------------------------------------------------------------------------- /doc/Chinese/menus/Filter Demo/Gaussian Demo.md: -------------------------------------------------------------------------------- 1 | # 高斯模糊示例 2 | 3 | **描述:** 一个高斯模糊的示例,用于展示如何编写插件 4 | 5 | 6 | ## 参数 7 | 8 | **标准差:** 高斯卷积核的标准差,越大结果越模糊 9 | 10 | 11 | 12 | ![14](http://idoc.imagepy.org/demoplugin/14.png) 13 | 14 |
Gaussian blur with sigma:5, supporting roi

15 | 16 | -------------------------------------------------------------------------------- /doc/Chinese/menus/Start Here/Hello World.md: -------------------------------------------------------------------------------- 1 | # 你好,ImagePy 2 | 3 | **描述:** 你好ImagePy 4 | 5 | ## 参数 6 | 7 | 无 -------------------------------------------------------------------------------- /doc/Chinese/menus/Start Here/Who Are You.md: -------------------------------------------------------------------------------- 1 | # 你是谁 2 | 3 | **描述:** 姓名和年龄 4 | 5 | 6 | ## 参数 7 | 8 | **姓名:** 姓名 9 | 10 | **年龄:** 几岁 -------------------------------------------------------------------------------- /doc/Chinese/tools/DemoTool/Pencil Demo.md: -------------------------------------------------------------------------------- 1 | # Pencil Demo 2 | 3 | **Description:** a pencil to show how to write a tool plugin. 4 | 5 | 6 | ## Parameter 7 | 8 | **width:** the pencil's pix width 9 | 10 | **color:** the pencil's color 11 | 12 | 13 | 14 | ![14](http://idoc.imagepy.org/demoplugin/24.png) 15 | 16 |
write ImagePy with width:10, color:red

17 | 18 | -------------------------------------------------------------------------------- /doc/English/attention.md: -------------------------------------------------------------------------------- 1 | # Matters Needing Attention 2 | Although the details are not exhaustive, we have introduced the development, release and documentation of plug-ins. Here are some considerations for the development process. 3 | 4 | 5 | 6 | ## User Friendliness 7 | 8 | If it is for your own use, you don't need to spend too much energy. But you want other users to be able to use your plug-ins, then user friendliness is very important, including: 9 | 10 | 1. **Reasonable functional organization** 11 | 12 | Divide the functions reasonably and present them with appropriate titles. 13 | 14 | 2. **Reasonable interaction way** 15 | 16 | For example, the parameter design of the plug-in can have a certain degree of versatility but not messy, and the use of the tool is in line with the use habits. 17 | 18 | 3. **A concise document** 19 | 20 | If you have the energy, it is best to write a manual for the plug-in. It is necessary to be illustrated. 21 | 22 | 4. **Optimize the performance experience as much as possible** 23 | 24 | Of course, this point is endless, and mainly depends on the algorithm. The faster the better, waiting is always bad. 25 | 26 | 27 | 28 | ## Developer Friendliness 29 | 30 | **ImagePy puts developer friendliness in the same position as user friendliness**, because developers and users are a group that can learn from each other, and the line between the two is blurred And they can be transformed into each other. Here are a few development concepts of ImagePy. 31 | 32 | 1. **ImagePy is not an algorithm library, just a connector** 33 | 34 | ImagePy does not reserch algorithms, but only provides necessary presentation and interaction. It is committed to enabling algorithm developers to configure algorithms with minimal code. You can integrate them into ImagePy, and turn algorithms into tools for others, even non-programmers. 35 | 36 | 2. **Isolate the UI as much as possible** 37 | 38 | UI for scientific research or the programmer is always unpleasant, ImagePy try your best to isolate UI. Most configuration functions can all be ` para `, ` view ` configuration dialog box to complete the parameters generated, and ` tool ` is abstracted as ` mouse_down `, ` mouse_up `, ` mouse_move `, ` mouse_wheel ` four interface implementation. And some deeply customed function have to use ` widget `, only this it requires developers to write your own UI code. 39 | 40 | 41 | 3. **Takes the algorithm itself as the core** 42 | 43 | Image data of ImagePy is based on ` Numpy `, tabular data based on ` Pandas `, vector data based on ` Shapely `, and these are universal data structures that are the equivalent of Python standard of scientific computing. As connectors, ImagePy is only support, and not interfere in writing of the algorithm. **so developers must not realize the core algorithm in ` run ` function implementation, because other developers will not be able to use them, which the meaning of open source will be discounted**. Algorithm, UI, and hybrid events result in ImageJ1 algorithm code difficultly invoked by other developers, who have to use ` IJ.run(...) `. Perhaps ImageJ2 is trying to change this situation. So this is not allowed in the ImagePy usage. 44 | 45 | **The way we recommend:** 46 | 47 | 1)if your plug-in only implements simple data manipulation with a few lines of code, OK, it can be implemented in ` run `. 48 | 49 | 2) If your algorithm is relatively complex, so it is best to write it in a separate file, and this module do not refer to any ImagePy related modules, which only based on ` Numpy `, ` Pandas ` standards such as scientific computing library. So that others can copy out, and ` import ` use. 50 | 51 | 3) if your algorithm is of great significance, versatility is very strong. Be sure to create a separate algorithm project, upload ` pypi `, and import it from your plug-in project (remember to add it in requirements.txt). 52 | 53 | 4. **About macros and headless** 54 | 55 | Compared with ImageJ, ImagePy's macro function is very limited. Only serialise existing function, but can not implement other logic. It is closely related to the design concept of ImagePy that **ImagePy is just connector!**. Python is already so easy and powerful, why bother learning another obscure and non-generic macro? ImagePy have not support ` headless ` as well, because all the functions to the algorithm itself are the core, and ImagePy only provides **interaction**. So in the case of headless, interaction does not exist. Then what is the value of ImagePy ? What's the point of using ImagePy? **If all functions can be provided in the form of libraries not depend on ImagePy, why does developers want to write `macros` or ` headless ` code rather than a pure python code?** 56 | 57 | 58 | 59 | ## Communicate Timely 60 | 61 | Compared with ImageJ, ImagePy is still a child, and its framework and functions are not perfect yet. However, the advantage is that we can control and adjust it in real time without considering the powerful and huge plug-in system on our backs. As a plugin developer, if you encounter any difficulties in the process of plug-in development, and please feel free to contact us.Especially when you feel a plug-in development very complex, it is possible that we lack of some aspect support of framework. We can discuss at any time on the plug-in development ,and at the same time,we improve the main frame together. Let ImagePy better realize the value of connector and serve users and developers. 62 | 63 | ImagePy is a partner of www.forum.image.sc, and any development, usage issues can be discussed there. 64 | 65 | -------------------------------------------------------------------------------- /doc/English/document.md: -------------------------------------------------------------------------------- 1 | # Write Operation Manual 2 | 3 | The manual is not a required part, but it is very important that you write your own plug-in to better serve your users. Here we demonstrate how to write a manual for the plug-in. 4 | 5 | ## Write The Opteration Manual 6 | 7 | Under the top-level directory of your plug-in project, create a `doc` folder, where you can write action documents for your plug-in using `markdown`. Note that the file name needs to be the same as the `title` of the plug-in, so that the `ImagePy` document manager can associate the document with the plug-in. Both tool-type and menu-type plug-ins can be documented. 8 | 9 | all the `markdown` files under `doc` are parsed and through the file name associated to the corresponding plugin, so there is no mandatory file organization way, but we strongly recommend that maintain a consistent with plug-in directory document directory (create `menus`, `tools`, `widgets` three top-level directory), convenient management and maintenance, so we can add more if necessary directory file, add the corresponding link, so the whole `doc` directory can also be read in the github or other online environment. 10 | 11 | ## View Operation Manual 12 | 13 | When the plugin is finished, we can check the document in the following ways: 14 | 15 | 1. We can use the Help button in the parameter dialog. 16 | 2. Right-click on the toolbar icon. 17 | 3. Use the various **`Tree`** views under the **`Plugins > Manager`** 18 | 19 | ![14](http://idoc.imagepy.org/demoplugin/31.png) 20 | 21 |
view doc from plugin tree view

22 | -------------------------------------------------------------------------------- /doc/English/filter.md: -------------------------------------------------------------------------------- 1 | # Filter Plugin 2 | 3 | Filter is the most important class of plug-ins, which is used to filter two-dimensional images. And it is also the most basic image processing and the most common applications. 4 | 5 | 6 | 7 | ## Invert 8 | 9 | ```python 10 | from imagepy.core.engine import Filter 11 | 12 | class Invert(Filter): 13 | title = 'Invert Demo' 14 | note = ['all', 'auto_msk', 'auto_snap'] 15 | 16 | def run(self, ips, snap, img, para = None): 17 | return 255-snap 18 | ``` 19 | 20 | Invert plug-in. The ` note ` indicates the plugin supports any type as well as ` roi ` and the undo operation. We return processing results to the ` run `. About ` snap ` and ` img `, the ` img ` is the current image. When ` note ` is added to ` auto_snap ` logo, the framework will help us to copy ` img ` to ` snap ` before ` run `. Because most of the filter need a ` buffer ` for convolution. Moreover the cancellation operation and ` roi ` support must also need the ` snap `. 21 | 22 | ![14](http://idoc.imagepy.org/demoplugin/13.png) 23 | 24 |
Invert

25 | 26 | 27 | 28 | ## Gaussian 29 | 30 | ```python 31 | from imagepy.core.engine import Filter 32 | from scipy.ndimage import gaussian_filter 33 | 34 | class Gaussian(Filter): 35 | title = 'Gaussian Demo' 36 | note = ['all', 'auto_msk', 'auto_snap','preview'] 37 | para = {'sigma':2} 38 | view = [(float, 'sigma', (0,30), 1, 'sigma', 'pix')] 39 | 40 | def run(self, ips, snap, img, para = None): 41 | gaussian_filter(snap, para['sigma'], output=img) 42 | ``` 43 | 44 | Gaussian plug-in. The ` note ` specifies any type support, and supports the ` roi ` as well as cancellation, which provides the preview function. The ` para ` and ` view ` indicate there is a floating point parameters ` sigma `. In ` run `, we can call ` scipy. ndimage. gaussian_filter ` to filter ` snap ` with the output to ` img `. If a function without output item, we will process the results ` return `. And framework will help us to assign a value to ` img `. 45 | 46 | ![14](http://idoc.imagepy.org/demoplugin/14.png) 47 | 48 |
Gaussian

49 | 50 | 51 | 52 | ## Filter operating mechanism 53 | 54 | **note:** 55 | 56 | The note option is a behavior control identifier that controls the flow that the plug-in performs. For example, the framework performs type compatibility checks, and is automatic abortsed if they are not met. Set channel and sequence support settings, and whether to provide preview, roi and other support. 57 | 58 | 1. `all`:The plug-in supports any type 59 | 60 | 2. `8-bit`:The plug-in supports unsigned 8 bits 61 | 62 | 3. `16-bit`:The plug-in supports unsigned 16 bits 63 | 64 | 4. `int`:The plug-in supports 32-bit, 64-bit integers 65 | 66 | 5. `rgb`:The plug-in supports 3 channels, 24 - bit color 67 | 68 | 6. `float`:The plug-in supports 32-bit, 64-bit floating point 69 | 70 | ------ 71 | 72 | 7. `not_channel`:When working with multiple channels, we set to not allow the framework to automatically traverse channels (Each channel is processed in turn by default) 73 | 74 | 8. `not_slice`:When processing image sequences, we set to not ask if you want to batch them (Users are asked by default) 75 | 76 | 9. `req_roi`:Whether there must be roi to handle 77 | 78 | --- 79 | 80 | 10. `auto_snap`:Whether it is needed for the frame to automatically buffer the current image in the processor 81 | 82 | 11. `auto_msk`:Whether roi is automatically supported or not(It must be combined with auto_snap to take effect, and the principle is to use snap to restore pixels other than roi) 83 | 84 | 12. `preview`:Whether preview is supported to adjust parameters to see the results in real time 85 | 86 | 13. `2int`:Whether to convert data lower than int32 to int32 for further processing (For example, to avoid 8-bit operation overflow) 87 | 88 | 14. `2float`:Whether to automatically convert the data lower than float32 to float32 for further processing during processing (some operations require precision) 89 | 90 | **para, view:** Parameter dictionary, see start for details. 91 | 92 | **run:** 93 | 94 | 1. ` ips ` : image wrapper class. The ` filter ` don't need often to operate it. 95 | 2. ` snap ` : when joining the ` auto_snap ` logo in ` note `, framework will copy current image to ` snap ` before ` run ` ( As much as possible to use snap to deal with implementations, the results will be assigned to the img) 96 | 3. ` img ` : current image. We will assign the result to ` img `, or we ` return ` results. The framework assign result to ` img `, and complete refreshing the interface. 97 | 98 | **load:** 99 | 100 | ` def load (self, ips) ` are executed first. If result of the ` return ` is ` False `, plug-in will suspend execution. The default returns ` True `. If necessary, it can be overloaded with a series of condition inspection.If not met, ` IPy. alert ` will pop up prompts, and will return the ` False `. 101 | 102 | **preview:** 103 | 104 | ` def preview (self, ips, para) ` can be executed when selecting preview status. The default will call ` run ` to process current image. If necessary, it can be overloaded. -------------------------------------------------------------------------------- /doc/English/free.md: -------------------------------------------------------------------------------- 1 | # Free plugin 2 | 3 | Free is a plugin that can run independently without any dependencies. We can do anything in it, such as creating images, downloading online resources, and so on. 4 | 5 | 6 | ## Create image 7 | ```python 8 | from imagepy.core.engine import Free 9 | from imagepy import IPy 10 | import numpy as np 11 | 12 | class NewImage(Free): 13 | title = 'New Image Demo' 14 | para = {'name':'new image','w':300, 'h':300} 15 | view = [(str, 'name', 'name',''), 16 | (int, 'w', (1,2048), 0, 'width', 'pix'), 17 | (int, 'h', (1,2048), 0, 'height', 'pix')] 18 | 19 | def run(self, para = None): 20 | imgs = [np.zeros((para['h'], para['w']), dtype=np.uint8)] 21 | IPy.show_img(imgs, para['name']) 22 | ``` 23 | Here we demonstrate this type of plugin through an example (create a new image). Similarly, we can interact with parameters through `para` and `view`. 24 | 25 | ![14](http://idoc.imagepy.org/demoplugin/22.png) 26 | 27 |
New Image

28 | 29 | 30 | ## About dialog box 31 | 32 | ```python 33 | from imagepy.core.engine import Free 34 | from imagepy import IPy 35 | 36 | class About(Free): 37 | title = 'About Demo' 38 | 39 | def run(self, para=None): 40 | IPy.alert('ImagePy v0.2') 41 | ``` 42 | It has been introduced in [Hello World](doc/start.md), and it is used as a dialog-box. 43 | 44 | ![14](http://idoc.imagepy.org/demoplugin/23.png) 45 | 46 |
ImagePy Alert

47 | 48 | 49 | ## Quit 50 | ```python 51 | from imagepy.core.engine import Free 52 | from imagepy import IPy 53 | 54 | class Close(Free): 55 | title = 'Exit Program Demo' 56 | asyn = False 57 | 58 | def run(self, para = None): 59 | IPy.curapp.Close() 60 | ``` 61 | The **quit** is a typical application in the `Free` type plugin. It is worth noticing that if `asyn = False` is added in the plugin, this sign will tell imagepy not to asynchronous execute `run`. Because 'window close' is a `UI` operation and must be done in the main thread. 62 | 63 | 64 | 65 | ## Free operating mechanism 66 | `Free` is the easiest plugin to run compared to other ones, because there is no need for preparation process for `Free`. `run` only has one parameter `para`, obtained through interaction, which is completely open to the developer. 67 | 68 | 69 | **para, view:** 70 | 71 | Parameter dictionary, for specific usage, see [start](doc/start.md). 72 | 73 | **run:** 74 | 75 | Get interactive results and do whatever you want. 76 | 77 | **load:** 78 | 79 | `def load(self, ips)` is executed at first,if the `False` is returned with `return` , the plugin will be ended. Default return is `True`, if neccesary, it can be overloaded for a series of condition checks. If it is not satisfied, the `IPy.alert` will popup prompt, and return`False` 80 | 81 | 82 | -------------------------------------------------------------------------------- /doc/English/macros.md: -------------------------------------------------------------------------------- 1 | # Macros Plugin 2 | 3 | Macros are a series of command records that can be used to repeat operations, instead of writing our own commands, we use a macro recorder to do the recording. Macro recorder in **`Plugins > Macros> Macros Recorder`**. We save the recorded commands to one of the menus or its subfolders, the MC suffix, and reboot to get them corresponding position. 4 | 5 | ![14](http://idoc.imagepy.org/demoplugin/08.png) 6 | 7 |
Macros Recorder

8 | 9 | **About The Loading Way Of Plugin** 10 | 11 | 1. The mc suffix file under the menus and its subfolders is resolved to a macro. 12 | 2. You can also drag and drop macro files into the status bar at the bottom of the ImagePy for execution. 13 | 14 | ## Gaussian Blur Then Invert 15 | 16 | ```python 17 | Gaussian>{'sigma': 2} 18 | Invert>None 19 | ``` 20 | 21 | These are two commands, Click and then perform the Gaussian and Invert. 22 | 23 | ![14](http://idoc.imagepy.org/demoplugin/09.png) 24 | 25 |
Gaussian And Invert

26 | 27 | 1. Macros are structured in this way of `name of Plugin>Parameters of the dictionary` 28 | 2. If no arguments using `None` placeholder. 29 | 3. If a parameter-needed command is given to `None`, ImagePy will pop up the parameter dialog box for interaction. 30 | 31 | ## Coins Segmentation 32 | 33 | ```python 34 | coins>None 35 | Up And Down Watershed>{'thr1': 36, 'thr2': 169, 'type': 'up area'} 36 | Fill Holes>None 37 | Geometry Filter>{'con': '4-connect', 'inv': False, 'area': 100.0, 'l': 0.0, 'holes': 0, 'solid': 0.0, 'e': 0.0, 'front': 255, 'back': 0} 38 | Geometry Analysis>{'con': '8-connect', 'center': True, 'area': True, 'l': True, 'extent': False, 'cov': True, 'slice': False, 'ed': False, 'holes': False, 'ca': False, 'fa': False, 'solid': False} 39 | ``` 40 | 41 | The above is a process of coin segmentation recorded macro, click will automatically perform coins segmentation, preprocessing, area filtering, area analysis, generate table. (we don't normally record 'open images' to macros, of course) 42 | 43 | ![14](http://idoc.imagepy.org/demoplugin/10.png) 44 | 45 |
Coins Segment Macros

46 | -------------------------------------------------------------------------------- /doc/English/markdown.md: -------------------------------------------------------------------------------- 1 | # Markdown Plugin 2 | 3 | Markdown is a kind of Markup language, easy to read, suitable for writing document, ImagePy has direct support for Markdown, copy the markdown file to one of the menus or its subdirectories, it will be parsed into a menu item the next time it launches, the file name is the menu caption, click and the pop-up window will display the contents of Markdown. 4 | 5 | ## MarkDown Demo 6 | 7 | ```markdown 8 | # Markdown Demo 9 | This is a Mark Down Demo 10 | ``` 11 | ![14](http://idoc.imagepy.org/demoplugin/05.png) 12 | 13 |
MarkDown Demo

14 | -------------------------------------------------------------------------------- /doc/English/menus/Filter Demo/Gaussian Demo.md: -------------------------------------------------------------------------------- 1 | # Gaussian Demo 2 | 3 | **Description:** a gaussian filter to show how to write a filter plugin. 4 | 5 | 6 | ## Parameter 7 | 8 | **sigma:** gaussian core's sigma, bigger sigma make more blur. 9 | 10 | 11 | 12 | ![14](http://idoc.imagepy.org/demoplugin/14.png) 13 | 14 |
Gaussian blur with sigma:5, supporting roi

15 | 16 | -------------------------------------------------------------------------------- /doc/English/menus/Start Here/Hello World.md: -------------------------------------------------------------------------------- 1 | # Hello World 2 | 3 | **Description:** say hello to you. 4 | 5 | ## Parameter 6 | 7 | no parameter -------------------------------------------------------------------------------- /doc/English/menus/Start Here/Who Are You.md: -------------------------------------------------------------------------------- 1 | # Who Are You 2 | 3 | **Description:** ask your name and age 4 | 5 | 6 | ## Parameter 7 | 8 | **name:** your name 9 | 10 | **age:** your age -------------------------------------------------------------------------------- /doc/English/publish.md: -------------------------------------------------------------------------------- 1 | # Plugin Release 2 | 3 | We discussed each plug-in realizing above. Of course, we can create the python scripts to develop a plugin function arbitrarily in ` menus `, ` tools `, ` widgets ` of ImagePy . But when our plugins are more and more, function system is more and more complex, of course we will hope to launch into a plug-in project, which can let other users to installa conveniently . Here we discuss how to publish a plug-in project. 4 | 5 | 6 | 7 | ## Function organization 8 | 9 | **Functional partitioning** 10 | 11 | If our plug-in is not a single function, but a set of very systematic functions. Then we should divide and cluster these functions and organize them with package. For example, all the functionality we wrote earlier can be organized by plug-in type. 12 | 13 | ![14](http://idoc.imagepy.org/demoplugin/28.png) 14 | 15 |
functional partitioning

16 | **Set Order ** 17 | 18 | We see that the functional division of plug-in is more clear, but the plugin is sorted in alphabetical order.We want to specify the order, and it is very easy to implement in ImagePy. We add ` catlog ` fields to the ` __init__.py ` file, and indicate the order with a list object. 19 | 20 | `__init__.py` 21 | 22 | ```python 23 | catlog = ['Start Here', '-', 'Markdown Demo', 'Macros Demo', 'Workflow Demo', '-', 'Filter Demo', 'Simple Demo', 'Table Demo', 'Free Demo', '-', 'WidgetDemo'] 24 | ``` 25 | 26 | Once catlog set well, menu will be loaded in specified order, such as :` '-' ` parses to segment line. The ` catlog ` can appear in any plug-in directory, or you can specify plug-in, or you can also specify the order of the folder, or to play a role to the tools (the other way to set the order is use ` plgs = [...] `to realize multiple plug-ins ,which is introducted before ). 27 | 28 | ![14](http://idoc.imagepy.org/demoplugin/29.png) 29 | 30 |
sort by catlog

31 | 32 | The ` catlog ` can appear in any plug-in directory, or specify a plug-in, or specify the order of the folder, and also play a role to ` tools ` .`widgets`. The ` plgs ` can also specify the order of the plugin for multi plugin file. 33 | 34 | 35 | 36 | ## Plugin project creation 37 | 38 | **Create a plugin project repository** 39 | 40 | If the plug-in is dispersed in ImagePy, the main folder is not easy to manage. So we create a separate plug-in project warehouse, and create ` menus `, ` tools `, ` widgets ` three folders on the top floor of the warehouse, which contain plug-ins with functional division and correct order . 41 | 42 | 43 | 44 | **Write requirements** 45 | 46 | Python's biggest advantage is rich in library. As a plug-in project, it is likely to depend on other libraries. By convention, we need to writte the dependence to ` requirements.txt` (When installing a plug-in, ImagePy automatically calls pip to resolve dependency libraries, temporary support only pip, follow-up we will consider supporting conda) 47 | 48 | 49 | 50 | **Write readme** 51 | 52 | Readme was originally intended for project introduction, but `the first few lines` of readme are used for plug-in management in ImagePy. So the first few lines of readme `need to strictly follow the following specifications`, taking this project as an example: 53 | 54 | ```markdown 55 | # Demo Plugin 56 | 57 | Path: https://github.com/Image-Py/demoplugin 58 | 59 | Version: 0.1 60 | 61 | Author: YXDragon 62 | 63 | Email: yxdragon@imagepy.org 64 | 65 | Keyword: demo, tutorial 66 | 67 | Description: a friendly develop tutorial 68 | 69 | *Feel free to write in the following* 70 | 71 | ``` 72 | 73 | 74 | 75 | **Plugin installation** 76 | 77 | **`Plugins > Install > Install Plugin`** Enter the github link to the plug-in repository in the dialog box, and ImagePy starts downloading the plug-in, solving dependencies, and loading it automatically. After loading successfully, we can see that the menu bar, toolbar and component bar are automatically updated. This way, you can send the address of your plug-in project to someone else and for better installing and using it. 78 | 79 | ![14](http://idoc.imagepy.org/demoplugin/30.png) 80 | 81 |
Plugin installation

82 | 83 | ## Release to ImagePy 84 | 85 | **Send Pull Requestion to ImagePy** 86 | 87 | You can also publish your plug-in project to ImagePy, which is a simple process if you have completed your plug-in project. You only need to ` fork ` a ImagePy, and copy your ` readme ` file to ` ImagePy - menus - Plugins - Contribute - Contributors `. After renamed the plug-in project name (not mandatory, but it is the best that can reflect the plug-in function), you try ImagePy ` Pull Request `. When ImagePy members receive ` Pull Request `, we will ` merge ` your ` Pull Request ` after the test.If any problem ,we will pass ` issue ` to communicate. Once incorporated into the ImagePy main branch, the user can retrieve, or install, or uninstall, and so on through the plug-in manager. 88 | 89 | ![14](http://idoc.imagepy.org/demoplugin/06.png) 90 | 91 |
Plugins Manager

92 | 93 | Plug-in manager will automatically parse ` contributors ` plug-in directory information, thus ` readme ` of plug-in project must be in accordance with the format to write seriously. It will affect the user's search experience if not. If there is update, please modify the version number, a new ` Pull Request `. And plug-in manager will automatically detect updates. 94 | 95 | 96 | 97 | **About the top-level menu** 98 | 99 | We see that after installing the plug-in, the functions in the plug-in project are also loaded into the menu bar, toolbar, and components bar. We can see that the menus, tools, widgets directory in the plug-in project has the same effect as the directory in the main ImagePy project. **if you don't want the Plugin functionality to be on the top menu, you can control it using the folder structure.** For example, if we want to get my menus to appear under the Plugin, we add a folder named Plugin to the menu of my Plugin project. 100 | 101 | After installing plug-in project , project is decompred into `plugins` directory of ImagePy. And ImagePy startup, after parsing main directory, which will parse the plugin directory structure of the project. So that independent management is achieved relatively for the plug-in projects. **As top-level menu space is scarce, please do not use it ,unless it has very rich and systematic functions** -------------------------------------------------------------------------------- /doc/English/report.md: -------------------------------------------------------------------------------- 1 | # Report Plugin 2 | 3 | In many cases, we end up with the results of our analysis in report, generating PDF documents, or printing them. Although now LaTex, Markdown based on the tag language document tools are very powerful, Excel software still has the widest audience,the quickliest start to fit task , the strongest form layout ability. Moreover Excel has powerful data processing, graph generating function. Thus ImagePy selects Excel as reporting features carrier, the user can design their Excel template, and add tags in a particular cell and save, change the suffix to `rpt`, you can get the report plugin of ImagePy . 4 | 5 | 6 | 7 | **How report plugins are loaded** 8 | 9 | 1. The `rpt` suffix file under the menus and its subfolders is resolved into a report template. 10 | 2. You can also drag and drop the template file into the bottom status bar of ImagePy to execute. 11 | 12 | 13 | ## Personal Information 14 | 15 | Use a personal information card to show how to make templates and tag cells. In order to facilitate printing, we need to set the paper size as A5 according to our own situation. Second, for precise layout, we switched the Excel view to the page layout, so that all cell sizes are set in cm. 16 | 17 | ![06](http://idoc.imagepy.org/demoplugin/33.png) 18 | 19 |
personal information template

20 | 21 | --- 22 | 23 | ![06](http://idoc.imagepy.org/demoplugin/34.png) 24 | 25 |
personal information result

26 | 27 | ## Coins Segmentation 28 | 29 | We continue to use the example of coin segmentation and measurement to produce reports of the analysis results. Here, we carefully designed an experiment report, including basic information, processing pictures and result tables. We also made statistics on the results in Excel, and drew a histogram for the area column. 30 | 31 | ![06](http://idoc.imagepy.org/demoplugin/37.png) 32 | 33 |
do coins segment in ImagePy

34 | 35 | ![06](http://idoc.imagepy.org/demoplugin/38.png) 36 | 37 |
generate coins report

38 | 39 | ## Report template design principles 40 | 41 | When executing report plug-in, ImagePy will firstly analyze Excel template, analyze each Work Sheet, detect each cell, extract all variable markers, and interact with users in the form of dialog box. After confirmation, all information will be backfilled and saved. It is very convenient to use, but we must follow certain principles to design the template, which is described in detail here. 42 | 43 | 44 | 45 | *In order to facilitate printing, we need to set the paper size according to our own situation, such as A4, A5. Second, for precise layout, we switched the Excel view to the page layout, so that all cell sizes are set in cm.* 46 | 47 | 48 | 49 | **Universal syntax** 50 | 51 | `{type Var_Name = Default Value # note}`, Variable tags of any type follow this format, with curly braces for variable identifiers and other items. Some items are required and some are optional. 52 | 53 | **Underlying parameter** 54 | 55 | `int,float,str,txt,bool`:these basic parameters, syntax format consistent take STR as an example, `{str Name = YX Dragon # please input your name here}`,where type and variable name are required, default value and comment are optional. The difference between `str` and `txt` is that in the ImagePy interactive dialog, `txt` can receive multiple lines of text. 56 | 57 | **Selection parameter** 58 | 59 | `list`: usage example`{list Favourite_System = [Windows, Linux, Mac] # please select your favourite system}`,for the list, the default value must be provided, the options are separated by commas, the Spaces are ignored, the comments are optional. 60 | 61 | **Image parameter** 62 | 63 | `img`:usage example `{img My_Photo = [4.8,4.8,0.9,0] # you photo here`,for img type, the default value must be provided, it is an brackets, inside four numbers, respectively represents: length (cm), height (cm), white space ratio (0.9 represents 10% around), whether to stretch (0 represents holding ratio, 1 can be stretched), annotation is optional. 64 | 65 | **Table parameter** 66 | 67 | `tab`:usage example `{tab Record = [1,3,0,0] # the result table}`,for tab type, a default value must be provided in a bracket, incleded four numbers respectively: spacing (1 represents not merged cells), column spacing (1 represents not merged cells), the header row relative position (1 represents the data area on a line, 0 represents don't fill the title), indexed column line of position (-1 represents a left column of the data area ,0 represents no filling index), the annotation is optional. -------------------------------------------------------------------------------- /doc/English/simple.md: -------------------------------------------------------------------------------- 1 | # Simple 2 | 3 | Simple is another important addition to Filter. The difference is that Simple does not focus on single images, but treats image sequences as a whole for 3d processing. In addition, Simple is also used to manipulate relevant attributes outside of images, such as ROI, color index table, scale and unit, or image Mark. 4 | 5 | 6 | 7 | ## Gaussian3D 8 | 9 | ```python 10 | from imagepy.core.engine import Simple 11 | import scipy.ndimage as ndimg 12 | 13 | class Gaussian3D(Simple): 14 | title = 'Gaussian 3D Demo' 15 | note = ['all', 'stack3d'] 16 | 17 | para = {'sigma':2} 18 | view = [(float, 'sigma', (0,30), 1, 'sigma', 'pix')] 19 | 20 | def run(self, ips, imgs, para = None): 21 | imgs[:] = ndimg.gaussian_filter(imgs, para['sigma']) 22 | ``` 23 | 24 | `stack3d` in `note` identity is refers to the plug-in processing a continuous image stack. And `run` function can get image sequence of ` ndarray ` object by `imgs`, We carries on the three-dimensional gaussian filter, assign the result to ` imgs `. 25 | 26 | Image sequence of ImagePy include `stack2d`, `stack3d`. And ` stack2d ` image sequence is based on ` list`. It is easy to increase or delete `slice`. While `stack3d` is a continuous ` numpy ` array, and facilitate three-dimensional filter to direvtly analyze. We can tansform them through the `Image > Type > Trans to stack/list` . 27 | 28 | *the 2d gaussian based on Gaussian Filter can also process sequences, but the processing method is to treat each slice one by one, while the 3d based on Gaussian Filter also convolves in the z direction.* 29 | 30 | 31 | 32 | ## SetLUT 33 | 34 | ```python 35 | from imagepy.core.engine import Simple 36 | import numpy as np 37 | 38 | class SetLUT(Simple): 39 | title = 'Set LUT Demo' 40 | note = ['all'] 41 | para = {'lut':'red'} 42 | view = [(list, 'lut', ['red', 'green', 'blue'], str, 'look up', 'table')] 43 | 44 | def run(self, ips, imgs, para = None): 45 | cmap = [[i==para['lut']] for i in ['red', 'green', 'blue']] 46 | ips.lut = (cmap*np.arange(256)).astype(np.uint8).T 47 | ``` 48 | 49 | Lookup table is a 255*3 color map that does not change the pixels, only the display of the image. It can be accessed or set via ips.lut. The range is a two element tuple, which sets the dynamic range of image pixels. For 8-bit images, it is usually (0, 255), but for float types, the range setting is very meaningful. In fact, when displaying, ImagePy first carries out clip on the image according to the range and scales it to 0-255, and then applies the lookup table. 50 | ![14](http://idoc.imagepy.org/demoplugin/15.png) 51 | 52 |
SetLUT

53 | 54 | 55 | ## Inflate ROI 56 | 57 | ```python 58 | from imagepy.core.engine import Simple 59 | 60 | class Inflate(Simple): 61 | title = 'Inflate ROI Demo' 62 | note = ['all', 'req_roi'] 63 | para = {'r':5} 64 | view = [(int, 'r', (1,100),0, 'radius', 'pix')] 65 | 66 | def run(self, ips, imgs, para = None): 67 | ips.roi = ips.roi.buffer(para['r']) 68 | ``` 69 | 70 | ` ROI ` indicate what areas we care about, the `ROI` of ImagePy based on `Shapely` object. We can operate on the `ROI`, the above is to inflate the current ` ROI ` example. 71 | 72 | ![14](http://idoc.imagepy.org/demoplugin/16.png) 73 | 74 |
Inflate ROI

75 | 76 | ## Set Scale And Unit 77 | 78 | ```python 79 | from imagepy.core.engine import Simple 80 | 81 | class Unit(Simple): 82 | title = 'Scale And Unit Demo' 83 | note = ['all'] 84 | para = {'scale':1, 'unit':'mm'} 85 | view = [(float, 'scale', (1e-3,1e3), 3, 'scale', ''), 86 | (str, 'unit', 'scale', '')] 87 | 88 | def run(self, ips, imgs, para = None): 89 | ips.unit = (para['scale'], para['unit']) 90 | ``` 91 | 92 | It is in pixels unit to everything in the default ImagePy measurement and analysis results, but we can get and set it though `ips.unit`. 93 | 94 | ![14](http://idoc.imagepy.org/demoplugin/17.png) 95 | 96 |
Set Scale And Unit

97 | 98 | ## Mark 99 | 100 | ```python 101 | from imagepy.core.engine import Simple 102 | from imagepy.core.mark import GeometryMark 103 | import numpy as np 104 | 105 | class Mark(Simple): 106 | title = 'Random Points Demo' 107 | note = ['all'] 108 | 109 | def run(self, ips, imgs, para = None): 110 | pts = (np.random.rand(200)*512).reshape((100,2)) 111 | ips.mark = GeometryMark({'type':'points', 'color':(255,0,0), 'lw':1, 'body':pts}) 112 | ``` 113 | 114 | ` mark ` is covering on the image, the image itself does not change. ImagePy defines a set of geometric data results for drawing ` mark `, here is a brief introduction: 115 | ![14](http://idoc.imagepy.org/demoplugin/18.png) 116 | 117 |
Set Random Point Mark

118 | 119 | 120 | **Various Mark types and usages** 121 | 122 | **point:** 123 | 124 | ```python 125 | {'type':'point', 'color':(r,g,b), 'lw':1, 'body':(x,y)} 126 | ``` 127 | 128 | **points:** 129 | 130 | ```python 131 | {'type':'points', 'color':(r,g,b), 'lw':1, 'body':[(x1,y1), (x2,y2), ...]} 132 | ``` 133 | 134 | **line:** 135 | ```python 136 | {'type':'line', 'color':(r,g,b), 'lw':1, 'style':'-', 'body':[(x1,y1), (x2,y2), ...]} 137 | ``` 138 | 139 | **lines:** 140 | ```python 141 | {'type':'lines', 'color':(r,g,b), 'lw':1, 'style':'-', 'body':[[(x1,y1), (x2,y2), ...], [...]]} 142 | ``` 143 | 144 | **polygon:** 145 | ```python 146 | {'type':'polygon', 'color':(r,g,b), 'fcolor':(r,g,b), 'lw':1, 'style':'o', 'body':[(x1,y1), (x2,y2), ...]} 147 | ``` 148 | 149 | **polygons:** 150 | ```python 151 | {'type':'polygons', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'lw':1, 'style':'o', 'body':[[(x1,y1), (x2,y2), ...], [...]]} 152 | ``` 153 | 154 | **circle:** 155 | ```python 156 | {'type':'circle', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':(x,y,r)} 157 | ``` 158 | 159 | **circles:** 160 | ```python 161 | {'type':'circles', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':[(x1,y1,r1), (x2,y2,r2)]} 162 | ``` 163 | 164 | **ellipse:** 165 | ```python 166 | {'type':'ellipse', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':(x,y,l1,l2,ori)} 167 | ``` 168 | 169 | **ellipses:** 170 | ```python 171 | {'type':'ellipses', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':[(x1,y1,a1,b1,ori1), (x2,y2,a2,b2,ori2), ...]} 172 | ``` 173 | **rectangle:** 174 | ```python 175 | {'type':'rectangle', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':True, 'body':(x,y,w,h)} 176 | ``` 177 | 178 | **rectangles:** 179 | ```python 180 | {'type':'rectangles', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':[(x1,y1,w1,h1),(x2,y2,w2,h2),...]} 181 | ``` 182 | 183 | **text:** 184 | ```python 185 | {'type':'text', 'color':(r,g,b), 'fcolor':(r,g,b), 'size':8, 'pt':True, 'body':(x,y,txt)} 186 | ``` 187 | 188 | **texts:** 189 | ```python 190 | {'type':'texts', 'color':(r,g,b), 'fcolor':(r,g,b), 'size':8, 'pt':True, 'body':[(x1,y1,txt1),(x2,y2,txt2)]} 191 | ``` 192 | 193 | --- 194 | 195 | **layer:** 196 | ```python 197 | {'type':'layer', 'num':-1, 'clolor':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':[sequence of basic element]} 198 | ``` 199 | 200 | **layers:** 201 | ```python 202 | {'type':'layers', 'num':-1, 'clolor':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':{1:layer1, 2:layer2, ...}} 203 | ``` 204 | 205 | 206 | 207 | **The above basic elements are similar in form. The meaning of each parameter is explained here:** 208 | 209 | **type:** element type 210 | 211 | **color:** colour 212 | 213 | **fcolor:** Fill color (only plane elements) 214 | 215 | **fill:** Whether to fill (only plane elements) 216 | 217 | **lw:** Line width 218 | 219 | **style:** Line style, with '-o' for both line and node drawn, or you can choose to draw only line or node, or neither 220 | 221 | **size:** Text height (text only) 222 | 223 | **body:** Geometric data, depending on the type 224 | 225 | 226 | 227 | **Point collection** 228 | 229 | **layer:** ` layer ` can specify ` color `, ` fcolor `, ` fill `, which is different from ` body ` .Because ` body ` of ` layer` deposit is the of other basis elements, actually the above all sorts of elements.In addition to ` type `, ` body ` ,other attributes are not necessary.If the current element is not specified, it will be taken from its ` layer `.If there is no subordinate ` layer `, or ` layer ` is not specified, the default value will be used. 230 | 231 | **layers:** ` layers ` is a set of more advanced elements than ` layer `. ` body ` of ` layers ` is a dictionary, whose key is a layer of int. And in the image sequence, only paint layer number corresponding ` layer `, so that we can realize each image of the image sequence a corresponding ` mark `. 232 | 233 | 234 | ## Simple operating mechanism 235 | 236 | **note:** 237 | 238 | ` note ` option is behavior control indicators, which is used to control the plug-in implementation process. Such as allowing framework compatible with the types of tests, if does not meet, it can be automatical suspensed. ` note ` option include set channel and sequence support settings, and whether to provide preview, ROI and other support. 239 | 240 | 1. `all`:Plug-ins support any type 241 | 242 | 2. `8-bit`:The plug-in supports unsigned 8 bits 243 | 244 | 3. `16-bit`:The plug-in supports unsigned 16 bits 245 | 246 | 4. `int`:The plug-in supports 32-bit, 64-bit integers 247 | 248 | 5. `rgb`:Plug-ins support 3 channels 24 - bit color 249 | 250 | 6. `float`:The plug-in supports 32-bit, 64-bit floating point 251 | 252 | --- 253 | 254 | 7. `req_roi`:Whether there must be ROI to handle 255 | 256 | 8. `stack`:The requirement must be a sequence of images 257 | 258 | 9. `stack2d`:It has to be a list of discrete images(list) 259 | 260 | 10. `stack3d`:It has to be a continuous sequence of images.(ndarray) 261 | 262 | 11. `preview`:Whether to display preview option 263 | 264 | 265 | 266 | **para, view:** 267 | 268 | Parameter dictionary, see Start for details. 269 | 270 | **run:** 271 | 272 | 1. ` ips ` : image wrapper class, we can operate through ` ips ` ,` ROI `, ` mark `, ` lut `, ` range `, ` unit `, etc 273 | 2. ` imgs ` : image sequence, carrying on the operation, such as three-dimensional filter, or analysis, can show the results in table form. 274 | 275 | **load:** 276 | 277 | ` def load (self, ips) ` are executed first, if ` return ` results for ` False `, plug-in will suspend execution. The default return ` True `,.If necessary, it can be overloaded and design a series of condition inspection.If not meet, ` IPy. Alert ` pop-up prompts, and returns the ` False `. 278 | 279 | **preview:** 280 | 281 | ` def preview (self, ips, para) ` Simple defines the ` preview ` option , but the default is to do nothing.Because it often requires a long operation time for the three dimensional filtering operation, therefore it is not suitable for ` preview ` .It can be overloaded, if necessary. -------------------------------------------------------------------------------- /doc/English/start.md: -------------------------------------------------------------------------------- 1 | # Start Here 2 | 3 | We'll start with the Hello World example, which provides an introduction to the plug-in's loading mechanism and how to configure the parameters dialog for future development. 4 | 5 | 6 | 7 | ## What is plugin 8 | 9 | ImagePy is a highly extensible image processing framework. We extend the functions of ImagePy through plug-ins. A plug-in is a piece of code or a file that is placed in a specific location and automatically loaded when ImagePy is launched. ImagePy native function does not enjoy any privileges in functions of ImagePy - actually. Plug-in is resolved into corresponding UI elements according to these plug-ins directory hierarchy. And we trigger it when click on the corresponding menu or tool. We can use the `Plugins > Manager > Plugin Tree View` to view the plug-in and its corresponding source code. 10 | 11 | ![31](http://idoc.imagepy.org/demoplugin/31.png) 12 |
Plugins Tree View

13 | 14 | 15 | 16 | ## Hello World 17 | 18 | Let's start writing our first plug-in to implement a simple Hello World. 19 | 20 | ```python 21 | from imagepy.core.engine import Free 22 | from imagepy import IPy 23 | 24 | class Plugin(Free): 25 | title = 'Hello World' 26 | 27 | def run(self, para=None): 28 | IPy.alert('Hello World, I am ImagePy!') 29 | ``` 30 | This is one of the most simple plug-in, first `import Free, IPy `. Here `Free` is a plug-in type. This type of plug-in does not depend on anything. In `run`, we use `IPy.alert` to pop up a 'Hello world, I am ImagePy!' message box. 31 | ![14](http://idoc.imagepy.org/demoplugin/01.png) 32 | 33 |
Hello World

34 | 35 | **How is plugin loaded** 36 | We rename the script file as `hello_plg.py` above, and copy to ` imagepy > menus > Plugins ` directory in ImagePy. We restart ImagePy, and click ` Plugins ` menu, then you will see our Hello World plug-in. Some loading principles are as follows: 37 | 38 | 1. `menus` and its subdirectories will be resolved. 39 | 2. files end with `plg.py` will be resolved. 40 | 3. ` Plugins ` class in the files will be resolved as a plug-in, ` title ` is menu's caption. 41 | 42 | 43 | 44 | ## Who Are You 45 | 46 | Next we add some parameters to the plug-in, inviting the user to enter a name and age. 47 | 48 | ```python 49 | from imagepy.core.engine import Free 50 | from imagepy import IPy 51 | 52 | class Plugin(Free): 53 | title = 'Who Are You' 54 | para = {'name':'', 'age':0} 55 | view = [(str, 'name', 'name', 'please'), 56 | (int, 'age', (0,120), 0, 'age', 'years old')] 57 | 58 | def run(self, para=None): 59 | IPy.alert('Name:\t%s\r\nAge:\t%d'%(para['name'], para['age'])) 60 | ``` 61 | 62 | ImagePy framework implements the parameter dialog generation mechanism, which can generate the corresponding interaction according to `para`, `view`. After completion of interactions, we can get a result of the `para` parameters for interaction in the ` run ` function. In the next example ,we will make more detailed interpretation of the various types of parameters. 63 | 64 | ![14](http://idoc.imagepy.org/demoplugin/02.png) 65 |
Who Are You

66 | 67 | 68 | 69 | ## Questionnaire 70 | 71 | ```python 72 | from imagepy.core.engine import Free 73 | from imagepy import IPy 74 | 75 | class Plugin(Free): 76 | title = 'Questionnaire' 77 | 78 | para = {'name':'yxdragon', 'age':10, 'h':1.72, 'w':70, 'sport':True, 'sys':'Mac', 'lan':['C/C++', 'Python'], 'c':(255,0,0)} 79 | 80 | view = [('lab', 'lab', 'This is a questionnaire'), 81 | (str, 'name', 'name', 'please'), 82 | (int, 'age', (0,150), 0, 'age', 'years old'), 83 | (float, 'h', (0.3, 2.5), 2, 'height', 'm'), 84 | ('slide', 'w', (1, 150), 0, 'kg'), 85 | (bool, 'sport', 'do you like sport'), 86 | (list, 'sys', ['Windows','Mac','Linux'], str, 'favourite', 'system'), 87 | ('chos', 'lan', ['C/C++','Java','Python'], 'lanuage you like(multi)'), 88 | ('color', 'c', 'which', 'you like')] 89 | 90 | def run(self, para=None): 91 | rst = ['Questionnaire Result', 92 | 'Name:%s'%para['name'], 93 | 'Age:%s'%para['age'], 94 | 'Height:%sm'%para['h'], 95 | 'Weight:%skg'%para['w'], 96 | 'Like Sport:%s'%para['sport'], 97 | 'Favourite System:%s'%para['sys'], 98 | 'Like lanuage:%s'%para['lan'], 99 | 'Favourite Color:%s'%str(para['c'])] 100 | 101 | IPy.alert('\r\n'.join(rst)) 102 | ``` 103 | Here we implement a questionnaire, which allow the user to input all kinds of information and to show the developer how to use `para`, `view` to configure parameter dialog that they want . 104 | 105 | 106 | ![14](http://idoc.imagepy.org/demoplugin/03.png) 107 |
Questionnaire

108 | 109 | **label:** para type:`no parameters required`, view usage:`('lab', 'lab', 'what you want to show')` 110 | 111 | **str:** para type:`str`, view usage:`(str, key, prefix, suffix)`, the ` key ` is correspond with ` key ` of ` para ` . ` prefix ` and ` suffix ` is used as tips content before and after the input box. 112 | 113 | **int:** para type:`int`,view usage:`(int, key, (lim1, lim2), accu, 'prefix', 'suffix')`,the ` key ` is correspond with ` key ` of ` para ` .` limit ` used to limit the range of input value,`accu` limits the number of decimal places (0).` prefix ` and ` suffix ` are used as tips content before and after the input box. 114 | 115 | **float:** para type:`float`,view usage:`(int, key, (lim1, lim2), accu, 'prefix', 'suffix')`,the ` key ` is correspond with ` key ` of ` para ` .` limit ` used to limit the range of input value,`accu` limits the number of decimal places (0).` prefix ` and ` suffix ` are used as tips content before and after the input box. 116 | 117 | **slider:** para type:`int/float`,view usage:`('slide', key, (lim1, lim2), accu, 'prefix')`,the ` key ` is correspond with ` key ` of ` para ` .` limit ` used to limit the range of input value,`accu` limits the number of decimal places (0). ` prefix ` is used as tips content before and after the input box. 118 | 119 | **bool:** para type:`bool`,view usage:`(bool, 'key', 'label')`,the ` key ` is correspond with ` key ` of ` para ` .`label` is used as a hint. 120 | 121 | **list:** para type:`any type`,view usage:`(list, key, [choices], type, prefix, suffix)`,the ` key ` is correspond with ` key ` of ` para ` .`choices` is a character option, `type` is the expected output type, such as `str`, `int`. ` prefix ` and ` suffix ` are used as tips content before and after the input box. 122 | 123 | **choices:** para type:`str list`,view usage:`('chos', key, [choices], prefix, suffix)`,Similar to `list`, the difference is that `choices` can support multiple selections, and the options are recorded in the form of `list of string`. 124 | 125 | **color:** para type:`(r,g,b) 0-255`, usage:`('color', key, prefix, suffix)`,the ` key ` is correspond with ` key ` of ` para ` .` prefix ` and ` suffix ` are used as tips content before and after the input box. 126 | 127 | 128 | 129 | *In addition to the basic data types above, ImagePy also supports some parameters of internal types, such as receiving an image, receiving a table, or making single or multiple selections of the fields of the table, which we will show in later example* 130 | 131 | 132 | 133 | ## Implement multi-plugins in one file 134 | We implemented three plug-ins above. And Python has the advantage of being syntax-efficient, so we can implement multiple plug-ins in one file, as follows. 135 | 136 | ```python 137 | from imagepy.core.engine import Free 138 | from imagepy import IPy 139 | 140 | class HelloWorld(Free): 141 | title = 'Hello World' 142 | ... 143 | 144 | class WhoAreYou(Free): 145 | title = 'Who Are You' 146 | ... 147 | 148 | class Questionnaire(Free): 149 | title = 'Questionnaire' 150 | ... 151 | 152 | plgs = [HelloWorld, WhoAreYou, Questionnaire] 153 | ``` 154 | 155 | We will write three classes in a file, then add `plgs = []`, file named `start_plgs.py`. The framework loading principle is as follows: 156 | 157 | 1. files in the ` menus ` directory or subdirectory, end with `plgs.py` will be resolved as multi plug-in. 158 | 2. `plgs` list in the file will be resolved one by one 159 | 3. `'-'` in ` plgs` will be resolved as a menu separator 160 | 161 | ![14](http://idoc.imagepy.org/demoplugin/04.png) 162 | 163 |
resolved as menus

164 | 165 | -------------------------------------------------------------------------------- /doc/English/table.md: -------------------------------------------------------------------------------- 1 | # Table Plugin 2 | 3 | Table is another very important data type besides image. In a sense, the results of scientific image analysis will eventually end up in table data. ImagePy havs very good support to table type data, whose core data structure is `pandas.DataFrame`. 4 | 5 | 6 | 7 | ## Generate score list 8 | 9 | ```python 10 | from imagepy.core.engine import Free 11 | from imagepy import IPy 12 | import numpy as np 13 | import pandas as pd 14 | 15 | class Score(Free): 16 | title = 'Student Score' 17 | 18 | def run(self, para=None): 19 | index = ['Stutent%s'%i for i in range(1,6)] 20 | columns = ['Math', 'Physics', 'Biology', 'History'] 21 | score = (np.random.rand(20)*40+60).reshape((5,4)).astype(np.uint8) 22 | IPy.show_table(pd.DataFrame(score, index, columns), 'Scores') 23 | ``` 24 | 25 | We generated table through a ` Free ` plug-in. Table is a `pandas.DataFrame` object, which is displayed by `IPy. show_table(df, title)` . 26 | 27 | ![14](http://idoc.imagepy.org/demoplugin/19.png) 28 | 29 |
generate score list

30 | 31 | 32 | ## Sort by field 33 | 34 | ```python 35 | from imagepy.core.engine import Table 36 | 37 | class Sort(Table): 38 | title = 'Table Sort Demo' 39 | 40 | para = {'by':'Math'} 41 | view = [('field', 'by', 'item', '')] 42 | 43 | def run(self, tps, data, snap, para=None): 44 | tps.data.sort_values(by=para['by'], inplace=True) 45 | ``` 46 | 47 | Here is the help of a new argument types, ` field `, and the base parameter type is a radio type, which don't need us to provide options and get automatically from the current form of ` columns `. `run` directly change ` DataFrame ` itself by ` inplace ` parameters. Some operations can not modify itself, please return the result. 48 | 49 | ![14](http://idoc.imagepy.org/demoplugin/20.png) 50 | 51 |
sort by math

52 | 53 | 54 | ## Bar Chart 55 | 56 | ```python 57 | class Bar(Table): 58 | title = 'Score Chart Demo' 59 | asyn = False 60 | 61 | para = {'item':[]} 62 | view = [('fields', 'item', 'select items')] 63 | 64 | def run(self, tps, data, snap, para = None): 65 | data[para['item']].plot.bar(stacked=True, grid=True, title='Score Chart') 66 | plt.show() 67 | ``` 68 | 69 | Here is a new argument types, ` fields `, and the parameter type is actually a multiple-choice type, which don't need us to provide options and get automatically from the current form of ` columns `. When the table is selected some columns in the interface, the corresponding items are also checked by default in the parameters dialog box. Pandas bring our own drawing functions, but it is worth mentioning that the plug-in joined ` asyn = False `, which tells ImagePy not to enable asynchronous execution ` run `. Because this plug-in involved in ` UI `, and it must be conducted in the main thread. 70 | 71 | 72 | ![14](http://idoc.imagepy.org/demoplugin/21.png) 73 | 74 |
bar chart

75 | 76 | ## Table operation mechanism 77 | 78 | **note:** 79 | 80 | ` note ` option is behavior control indicators, which is used to control the plug-in implementation process. Such as allowing framework to be compatible with the types of tests, if not meet ,the automatic suspension will happen.And it is different from the Filter and simple ` note ` . 81 | 82 | 1. `req_sel`: It needs selection district 83 | 84 | 2. `req_row`: It needs to select the row 85 | 86 | 3. `req_col`: It needs to select the column 87 | 88 | 4. `auto_snap`: The framework automatically buffers the data before processing 89 | 90 | 5. `row_msk`: In snap , it only buffers the selected rows 91 | 92 | 6. `col_msk`: In snap , it only buffers the selected columns 93 | 94 | 7. `num_only`: In snap , it only buffers numeric value columns 95 | 96 | 8. `preview`: Whether to display preview option 97 | 98 | 99 | 100 | **para, view:** 101 | 102 | Parameter dictionary, see start for details. 103 | 104 | **run:** 105 | 106 | 1. `tps` : table wrapper class. We can visit or operate ` rowmsk ` and ` colmsk ` by ` tps ` 107 | 2. ` snap ` : the buffer of table.If there is a ` auto_snap ` logo, it can take effect. 108 | 3. ` data ` : current table can be operation. 109 | 110 | **load:** 111 | 112 | ` def load (self, tps):` are executed first. If return ` False `, plug-in will suspend execution. The default return ` True `. If necessary, which can be overloaded to add a series of condition inspection. If not meet, `IPy.alert` pops up prompts, and returns the ` False `. 113 | 114 | **preview:** 115 | 116 | `def preview (self, tps, para)` will automatically perform ` run ` and update by default , which can be overloaded in need . -------------------------------------------------------------------------------- /doc/English/tool.md: -------------------------------------------------------------------------------- 1 | # Tool Plug-in 2 | 3 | The Tool plug-in is used to complete mouse interaction and is loaded as icons on the toolbar at startup. Typical tool plug-ins are ROI editing, brushes, measuring tools, etc. 4 | 5 | 6 | 7 | ## Brush Tool 8 | 9 | ```python 10 | from imagepy.core.engine import Tool 11 | from skimage.draw import line, circle 12 | 13 | def drawline(img, oldp, newp, w, value): 14 | if img.ndim == 2: value = sum(value)/3 15 | oy, ox = line(*[int(round(i)) for i in oldp+newp]) 16 | cy, cx = circle(0, 0, w/2+1e-6) 17 | ys = (oy.reshape((-1,1))+cy).clip(0, img.shape[0]-1) 18 | xs = (ox.reshape((-1,1))+cx).clip(0, img.shape[1]-1) 19 | img[ys.ravel(), xs.ravel()] = value 20 | 21 | class Plugin(Tool): 22 | title = 'Pencil' 23 | 24 | para = {'width':1, 'value':(255, 255, 255)} 25 | view = [(int, 'width', (0,30), 0, 'width', 'pix'), 26 | ('color', 'value', 'color', '')] 27 | 28 | def __init__(self): 29 | self.status = False 30 | self.oldp = (0,0) 31 | 32 | def mouse_down(self, ips, x, y, btn, **key): 33 | self.status = True 34 | self.oldp = (y, x) 35 | ips.snapshot() 36 | 37 | def mouse_up(self, ips, x, y, btn, **key): 38 | self.status = False 39 | 40 | def mouse_move(self, ips, x, y, btn, **key): 41 | if not self.status:return 42 | w, value = self.para['width'], self.para['value'] 43 | drawline(ips.img, self.oldp, (y, x), w, value) 44 | self.oldp = (y, x) 45 | ips.update() 46 | 47 | def mouse_wheel(self, ips, x, y, d, **key):pass 48 | ``` 49 | 50 | By overloading ` mouse_down `, ` mouse_up `, ` mouse_move ` method, we can realize the mouse interaction. Here, we implement one of the most common brush tool. When the mouse is pressed, tag ` status` will be ` True `, with drawing in the process of the mouse movement, and updating the display. 51 | 52 | ![14](http://idoc.imagepy.org/demoplugin/24.png) 53 | 54 |
Brush Tool

55 | 56 | 57 | **Tool loading method** 58 | 59 | 1. The file must end up with ` _tol.py ` ,and the class name must be ` Plugin ` (one file can only contain one tool) 60 | 2. The file must be in ` tools ` submenu directory level 61 | 3. It is required for the toolbar icon to have a GIF file , 16*16, with the same name as `tool` 62 | 4. Click to select and apply to the canvas. If there are `para` and `view` parameters, you can click doublely to configure them. 63 | 64 | 65 | ![14](http://idoc.imagepy.org/demoplugin/25.png) 66 | 67 |
Tool loading

68 | 69 | ## Tool operating mechanism 70 | 71 | **title:** title 72 | 73 | **mouse_down:** ` mouse_down (self, ips, x, y, btn ** key): `Mouse pressed cause to the trigger.` ips` is ` ImagePlus ` wrapper class. We can get the current image by the` ips.img `. And we can sequencely get the unit, image indexing table, ROI and additional information on scale and unit corresponding by the ` ips.lut ` , the ` ips.roi `, and the ` ips.unit `. The x, y is the current mouse position under the data coordinate system.The ` btn ` triggers the mouse button, such as : `0:no`, `1:left`, `2:mid key`, and `3:right`. We can obtain if corresponding function key is pressed or not by the ` key ['alt'] `, the ` key ['ctrl'] `, and the `key ['shift'] `. And ` key['canvas'] ` can get ` canvas ` object of triggering event. 74 | 75 | **mouse_up:** ` mouse_up (self, ips, x, y, btn, ** key) : ` When release pressed mouse, it cause to the trigger.Specific parameters are the same as ` mouse_down `. 76 | 77 | **mouse_move:** ` mouse_up (self, ips, x, y, btn, ** key) : ` When mouse moves, it cause to the trigger. Specific parameters are the same as ` mouse_down `. 78 | 79 | **mouse_wheel:** ` mouse_up (self, ips, x, y, btn, ** key) : ` When the mouse wheel rolls, it cause to the trigger.Specific parameters are the same as ` mouse_down `. 80 | 81 | -------------------------------------------------------------------------------- /doc/English/tools/DemoTool/Pencil Demo.md: -------------------------------------------------------------------------------- 1 | # Pencil Demo 2 | 3 | **Description:** a pencil to show how to write a tool plugin. 4 | 5 | 6 | ## Parameter 7 | 8 | **width:** the pencil's pix width 9 | 10 | **color:** the pencil's color 11 | 12 | 13 | 14 | ![14](http://idoc.imagepy.org/demoplugin/24.png) 15 | 16 |
write ImagePy with width:10, color:red

17 | 18 | -------------------------------------------------------------------------------- /doc/English/widget.md: -------------------------------------------------------------------------------- 1 | # Widget Plugin 2 | 3 | The Widget plugin is loaded as a panel, which is a actually a ui object that inherits from `wx.Panel`, this gives us a lot of free space, but at the cost of not being able to isolate the UI, we must write `wxpython` code directly. For example, the navigation bar on the right side, the eagle eye is extended by the `widget`, and the Macro recorder that I have seen before is also a `widget`. 4 | 5 | ## Widget Demo 6 | 7 | ```python 8 | from imagepy import IPy 9 | import wx 10 | 11 | class Plugin ( wx.Panel ): 12 | title = 'Widget Demo' 13 | def __init__( self, parent ): 14 | wx.Panel.__init__ ( self, parent) 15 | sizer = wx.BoxSizer( wx.VERTICAL ) 16 | self.lable = wx.StaticText( self, wx.ID_ANY, 'This is a widgets demo') 17 | self.lable.Wrap( -1 ) 18 | sizer.Add( self.lable, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) 19 | self.btn_invert = wx.Button( self, wx.ID_ANY, 'Invert curent image') 20 | sizer.Add( self.btn_invert, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) 21 | 22 | self.SetSizer( sizer ) 23 | self.Layout() 24 | self.Fit() 25 | # Connect Events 26 | self.btn_invert.Bind( wx.EVT_BUTTON, self.on_invert) 27 | 28 | def on_invert(self, event): 29 | ips = IPy.get_ips() 30 | if ips is None: return 31 | ips.img[:] = 255-ips.img 32 | ips.update() 33 | ``` 34 | 35 | Since `wxpython` has more content itself, if you need to write your own `widget`, you will inevitably learn systematically about `wxpython`. Here is just a simple example. 36 | 37 | ![14](http://idoc.imagepy.org/demoplugin/27.png) 38 | 39 |
widget

40 | 41 | **widget loading method** 42 | 43 | 1. The file end with `_wgt.py`, the class name must be called `Plugin`, inherited from `wx.Panel`(one file can only implement one widget) 44 | 2. The file can be located in the first level submenu under the `widgets` directory, and will be loaded into the right component bar according to the level when starting. It can also be located under menus or its submenus, which loads the panel as a floating window when the user clicks on the menu. 45 | 46 | ![14](http://idoc.imagepy.org/demoplugin/26.png) 47 | 48 |
Widget Demo

49 | 50 | ## Widget opterating mechanism 51 | 52 | Widgets are essentially a subclass of `wx.Panel`. There must be a `title` field as the plugin name. Others are `wxpython` programming. By writing the `UI` and adding events, we don't discuss it in detail here. 53 | -------------------------------------------------------------------------------- /doc/English/workflow.md: -------------------------------------------------------------------------------- 1 | # Workflow Plugin 2 | 3 | Macros is a series of command record executed in order, but Workflow is a mix of Macros and Markdown, the same preocess is specified, but Macros does not automatically execute, each step can be adjusted by the user, even some processes can be added or skipped during the process. In addition, each process developer can set the prompt information, Macro is an automated process, but the Workflow is a guide, which reduces the degree of automation, but is more instructive. 4 | 5 | 6 | ## Coins Segmentation Workflow 7 | 8 | ```markdown 9 | Coins Segment Workflow Demo 10 | =========================== 11 | ## Open Image 12 | 1. coins 13 | open the coins demo image,we will segment and measure it. 14 | ## Segment 15 | 1. Up And Down Watershed 16 | check "preview", slide to mark every coins red more or less, mark background green more or less, use "up area". 17 | ## Repair the mask 18 | 1. Fill Holes 19 | Fill the holes in the conis. 20 | 2. Geometry Filter 21 | check "preview", give "area" 100, small fragment less than 100 become dark, then give "back color" 0 to clear them. 22 | ## Measure 23 | 1. Geometry Analysis 24 | check the indecate we need, here check the "cov", count the cov ellipse. 25 | ## Export Result 26 | 1. CSV Save 27 | save the measure result as a csv file. 28 | ``` 29 | 30 | ![14](http://idoc.imagepy.org/demoplugin/11.png) 31 | 32 |
Workflow

33 | 34 | Write a Workflow based on the previous Coin Segmentation Macro, follow the markdown specification, add the necessary notes and chapters, suffix is wf, save to menus or its subfolders, it will be a horizontal block panel when loading, divided into different chapters, click from left to right. Mouse over each section will display the corresponding prompt information, click on the top right to view the entire process 35 | 36 | ![14](http://idoc.imagepy.org/demoplugin/12.png) 37 | 38 |
Workflow Demo

39 | 40 | **Workflow writing and loading** 41 | 42 | 1. The `workflow` is a markdown file with the suffix `wf` 43 | 2. The `first two lines` are the main title, parsed into the main title of the panel. 44 | 3. The `second-level` heading represents a chapter, which is a function block that resolves to a rectangular panel. 45 | 4. The `number` is the command to be executed, starting with a numeric serial number, without parameters, parsing into a button. 46 | 5. A line of `comments` can be added below each command. When the user mouse moves over a button, the corresponding description will be displayed. 47 | 6. Can be copied to `menus` or its submenus, resolved into menu items at startup. 48 | 7. You can also drag and drop to the status bar at the bottom of ImagePy to load the `workflow`. 49 | -------------------------------------------------------------------------------- /doc/chinese/attention.md: -------------------------------------------------------------------------------- 1 | # 注意事项 2 | 虽然细节未能详尽,但我们大致介绍了插件的开发,发布,文档编写。这里提出一些开发过程中的注意事项。 3 | 4 | 5 | 6 | ## 用户友好性 7 | 8 | 如果是自己用则可以无需过多花费精力,但希望其他用户可以使用自己的插件,那么用户友好性是非常重要的,这包括: 9 | 10 | 1. **合理的功能组织** 11 | 12 | 将功能合理的划分,并用合适的标题展示。 13 | 14 | 2. **合理的交互方式** 15 | 16 | 如插件的参数暴露能具有一定通用性但又不至于杂乱,工具的使用方式符合使用习惯。 17 | 18 | 3. **言简意赅的文档** 19 | 20 | 如果有精力,最好为插件编写操作手册,有必要可以图文并茂。 21 | 22 | 4. **尽可能优化的性能体验** 23 | 24 | 当然这一点是永无止境的,并且主要取决于算法,固然越快越好,等待总是糟糕的。 25 | 26 | 27 | 28 | ## 开发者友好性 29 | 30 | **ImagePy将开发者友好性放在与用户友好性等同的地位**,因为开发者与用户本是一个教学相长的群体,并且两者之间界线模糊,可以互相转化,这里介绍几个ImagePy的开发理念。 31 | 32 | 1. **ImagePy不是算法库,只是连接器** 33 | 34 | ImagePy不做算法,只提供必要的展示与交互,致力于让算法开发者用最少的代码将算法进行配置,整合到ImagePy,将算法转化为工具,给其他人甚至是非程序员使用。 35 | 36 | 2. **尽可能隔离UI** 37 | 38 | UI对于科研程序员总是不愉快的,ImagePy尽最大努力隔绝UI,多数的配置功能都可以通过`para`,`view`的配置来完成参数对话框的生成,而`tool`也抽象为`mouse_down`, `mouse_up`, `mouse_move`, `mouse_wheel`四个接口实现。而一些定制化很强的功能,不得不借助`widget`,只有这时才需要开发者自己编写UI相关的代码。 39 | 40 | 3. **以算法本身为核心** 41 | 42 | ImagePy的图像数据基于`Numpy`,表格数据基于`Pandas`,矢量数据基于`Shapely`,这些都是通用数据结构,相当于Python科学计算的标准,ImagePy作为算法连通器,固然只能支持,而不能干涉算法的编写。因而开发者*切不可将核心算法在`run`函数中实现*,这样其他开发者将无法使用,开源的意义就大打折扣。算法,UI,事件混合,这导致ImageJ1的算法代码无法被其他开发者调用,不得不大量使用`IJ.run(...)`,或许ImageJ2正在极力改变这种情况,而这在ImagePy中是不被允许的用法。我们推荐的方法是 43 | 44 | 1)如果你的插件只是实现很简单的数据操作,只有几行代码,那么OK,可以在run中实现。 45 | 46 | 2)如果你的算法相对复杂,那么最好将它写在一个单独的文件,并且这个模块中不要引用任何与ImagePy相关的模块,只基于`Numpy`,`Pandas`等标准科学计算库,这样以便他人可以拷贝出去,并且`import`使用。 47 | 48 | 3)如果你的算法意义重大,通用性很强,那么务必创建一个独立的算法项目,上传`pypi`,在插件项目中以引用的方式来使用。 49 | 50 | 4. **关于宏和headless** 51 | 52 | 相比ImageJ,ImagePy的宏实现的功能非常有限,只支持已有功能流程化调用,无法用宏实现逻辑,这其实与ImagePy的设计理念紧密相关,只要开发者都能做到以算法本身为核心,让ImagePy充当纯粹的连接器,那么任何的算法调用,可以用Python简单的调用。*Python已经如此简单强大,为什么还要另外学习一种晦涩而不通用的宏呢*?同样,ImagePy也不会支持`headless`,因为一切功能以算法本身为核心,而ImagePy只提供交互,那么在headless情况下,ImagePy还有什么意义?又有什么非要借助ImagePy的呢?如果一切功能都可以以库的形式提供,那么开发者为什么希望编写`headless`代码,而不是纯粹的python代码? 53 | 54 | 55 | 56 | ## 及时沟通 57 | 58 | 相比ImageJ,ImagePy还只是一个孩子,框架和功能都还不够完善,但优势是,我们可以自由把控,即时调整,而不需要考虑背在身上的强大且庞大的插件体系。作为插件开发者,如果在插件开发过程中遇到任何困难,请随时与我们联系,尤其是当你觉得一个插件开发的很复杂时,那么很可能是因为我们的框架缺乏某方面的支持,我们可以随时讨论,在插件开发的同时,共同完善主框架。让ImagePy更好的实现连接器的价值,为用户和开发者服务。 59 | 60 | ImagePy是 www.forum.image.sc 的合作伙伴,任何研发,使用方面的问题可以在里面进行讨论。 61 | 62 | -------------------------------------------------------------------------------- /doc/chinese/document.md: -------------------------------------------------------------------------------- 1 | # 为插件编写操作手册 2 | 3 | 操作手册并不是必须部分,但希望自己编写的插件能更好的服务用户,它是是非常重要的。这里我们演示如何给插件编写操作手册。 4 | 5 | 6 | 7 | ## 编写操作手册 8 | 9 | 在插件项目的顶级目录下,创建`doc`文件夹,在文件夹里即可用`markdown`为你的插件编写操作文档了,需要注意的是文件名需要与插件的`title`一致,这样ImagePy的文档管理器即可将文档与插件进行关联。工具类型的插件与菜单类型的插件都可以编写文档。 10 | 11 | `doc`下所有的`markdown`文件都会被解析并通过文件名关联给对应插件,所以这里并不强制要求文件组织方式,但我们强烈建议维护一个与插件目录一致的文档目录(创建`menus`,`tools`,`widgets`三个顶级目录),这样方便管理和维护,如果有必要我们可以加入多的目录文件,添加对应的跳转,这样整个`doc`目录也可以在github或其他在线环境中进行阅读。 12 | 13 | 14 | 15 | ## 查阅操作手册 16 | 17 | 当插件编写完成后,我们有如下方式对文档进行查阅: 18 | 19 | 1. 我们可以通过参数对话框的Help按钮 20 | 21 | 2. 工具栏图标上右键单击 22 | 23 | 3. 使用 **`Plugins > Manager`** 下的各种 **`Tree View`** 24 | 25 | ![14](http://idoc.imagepy.org/demoplugin/31.png) 26 | 27 |
view doc from plugin tree view

28 | 29 | 30 | -------------------------------------------------------------------------------- /doc/chinese/filter.md: -------------------------------------------------------------------------------- 1 | # Filter 插件 2 | 3 | Filter是最重要的一类插件,用于对二维图像进行滤波,也是图像处理中最基础,最普遍的一类应用。 4 | 5 | 6 | 7 | ## Invert 8 | 9 | ```python 10 | from imagepy.core.engine import Filter 11 | 12 | class Invert(Filter): 13 | title = 'Invert Demo' 14 | note = ['all', 'auto_msk', 'auto_snap'] 15 | 16 | def run(self, ips, snap, img, para = None): 17 | return 255-snap 18 | ``` 19 | 20 | Invert插件,`note`指明插件支持任何类型,并且支持`roi`,支持撤销。我们在`run`里面返回处理后的结果。关于`snap`和`img`,`img`是当前图像,而如果当`note`中加入`auto_snap`标识,在`run`之前,框架会帮我们把`img`拷贝给`snap`,因为多数的滤波器需要一个`buffer`来卷积,此外撤销和`roi`支持也必须借助`snap`。 21 | 22 | ![14](http://idoc.imagepy.org/demoplugin/13.png) 23 | 24 |
Invert

25 | 26 | 27 | 28 | ## Gaussian 29 | 30 | ```python 31 | from imagepy.core.engine import Filter 32 | from scipy.ndimage import gaussian_filter 33 | 34 | class Gaussian(Filter): 35 | title = 'Gaussian Demo' 36 | note = ['all', 'auto_msk', 'auto_snap','preview'] 37 | para = {'sigma':2} 38 | view = [(float, 'sigma', (0,30), 1, 'sigma', 'pix')] 39 | 40 | def run(self, ips, snap, img, para = None): 41 | gaussian_filter(snap, para['sigma'], output=img) 42 | ``` 43 | 44 | Gaussian插件,`note`指明支持任何类型,并且支持`roi`,支持撤销,并提供预览功能。`para`和`view`指明有一个浮点参数`sigma`,而`run`里,我们调用`scipy.ndimage.gaussian_filter`,对`snap`进行滤波,输出指向`img`,如果函数不带输出项,我们将处理结果`return`即可,框架会帮我们赋值给`img`。 45 | 46 | ![14](http://idoc.imagepy.org/demoplugin/14.png) 47 | 48 |
Gaussian

49 | 50 | 51 | 52 | ## Filter 运行机制 53 | 54 | **note:** 55 | 56 | note选项是行为控制标识,用于控制插件执行的流程,比如让框架进行类型兼容检测,如不满足自动中止。设定通道和序列支持设定,以及是否需要提供预览,roi等支持。 57 | 58 | 1. `all`:插件支持任意类型 59 | 60 | 2. `8-bit`:插件支持无符号8位 61 | 62 | 3. `16-bit`:插件支持无符号16位 63 | 64 | 4. `int`:插件支持32位,64位整数 65 | 66 | 5. `rgb`:插件支持3通道24位彩色 67 | 68 | 6. `float`:插件支持32位,64位浮点 69 | 70 | ------ 71 | 72 | 7. `not_channel`:当处理多通道时,不要框架自动遍历通道(默认情况下会将每个通道依次处理) 73 | 74 | 8. `not_slice`:当处理图像序列时,不要询问是否批量处理(默认情况会询问用户) 75 | 76 | 9. `req_roi`:是否必须有roi才能够处理 77 | 78 | --- 79 | 80 | 10. `auto_snap`:是否需要框架在处理器对当前图像自动缓冲 81 | 82 | 11. `auto_msk`:是否自动支持ROI(必须配合auto_snap才生效,原理是用snap恢复ROI以外像素) 83 | 84 | 12. `preview`:是否支持预览,调整参数实时查看结果 85 | 86 | 13. `2int`:是否在运算过程中将低于int32的数据转为int32再进行处理(例如避免8位的运算溢出) 87 | 88 | 14. `2float`:是否在运算过程中将低于float32的数据自动转为float32再进行处理(一些运算要求精度) 89 | 90 | 91 | 92 | **para, view:** 参数字典,具体用法参阅start入门。 93 | 94 | **run:** 95 | 96 | 1. `ips`:图像封装类,通常在`filter`中不需要对其进行操作 97 | 2. `snap`:当`note`里加入`auto_snap`标识后,在`run`之前框架会将当前图像拷贝到`snap`(尽可能实现使用对snap进行处理,将结果赋值给img) 98 | 3. `img`:当前图像,我们将结果赋值给`img`,或`return`结果,由框架赋值给`img`,并完成界面刷新。 99 | 100 | **load:** 101 | 102 | `def load(self, ips)` 最先执行,如果`return`结果为`False`,插件将中止执行。默认返回`True`,如有必要,可以对其进行重载,进行一系列条件检验,如不满足,`IPy.alert`弹出提示,并返回`False`。 103 | 104 | **preview:** 105 | 106 | `def preview(self, ips, para)` 在预览时执行,默认会调用`run`处理当前图像,如果有必要可以对其进行重载。 -------------------------------------------------------------------------------- /doc/chinese/free.md: -------------------------------------------------------------------------------- 1 | # Free 插件 2 | 3 | Free是不需要任何依赖就可以独立运行的插件,我们可以在里面做任何事,如创建图像,下载在线资源等。 4 | 5 | 6 | 7 | ## 创建图像 8 | 9 | ```python 10 | from imagepy.core.engine import Free 11 | from imagepy import IPy 12 | import numpy as np 13 | 14 | class NewImage(Free): 15 | title = 'New Image Demo' 16 | para = {'name':'new image','w':300, 'h':300} 17 | view = [(str, 'name', 'name',''), 18 | (int, 'w', (1,2048), 0, 'width', 'pix'), 19 | (int, 'h', (1,2048), 0, 'height', 'pix')] 20 | 21 | def run(self, para = None): 22 | imgs = [np.zeros((para['h'], para['w']), dtype=np.uint8)] 23 | IPy.show_img(imgs, para['name']) 24 | ``` 25 | 26 | 这里通过一个例子,创建一副新图像,同样我们可以通过para,view进行参数交互。 27 | 28 | ![14](http://idoc.imagepy.org/demoplugin/22.png) 29 | 30 |
New Image

31 | 32 | 33 | ## 关于对话框 34 | 35 | ```python 36 | from imagepy.core.engine import Free 37 | from imagepy import IPy 38 | 39 | class About(Free): 40 | title = 'About Demo' 41 | 42 | def run(self, para=None): 43 | IPy.alert('ImagePy v0.2') 44 | ``` 45 | 46 | 早在Hello World时就接触过,这里用作关于对话框。 47 | 48 | ![14](http://idoc.imagepy.org/demoplugin/23.png) 49 | 50 |
ImagePy Alert

51 | 52 | 53 | ## 退出软件 54 | 55 | ```python 56 | from imagepy.core.engine import Free 57 | from imagepy import IPy 58 | 59 | class Close(Free): 60 | title = 'Exit Program Demo' 61 | asyn = False 62 | 63 | def run(self, para = None): 64 | IPy.curapp.Close() 65 | ``` 66 | 67 | 退出软件是Free类型插件一个非常典型的应用,但值得一提的是,插件中加入了`asyn = False`,这个标识告诉ImagePy不要启用异步执行`run`,因为窗口关闭属于`UI`操作,必须在主线程进行。 68 | 69 | 70 | 71 | ## Free 的运行机制 72 | 73 | Free相比其他插件是运行机制最简单的,因为Free不需要做任何的流程准备,`run`也只有通过交互得到的`para`一个参数,完全放权给开发者。 74 | 75 | **para, view:** 76 | 77 | 参数字典,具体用法参阅start入门。 78 | 79 | **run:** 80 | 81 | 获取交互结果,做任何想做的事 82 | 83 | **load:** 84 | 85 | `def load(self, ips)` 最先执行,如果`return`结果为`False`,插件将中止执行。默认返回`True`,如有必要,可以对其进行重载,进行一系列条件检验,如不满足,`IPy.alert`弹出提示,并返回`False`。 86 | 87 | -------------------------------------------------------------------------------- /doc/chinese/macros.md: -------------------------------------------------------------------------------- 1 | # Macros 插件 2 | 3 | Macros是一系列的命令记录,用这些记录可以重演操作,我们一般并不会自己编写命令,而是通过宏录制器来完成记录。宏录制器在**`Plugins > Macros> Macros Recorder`**。 我们将录制的命令保存到menus或其子文件夹里,mc后缀,重启即可加载到对应位置。 4 | 5 | ![14](http://idoc.imagepy.org/demoplugin/08.png) 6 | 7 |
Macros Recorder

8 | 9 | **关于插件的加载方式** 10 | 11 | 1. menus及其子文件夹下的mc后缀文件会被解析成宏。 12 | 13 | 2. 也可以将宏文件拖拽到ImagePy最下方的状态栏执行。 14 | 15 | 16 | 17 | ## 高斯模糊再求反 18 | 19 | ```python 20 | Gaussian>{'sigma': 2} 21 | Invert>None 22 | ``` 23 | 24 | 以上是两条命令,点击后会依次执行Gaussian,Invert。 25 | 26 | ![14](http://idoc.imagepy.org/demoplugin/09.png) 27 | 28 |
Gaussian And Invert

29 | 30 | 1. 宏命令是`插件名称>参数字典`这种形式构成 31 | 2. 如果没有参数用 `None`占位 32 | 3. 如果有参数的命令参数给`None`,ImagePy会弹出参数对话框进行交互。 33 | 34 | 35 | 36 | ## 分割硬币 37 | 38 | ```python 39 | coins>None 40 | Up And Down Watershed>{'thr1': 36, 'thr2': 169, 'type': 'up area'} 41 | Fill Holes>None 42 | Geometry Filter>{'con': '4-connect', 'inv': False, 'area': 100.0, 'l': 0.0, 'holes': 0, 'solid': 0.0, 'e': 0.0, 'front': 255, 'back': 0} 43 | Geometry Analysis>{'con': '8-connect', 'center': True, 'area': True, 'l': True, 'extent': False, 'cov': True, 'slice': False, 'ed': False, 'holes': False, 'ca': False, 'fa': False, 'solid': False} 44 | ``` 45 | 46 | 以上是一个硬币分割的流程录制成宏,点击后会自动执行硬币分割,预处理,区域过滤,区域分析,生成表格。(当然通常我们不会将图像打开也录制到宏) 47 | 48 | ![14](http://idoc.imagepy.org/demoplugin/10.png) 49 | 50 |
Coins Segment Macros

-------------------------------------------------------------------------------- /doc/chinese/markdown.md: -------------------------------------------------------------------------------- 1 | # Markdown 插件 2 | 3 | MarkDown是一种标记语言,简单易读,适合书写文档,ImagePy对Markdown有直接支持,将Markdown文件拷贝到menus或其子目录下,下次启动时会被解析成一个菜单项,文件名即菜单标题,点击后弹出窗口,显示Markdown的内容。 4 | 5 | 6 | 7 | ## MarkDown Demo 8 | 9 | ```markdown 10 | # Markdown Demo 11 | This is a Mark Down Demo 12 | ``` 13 | ![14](http://idoc.imagepy.org/demoplugin/05.png) 14 | 15 |
MarkDown Demo

16 | -------------------------------------------------------------------------------- /doc/chinese/publish.md: -------------------------------------------------------------------------------- 1 | # 插件项目发布 2 | 3 | 以上我们讨论了每一种插件的写法,当然,我们可以任意在ImagePy的`menus`,`tools`,`widgets`下创建python脚本以扩展出某个插件功能,但当我们的插件越来越多,功能越来越系统,当然就会希望正式发布成一个插件项目,可以让其他用户方便的安装使用。这里我们讨论如何发布一个插件项目。 4 | 5 | 6 | 7 | ## 功能组织 8 | 9 | **功能划分** 10 | 11 | 如果我们的插件并不是一个单一的功能,而是系统性很强的一系列功能,那么我们应该将这些功能进行划分和聚类,用文件夹来进行组织。例如我们之前编写的全部功能,就可以按照插件类型来进行组织。 12 | 13 | ![14](http://idoc.imagepy.org/demoplugin/28.png) 14 | 15 |
功能划分

16 | **顺序设定** 17 | 18 | 我们看到,对插件进行了功能划分,看起来就更加清晰,然而插件是以字母顺序进行排序的,我们希望指定顺序,在ImagePy中这非常容易实现,我们在init.py文件中加入`catlog`字段,用一个列表对象指明顺序。 19 | 20 | `__init__.py` 21 | 22 | ```python 23 | catlog = ['Start Here', '-', 'Markdown Demo', 'Macros Demo', 'Workflow Demo', '-', 'Filter Demo', 'Simple Demo', 'Table Demo', 'Free Demo', '-', 'WidgetDemo'] 24 | ``` 25 | 26 | 一旦设定catlog,菜单将按照指定顺序加载,`'-'`被解析成分割线。`catlog`可以出现在任何插件目录下,即可以指定插件,也可以指定文件夹的顺序,对于tools也起作用(另一种设定顺序的方式是之前介绍的一个文件实现多个插件的`plgs`方式)。 27 | 28 | ![14](http://idoc.imagepy.org/demoplugin/29.png) 29 | 30 |
sort by catlog

31 | 32 | `catlog`可以出现在任何插件目录下,即可以指定插件,也可以指定文件夹的顺序,对于`tools`也起作用。另外多插件的文件中通过`plgs`也可以指定插件的顺序。 33 | 34 | 35 | 36 | ## 插件项目创建 37 | 38 | **创建插件项目仓库** 39 | 40 | 如果插件都分散在ImagePy主项目的文件夹下不便于管理,因而我们创建一个单独的插件项目仓库,在仓库的顶层创建`menus`,`tools`,`widgets`三个文件夹,里面存放经过功能划分和顺序设定的插件。 41 | 42 | 43 | 44 | **编写 requirements** 45 | 46 | Python最大的好处在于有丰富的库,作为一个插件项目,很可能会依赖其他的库,按照惯例,需要把依赖写入到`requirements.txt`中(ImagePy在安装插件时会自动调用pip解决依赖,暂时只支持pip,后续会考虑支持conda) 47 | 48 | 49 | 50 | **编写readme** 51 | 52 | readme原本只是用于项目介绍,但在ImagePy中将readme的前几行信息用作插件管理,所以readme前几行需要严格按照如下规范,以本项目为例: 53 | 54 | ```markdown 55 | # Demo Plugin 56 | 57 | Path: https://github.com/Image-Py/demoplugin 58 | 59 | Version: 0.1 60 | 61 | Author: YXDragon 62 | 63 | Email: yxdragon@imagepy.org 64 | 65 | Keyword: demo, tutorial 66 | 67 | Description: a friendly develop tutorial 68 | 69 | *以下可以随意书写* 70 | 71 | ``` 72 | 73 | 74 | 75 | **插件的安装** 76 | 77 | **`Plugins > Install > Install Plugin`** 在对话框中输入插件仓库的github连接,ImagePy即开始下载插件,解决依赖,并自动加载。加载成功后我们可以看到菜单栏,工具栏,组件栏自动更新。这样,把你的插件项目地址发给其他人,就可以安装,使用了。 78 | 79 | ![14](http://idoc.imagepy.org/demoplugin/30.png) 80 | 81 |
插件的安装

82 | 83 | ## 发布到 ImagePy 84 | 85 | **给ImagePy发Pull Request** 86 | 87 | 你也可以将插件项目发布到ImagePy,如果你已经完成你的插件项目,那么发布是一个很简单的过程。只需要`fork`一份ImagePy,将你的`readme`文件拷贝到**`imagepy - Plugins - Contribute - Contributors`**下,重命名为插件项目名称(不强制,但最好能体现插件功能),然后给ImagePy提`Pull Request`。当ImagePy组织成员收到`Pull Request`,并进行测试后,会`merge`你的`Pull Request`,如有问题会通过`issue`进行沟通。一旦合并到ImagePy主分支内,用户即可通过插件管理器对插件进行检索,安装,卸载等操作。 88 | 89 | ![14](http://idoc.imagepy.org/demoplugin/06.png) 90 | 91 |
Plugins Manager

92 | 93 | 插件管理器会自动解析`contributors`目录下的插件信息,因而插件项目的`readme`务必按照格式认真书写,这会影响用户的检索体验。如果有更新,请修改版本号,重新`Pull Request`,插件管理器会自动检测更新。 94 | 95 | 96 | 97 | **关于顶级菜单** 98 | 99 | 我们看到安装插件后,插件项目中的功能也加载到了菜单栏,工具栏,组件栏中,可见插件项目中的menus,tools,widgets目录与ImagePy主项目中的目录具有等同效果。**如果不希望插件功能出现在顶级菜单,可以用文件夹结构进行控制**,比如希望出现在Plugin下,就在插件项目的menus目录下加一层Plugin,进而放我们自己的插件,启动后新功能就会出现在Plugins菜单下) 100 | 101 | 其实插件项目安装后会将项目解压到ImagePy下的`plugins`目录内,而ImagePy启动时,在解析主项目的目录后,也会解析插件项目的目录结构,这样实现了插件项目的相对独立管理。**由于顶级菜单空间稀缺,因而如果不是非常丰富,系统性很强的功能,请不要占用顶级菜单** -------------------------------------------------------------------------------- /doc/chinese/report.md: -------------------------------------------------------------------------------- 1 | # Report 插件 2 | 3 | 很多问题,最终我们都需要将分析结果整理成报表,生成PDF文档,或者打印。虽然现在LaTex,Markdown等基于标签语言的文档工具非常强大,但是Excel依然是受众最广,上手最简单,精细布局能力最强的表格软件,此外Excel具有强大的数据处理,图表生成功能,因而ImagePy选择Excel作为报表功能载体,用户可自己设计Excel模板,并且在特定单元格中加入标记并保存,将后缀改为rpt,这样就成为了ImagePy的报表插件。 4 | 5 | 6 | 7 | **报表插件的加载方式** 8 | 9 | 1. menus及其子文件夹下的rpt后缀文件会被解析成报表模板。 10 | 2. 也可以将模板文件拖拽到ImagePy最下方的状态栏来执行。 11 | 12 | 13 | 14 | ## 个人信息 15 | 16 | 这里用一张个人信息卡来展示如何制作模板并标记单元格。为了方便打印,我们需要根据自己的情况,先设定纸张大小,这里设置为A5。其次为了精确布局,我们将Excel的视图切换为页面布局,这样单元格尺寸设定都会以cm为单位。 17 | 18 | --- 19 | 20 | ![06](http://idoc.imagepy.org/demoplugin/33.png) 21 | 22 |
personal information template

23 | 24 | --- 25 | 26 | ![06](http://idoc.imagepy.org/demoplugin/34.png) 27 | 28 |
personal information result

29 | 30 | ## 硬币分割 31 | 32 | 我们继续用硬币分割与测量的例子,将分析结果制作成报表。这里我们精心设计一个实验报告,里面包基础信息,处理过程图片,以及结果表格,并在Excel中对结果做了统计,针对面积列,绘制了柱状图。 33 | 34 | ![06](http://idoc.imagepy.org/demoplugin/37.png) 35 | 36 |
do coins segment in ImagePy

37 | 38 | ![06](http://idoc.imagepy.org/demoplugin/38.png) 39 | 40 |
generate coins report

41 | 42 | ## 报表模板设计原则 43 | 44 | ImagePy在执行报表插件时,会首先对Excel模板进行解析,分析各个Work Sheet,并检测每个单元格,将所有变量标记提取,以对话框形式与用户交互,确认后,将全部信息回填,并另存。使用非常方便,但我们必须遵循一定的原则来设计模板,这里详细介绍。 45 | 46 | 47 | 48 | *为了方便打印,我们需要根据自己的情况,先设定纸张大小,例如 A4, A5。其次为了精确布局,我们将 Excel 的视图切换为页面布局,这样单元格尺寸设定都会以cm为单位。* 49 | 50 | 51 | 52 | **通用语法** 53 | 54 | `{type Var_Name = Default Value # note}`,任何类型的变量标记都遵循这个格式,其中大括号为变量标识,而其他项有些项是必须,有些可选,对于不同类型稍有差异,具体如下。 55 | 56 | **基础参数** 57 | 58 | `int,float,str,txt,bool`:这几个基础参数,语法格式一致以str为例,`{str Name = YX Dragon # please input your name here}`,其中类型与变量名是必须的,默认值与注释为可选。`str`与`txt`的差别在于,在ImagePy的交互对话框中,`txt`可以接收多行文字。 59 | 60 | **选择参数** 61 | 62 | `list`:用法举例`{list Favourite_System = [Windows, Linux, Mac] # please select your favourite system}`,对于list选项,默认值必须提供,用中括号框住,选项用逗号分开,空格会被忽略,注释为可选。 63 | 64 | **图像参数** 65 | 66 | `img`:用法举例`{img My_Photo = [4.8,4.8,0.9,0] # you photo here`,对于img类型,默认值必须提供,是一个中括号,里面四个数字,分别代表:长度(cm),高度(cm),留白比例(0.9代表四周留10%),是否拉伸(0表示保持比例,1可以拉伸),注释为可选。 67 | 68 | **表格参数** 69 | 70 | `tab`:用法举例`{tab Record = [1,3,0,0] # the result table}`,对于tab类型,默认值必须提供,是一个中括号,里面四个数字,分别代表:行距(不合并单元格为1),列距(不合并单元格为1),标题行相对位置(-1代表数据区域的上一行,0代表不填充标题),索引列行对位置(-1代表数据区域的左边一列,0代表不填充索引),注释为可选。 -------------------------------------------------------------------------------- /doc/chinese/simple.md: -------------------------------------------------------------------------------- 1 | # Simple 2 | 3 | Simple是Filter之外的又一个比较重要的插件,不同的是Simple不着重处理单张图像,而是把图像序列当作整体进行三维处理,此外也用于操作图像之外的相关属性,如ROI, 色彩索引表,比例尺及单位,或图像Mark。 4 | 5 | 6 | 7 | ## Gaussian3D 8 | 9 | ```python 10 | from imagepy.core.engine import Simple 11 | import scipy.ndimage as ndimg 12 | 13 | class Gaussian3D(Simple): 14 | title = 'Gaussian 3D Demo' 15 | note = ['all', 'stack3d'] 16 | 17 | para = {'sigma':2} 18 | view = [(float, 'sigma', (0,30), 1, 'sigma', 'pix')] 19 | 20 | def run(self, ips, imgs, para = None): 21 | imgs[:] = ndimg.gaussian_filter(imgs, para['sigma']) 22 | ``` 23 | 24 | `note`里的`stack3d`标识是指插件处理一个连续的图像栈,而`run`函数里,可以通过`imgs`拿到图像序列,是一个`ndarray`对象,我们对其进行三维高斯滤波,结果重新赋值给`imgs`。 25 | 26 | ImagePy里图像序列分`stack2d`,`stack3d`,其中`stack2d`是基于`list`的图像序列,便于增加,删除`slice`。而`stack3d`是一个连续的`numpy`数组,便于三维滤波,分析。我们可以通过 **`Image > Type > Trans to stack/list`** 进行转换。 27 | 28 | *基于Filter的二维高斯滤波也会处理序列,但处理方式是当成多个二维图像处理,而基于Simple的三维高斯滤波,则是在z方向也进行了卷积。* 29 | 30 | 31 | 32 | ## SetLUT 33 | 34 | ```python 35 | from imagepy.core.engine import Simple 36 | import numpy as np 37 | 38 | class SetLUT(Simple): 39 | title = 'Set LUT Demo' 40 | note = ['all'] 41 | para = {'lut':'red'} 42 | view = [(list, 'lut', ['red', 'green', 'blue'], str, 'look up', 'table')] 43 | 44 | def run(self, ips, imgs, para = None): 45 | cmap = [[i==para['lut']] for i in ['red', 'green', 'blue']] 46 | ips.lut = (cmap*np.arange(256)).astype(np.uint8).T 47 | ``` 48 | 49 | lookup table是一个255*3的色彩映射表,映射表并不改变像素,只改变图像的显示。可以通过ips.lut进行访问或设定。与之相关的还有一个ips.range,是一个二元tuple,设定图像像素的动态范围,对于8位图像,通常是0-255,但对于float类型,range的设定就非常有意义,事实上,在展示时,ImagePy先根据range将图像进行clip,并缩放到0-255,然后再套用索引表。 50 | 51 | ![14](http://idoc.imagepy.org/demoplugin/15.png) 52 | 53 |
SetLUT

54 | 55 | 56 | ## Inflate ROI 57 | 58 | ```python 59 | from imagepy.core.engine import Simple 60 | 61 | class Inflate(Simple): 62 | title = 'Inflate ROI Demo' 63 | note = ['all', 'req_roi'] 64 | para = {'r':5} 65 | view = [(int, 'r', (1,100),0, 'radius', 'pix')] 66 | 67 | def run(self, ips, imgs, para = None): 68 | ips.roi = ips.roi.buffer(para['r']) 69 | ``` 70 | 71 | `ROI`指明哪些区域是我们关心的,ImagePy中的`ROI`基于`Shapely`对象,我们可以对其进行操作,以上是对当前`ROI`进行扩张的例子。 72 | 73 | 74 | ![14](http://idoc.imagepy.org/demoplugin/16.png) 75 | 76 |
Inflate ROI

77 | 78 | ## Set Scale And Unit 79 | 80 | ```python 81 | from imagepy.core.engine import Simple 82 | 83 | class Unit(Simple): 84 | title = 'Scale And Unit Demo' 85 | note = ['all'] 86 | para = {'scale':1, 'unit':'mm'} 87 | view = [(float, 'scale', (1e-3,1e3), 3, 'scale', ''), 88 | (str, 'unit', 'scale', '')] 89 | 90 | def run(self, ips, imgs, para = None): 91 | ips.unit = (para['scale'], para['unit']) 92 | ``` 93 | 94 | 默认情况ImagePy中的一切测量,分析结果以像素为单位,但我们可以通过`ips.unit`对其进行访问和设定。 95 | 96 | 97 | ![14](http://idoc.imagepy.org/demoplugin/17.png) 98 | 99 |
Set Scale And Unit

100 | 101 | ## Mark 102 | 103 | ```python 104 | from imagepy.core.engine import Simple 105 | from imagepy.core.mark import GeometryMark 106 | import numpy as np 107 | 108 | class Mark(Simple): 109 | title = 'Random Points Demo' 110 | note = ['all'] 111 | 112 | def run(self, ips, imgs, para = None): 113 | pts = (np.random.rand(200)*512).reshape((100,2)) 114 | ips.mark = GeometryMark({'type':'points', 'color':(255,0,0), 'lw':1, 'body':pts}) 115 | ``` 116 | 117 | `mark`是图像上的覆盖物,并不改变图像本身。ImagePy定义了一套几何数据结果用于绘制`mark`,这里简单介绍: 118 | 119 | ![14](http://idoc.imagepy.org/demoplugin/18.png) 120 | 121 |
Set Random Point Mark

122 | 123 | 124 | **各种Mark类型及用法** 125 | 126 | **point:** 127 | 128 | ```python 129 | {'type':'point', 'color':(r,g,b), 'lw':1, 'body':(x,y)} 130 | ``` 131 | 132 | **points:** 133 | 134 | ```python 135 | {'type':'points', 'color':(r,g,b), 'lw':1, 'body':[(x1,y1), (x2,y2), ...]} 136 | ``` 137 | 138 | **line:** 139 | ```python 140 | {'type':'line', 'color':(r,g,b), 'lw':1, 'style':'-', 'body':[(x1,y1), (x2,y2), ...]} 141 | ``` 142 | 143 | **lines:** 144 | ```python 145 | {'type':'lines', 'color':(r,g,b), 'lw':1, 'style':'-', 'body':[[(x1,y1), (x2,y2), ...], [...]]} 146 | ``` 147 | 148 | **polygon:** 149 | ```python 150 | {'type':'polygon', 'color':(r,g,b), 'fcolor':(r,g,b), 'lw':1, 'style':'o', 'body':[(x1,y1), (x2,y2), ...]} 151 | ``` 152 | 153 | **polygons:** 154 | ```python 155 | {'type':'polygons', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'lw':1, 'style':'o', 'body':[[(x1,y1), (x2,y2), ...], [...]]} 156 | ``` 157 | 158 | **circle:** 159 | ```python 160 | {'type':'circle', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':(x,y,r)} 161 | ``` 162 | 163 | **circles:** 164 | ```python 165 | {'type':'circles', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':[(x1,y1,r1), (x2,y2,r2)]} 166 | ``` 167 | 168 | **ellipse:** 169 | ```python 170 | {'type':'ellipse', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':(x,y,l1,l2,ori)} 171 | ``` 172 | 173 | **ellipses:** 174 | ```python 175 | {'type':'ellipses', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':[(x1,y1,a1,b1,ori1), (x2,y2,a2,b2,ori2), ...]} 176 | ``` 177 | **rectangle:** 178 | ```python 179 | {'type':'rectangle', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':True, 'body':(x,y,w,h)} 180 | ``` 181 | 182 | **rectangles:** 183 | ```python 184 | {'type':'rectangles', 'color':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':[(x1,y1,w1,h1),(x2,y2,w2,h2),...]} 185 | ``` 186 | 187 | **text:** 188 | ```python 189 | {'type':'text', 'color':(r,g,b), 'fcolor':(r,g,b), 'size':8, 'pt':True, 'body':(x,y,txt)} 190 | ``` 191 | 192 | **texts:** 193 | ```python 194 | {'type':'texts', 'color':(r,g,b), 'fcolor':(r,g,b), 'size':8, 'pt':True, 'body':[(x1,y1,txt1),(x2,y2,txt2)]} 195 | ``` 196 | 197 | --- 198 | 199 | **layer:** 200 | ```python 201 | {'type':'layer', 'num':-1, 'clolor':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':[sequence of basic element]} 202 | ``` 203 | 204 | **layers:** 205 | ```python 206 | {'type':'layers', 'num':-1, 'clolor':(r,g,b), 'fcolor':(r,g,b), 'fill':False, 'body':{1:layer1, 2:layer2, ...}} 207 | ``` 208 | 209 | 210 | 211 | **以上各个基础元素,形式类似,这里统一讲解各个参数的意义:** 212 | 213 | **type:** 元素类型 214 | 215 | **color:** 颜色 216 | 217 | **fcolor:** 填充色 (只有面状要素有) 218 | 219 | **fill:** 是否填充 (只有面状要素有) 220 | 221 | **lw:** 线条宽度 222 | 223 | **style:** 线条风格,有'-o'代表线条和节点都绘制,当然也可以选择只绘制线条或节点,或都不 224 | 225 | **size:** 文字高度 (只有文字有) 226 | 227 | **body:** 几何数据,根据各个类型而定 228 | 229 | 230 | 231 | **要素集合** 232 | 233 | **layer:** `layer`可以指定`color`, `fcolor`, `fill`, 不同的是,`layer`的`body`存放的是其他基础要素,其实以上各种要素,除了`type`,`body`其他的属性都是非必须的,如果当前要素没有指定,则会取自其所属的`layer`,如果没有所属`layer`,或`layer`也未指定,则会使用默认。 234 | 235 | **layers:** `layers`是更高级的要素集合,与`layer`不同的是,`layers`的`body`是一个字典,其键是一个表示层数的int,而且在图像序列中,只绘制层号所对应的`layer`,这样可以实现对图像序列的每一张设定一个对应的`mark`。 236 | 237 | 238 | 239 | ## Simple 运行机制 240 | 241 | **note:** 242 | 243 | `note`选项是行为控制标识,用于控制插件执行的流程,比如让框架进行类型兼容检测,如不满足自动中止。设定通道和序列支持设定,以及是否需要提供预览,roi等支持。 244 | 245 | 1. `all`:插件支持任意类型 246 | 247 | 2. `8-bit`:插件支持无符号8位 248 | 249 | 3. `16-bit`:插件支持无符号16位 250 | 251 | 4. `int`:插件支持32位,64位整数 252 | 253 | 5. `rgb`:插件支持3通道24位彩色 254 | 255 | 6. `float`:插件支持32位,64位浮点 256 | 257 | --- 258 | 259 | 7. `req_roi`:是否必须有roi才能够处理 260 | 261 | 8. `stack`:要求必须是图像序列 262 | 263 | 9. `stack2d`:要求必须是离散图像序列(list) 264 | 265 | 10. `stack3d`:要求必须是连续图像序列(ndarray) 266 | 267 | 11. `preview`:是否显示预览选项 268 | 269 | **para, view:** 270 | 271 | 参数字典,具体用法参阅start入门。 272 | 273 | **run:** 274 | 275 | 1. `ips`:图像封装类,我们可以通过`ips`对`roi`, `mark`, `lut`, `range`, `unit`等进行操作 276 | 2. `imgs`:图像序列,对其进行操作,如三维滤波,或分析,可以以表格形式展示结果。 277 | 278 | **load:** 279 | 280 | `def load(self, ips)` 最先执行,如果`return`结果为`False`,插件将中止执行。默认返回`True`,如有必要,可以对其进行重载,进行一系列条件检验,如不满足,`IPy.alert` 弹出提示,并返回`False`。 281 | 282 | **preview:** 283 | 284 | `def preview(self, ips, para)` Simple虽然定义了`preview`,但默认是什么也不做的,因为对于三维滤波等操作,往往需要很长的运算时间,因而并不适合预览,如有需要可以重载。 -------------------------------------------------------------------------------- /doc/chinese/start.md: -------------------------------------------------------------------------------- 1 | # 从这里开始 2 | 3 | 这里我们用Hello World的例子来开始,顺带介绍插件的加载机制,以及如何配置参数对话框,为后续的开发做好准备。 4 | 5 | 6 | 7 | ## 什么是插件 8 | 9 | ImagePy是一个扩展性很强的图像处理框架,我们是通过插件来对ImagePy进行功能扩展的,插件是一段代码或一个文件,放在特定的位置,在ImagePy启动时自动加载,其具体形式可以体现为菜单,工具栏,桌面小部件。其实在ImagePy中一切功能皆插件,ImagePy原生功能并不享受任何特权,这些插件根据目录层级解析成对应UI元素,并在点击时触发相应功能,我们可以使用**`Plugins > Manager > Plugin Tree View`**来查看插件及其对应的源码。 10 | 11 | ![31](http://idoc.imagepy.org/demoplugin/31.png) 12 |
Plugins Tree View

13 | 14 | 15 | 16 | ## Hello World 17 | 18 | 我们开始写第一个插件,实现一个简单的hello world. 19 | 20 | ```python 21 | from imagepy.core.engine import Free 22 | from imagepy import IPy 23 | 24 | class Plugin(Free): 25 | title = 'Hello World' 26 | 27 | def run(self, para=None): 28 | IPy.alert('Hello World, I am ImagePy!') 29 | ``` 30 | 这是一个最简单的插件,首先`import Free, IPy`. 这里的`Free`是一种插件类型,这种类型插件可以不依赖图像而运行,我们在`run`里面用`IPy.alert`弹出一个'Hello world, I am ImagePy!'的提示框。 31 | 32 | ![14](http://idoc.imagepy.org/demoplugin/01.png) 33 |
Hello World

34 | 35 | **如何加载** 36 | 我们将上面的脚本文件命名为 `hello_plg.py`,拷贝到ImagePy目录下的`Imagepy > menus > Plugins`目录下,重新启动ImagePy,点开`Plugins`菜单,就会看到我们的插件。一些加载原则如下: 37 | 38 | 1. `menus`及其子目录会被解析。 39 | 2. `plg.py`的文件会被解析。 40 | 3. 文件内的`Plugins`类会被解析为插件,`title`是菜单显示内容 41 | 42 | 43 | 44 | ## Who Are You 45 | 46 | 接下来我们为这个插件添加一些参数,邀请用户输入名字和年龄。 47 | 48 | ```python 49 | from imagepy.core.engine import Free 50 | from imagepy import IPy 51 | 52 | class Plugin(Free): 53 | title = 'Who Are You' 54 | para = {'name':'', 'age':0} 55 | view = [(str, 'name', 'name', 'please'), 56 | (int, 'age', (0,120), 0, 'age', 'years old')] 57 | 58 | def run(self, para=None): 59 | IPy.alert('Name:\t%s\r\nAge:\t%d'%(para['name'], para['age'])) 60 | ``` 61 | 62 | ImagePy框架实现了参数对话框生成机制,可以根据`para`,`view`来生成对应的交互,完成交互后,我们在`run`函数中可以通过`para`参数获取交互结果,我们在下一个例子中会更加详细的讲解各种类型的参数生成。 63 | 64 | ![14](http://idoc.imagepy.org/demoplugin/02.png) 65 |
Who Are You

66 | 67 | 68 | 69 | ## Questionnaire 70 | 71 | ```python 72 | from imagepy.core.engine import Free 73 | from imagepy import IPy 74 | 75 | class Plugin(Free): 76 | title = 'Questionnaire' 77 | 78 | para = {'name':'yxdragon', 'age':10, 'h':1.72, 'w':70, 'sport':True, 'sys':'Mac', 'lan':['C/C++', 'Python'], 'c':(255,0,0)} 79 | 80 | view = [('lab', 'lab', 'This is a questionnaire'), 81 | (str, 'name', 'name', 'please'), 82 | (int, 'age', (0,150), 0, 'age', 'years old'), 83 | (float, 'h', (0.3, 2.5), 2, 'height', 'm'), 84 | ('slide', 'w', (1, 150), 0, 'kg'), 85 | (bool, 'sport', 'do you like sport'), 86 | (list, 'sys', ['Windows','Mac','Linux'], str, 'favourite', 'system'), 87 | ('chos', 'lan', ['C/C++','Java','Python'], 'lanuage you like(multi)'), 88 | ('color', 'c', 'which', 'you like')] 89 | 90 | def run(self, para=None): 91 | rst = ['Questionnaire Result', 92 | 'Name:%s'%para['name'], 93 | 'Age:%s'%para['age'], 94 | 'Height:%sm'%para['h'], 95 | 'Weight:%skg'%para['w'], 96 | 'Like Sport:%s'%para['sport'], 97 | 'Favourite System:%s'%para['sys'], 98 | 'Like lanuage:%s'%para['lan'], 99 | 'Favourite Color:%s'%str(para['c'])] 100 | 101 | IPy.alert('\r\n'.join(rst)) 102 | ``` 103 | 这里我们实现一个调查问卷,让用户输入各类信息,同时也是为了向开发者展示,如何通过`para`,`view`来说配置出任何自己想要的参数对话框。 104 | 105 | 106 | ![14](http://idoc.imagepy.org/demoplugin/03.png) 107 |
Questionnaire

108 | 109 | **label:** para类型:`不需要参数`, view用法:`('lab', 'lab', 'what you want to show')` 110 | 111 | **str:** para类型:`str`, view用法:`(str, key, prefix, suffix)`,其中`key`要和`para`中的`key`对应,`prefix`,`suffix`用作输入框前后的提示内容。 112 | 113 | **int:** para类型:`int`,view用法:`(int, key, (lim1, lim2), accu, 'prefix', 'suffix')`,其中`key`要和`para`中的`key`对应,`limit`用于限定输入数值的范围,`accu`限定小数点位数(0),`prefix`,`suffix`用作输入框前后的提示内容。 114 | 115 | **float:** para类型:`float`,view用法:`(int, key, (lim1, lim2), accu, 'prefix', 'suffix')`,其中`key`要和`para`中的`key`对应,`limit`用于限定输入数值的范围,`accu`限定小数点位数,`prefix`,`suffix`用作输入框前后的提示内容。 116 | 117 | **slider:** para类型:`int/float`,view用法:`('slide', key, (lim1, lim2), accu, 'prefix')`,其中`key`要和`para`中的`key`对应,`limit`用于限定输入数值的范围,`accu`限定小数点位数,`prefix`用作输入框前后的提示内容。 118 | 119 | **bool:** para类型:`bool`,view用法:`(bool, 'key', 'label')`,其中`key`要和`para`中的`key`对应,`label`用作提示。 120 | 121 | **list:** para类型:`any type`,view用法:`(list, key, [choices], type, prefix, suffix)`,其中`key`要和`para`中的`key`对应,`choices`是字符选项,`type`是期望输出类型,如`str`, `int`,`prefix`,`suffix`用作选择框前后的提示内容。 122 | 123 | **choices:** para类型:`str list`,view用法:`('chos', key, [choices], prefix, suffix)`,与`list`类似,不同的是`choices`可以支持多选,选项以`list of string`形式记录。 124 | 125 | **color:** para类型:`(r,g,b) 0-255`,用法:`('color', key, prefix, suffix)`,其中`key`要和`para`中的`key`对应,`prefix`,`suffix`用作输入框前后的提示内容。 126 | 127 | 128 | 129 | *除以上基础数据类型之外,ImagePy还支持一些内部类型的参数,如接收一副图像,接收一个表格,或者对表格的字段进行单选或多选,这些我们在后续的示例中会有所展示* 130 | 131 | 132 | 133 | ## 一个文件内实现多个插件 134 | 以上我们分别实现了三个插件,而Python具有语法精简的优势,所以我们也可以在一个文件内实现多个插件,方法如下。 135 | 136 | ```python 137 | from imagepy.core.engine import Free 138 | from imagepy import IPy 139 | 140 | class HelloWorld(Free): 141 | title = 'Hello World' 142 | ... 143 | 144 | class WhoAreYou(Free): 145 | title = 'Who Are You' 146 | ... 147 | 148 | class Questionnaire(Free): 149 | title = 'Questionnaire' 150 | ... 151 | 152 | plgs = [HelloWorld, WhoAreYou, Questionnaire] 153 | ``` 154 | 155 | 我们将三个类写在一个文件内,最后加上`plgs = []`,文件命名为`start_plgs.py`。框架加载原则如下: 156 | 157 | 1. `menus`目录或子目录下的`plgs.py`结尾的文件会被当作多插件解析 158 | 2. 插件内的`plgs`列表会被依次解析 159 | 3. `plgs`内可以加入`'-'`,会被解析为菜单分隔符 160 | 161 | ![14](http://idoc.imagepy.org/demoplugin/04.png) 162 | 163 |
parse as menus

164 | 165 | -------------------------------------------------------------------------------- /doc/chinese/table.md: -------------------------------------------------------------------------------- 1 | # Table 插件 2 | 3 | 表格是图像之外另一个非常重要的数据类型,某种意义上,科研图像分析的结果最终都会归到表格。ImagePy对表格类型数据有很好的支持,其核心数据结构是`pandas.DataFrame`。 4 | 5 | 6 | 7 | ## 生成成绩单 8 | 9 | ```python 10 | from imagepy.core.engine import Free 11 | from imagepy import IPy 12 | import numpy as np 13 | import pandas as pd 14 | 15 | class Score(Free): 16 | title = 'Student Score' 17 | 18 | def run(self, para=None): 19 | index = ['Stutent%s'%i for i in range(1,6)] 20 | columns = ['Math', 'Physics', 'Biology', 'History'] 21 | score = (np.random.rand(20)*40+60).reshape((5,4)).astype(np.uint8) 22 | IPy.show_table(pd.DataFrame(score, index, columns), 'Scores') 23 | ``` 24 | 25 | 我们通过一个`Free`插件生成表格,表格是一个`pandas.DataFrame`对象,通过`IPy.show_table(df, title)`来展示。 26 | 27 | ![14](http://idoc.imagepy.org/demoplugin/19.png) 28 | 29 |
generate score list

30 | 31 | 32 | ## 根据某科成绩排序 33 | 34 | ```python 35 | from imagepy.core.engine import Table 36 | 37 | class Sort(Table): 38 | title = 'Table Sort Demo' 39 | 40 | para = {'by':'Math'} 41 | view = [('field', 'by', 'item', '')] 42 | 43 | def run(self, tps, data, snap, para=None): 44 | tps.data.sort_values(by=para['by'], inplace=True) 45 | ``` 46 | 47 | 这里用到了一种新的参数类型,`field`,这种参数类型其实是一个单选类型,但是不需要我们提供选项,会自动从当前表格的`columns`中获取。`run`中通过`inplace`参数直接改变`DataFrame`本身,一些操作无法修改本身,可以将结果return。 48 | 49 | ![14](http://idoc.imagepy.org/demoplugin/20.png) 50 | 51 |
sort by math

52 | 53 | 54 | ## 绘制柱状图 55 | 56 | ```python 57 | class Bar(Table): 58 | title = 'Score Chart Demo' 59 | asyn = False 60 | 61 | para = {'item':[]} 62 | view = [('fields', 'item', 'select items')] 63 | 64 | def run(self, tps, data, snap, para = None): 65 | data[para['item']].plot.bar(stacked=True, grid=True, title='Score Chart') 66 | plt.show() 67 | ``` 68 | 69 | 这里又遇到了一种参数类型,`fields`,这种参数类型其实是一个多选类型,但是不需要我们提供选项,会自动从当前表格的`columns`中获取。当表格从界面上被选中若干列,参数对话框里对应的项也会被默认勾上。我们用pandas自带的绘图函数,但值得一提的是,插件中加入了`asyn = False`,这个标识告诉ImagePy不要启用异步执行`run`,因为这个插件涉及了`UI`,必须在主线程进行。 70 | 71 | 72 | ![14](http://idoc.imagepy.org/demoplugin/21.png) 73 | 74 |
bar chart

75 | 76 | ## Table 运行机制 77 | 78 | **note:** 79 | 80 | `note`选项是行为控制标识,用于控制插件执行的流程,比如让框架进行类型兼容检测,如不满足自动中止,与Filter和simple的note有所区别。 81 | 82 | 1. `req_sel`:需要选区 83 | 2. `req_row`:需要选中行 84 | 3. `req_col`:需要选中列 85 | 4. `auto_snap`:处理前框架自动对数据进行缓冲 86 | 5. `row_msk`:snap时只缓冲选中的行 87 | 6. `col_msk`:snap时只缓冲选中的列 88 | 7. `num_only`:snap时只缓冲数值列 89 | 8. `preview`:是否显示预览选项 90 | 91 | **para, view:** 92 | 93 | 参数字典,具体用法参阅start入门。 94 | 95 | **run:** 96 | 97 | 1. `tps`:表格封装类,我们可以通过`tps`对`rowmsk`, `colmsk`等进行访问或操作 98 | 2. `snap`:表格缓冲,如果有`auto_snap`标识,则可以生效。 99 | 3. `data`:当前表格,对其进行操作。 100 | 101 | **load:** 102 | 103 | `def load(self, tps)` 最先执行,如果`return`结果为`False`,插件将中止执行。默认返回`True`,如有必要,可以对其进行重载,进行一系列条件检验,如不满足,`IPy.alert`弹出提示,并返回`False`。 104 | 105 | **preview:** 106 | 107 | `def preview(self, tps, para)` ,默认情况下会自动执行`run`并更新,有需要可以重载。 -------------------------------------------------------------------------------- /doc/chinese/tool.md: -------------------------------------------------------------------------------- 1 | # Tool 插件 2 | 3 | Tool插件用来完成鼠标交互,启动时被加载为工具栏上的图标。典型的工具插件是,roi编辑,画笔,测量工具等。 4 | 5 | 6 | 7 | ## 画笔工具 8 | 9 | ```python 10 | from imagepy.core.engine import Tool 11 | from skimage.draw import line, circle 12 | 13 | def drawline(img, oldp, newp, w, value): 14 | if img.ndim == 2: value = sum(value)/3 15 | oy, ox = line(*[int(round(i)) for i in oldp+newp]) 16 | cy, cx = circle(0, 0, w/2+1e-6) 17 | ys = (oy.reshape((-1,1))+cy).clip(0, img.shape[0]-1) 18 | xs = (ox.reshape((-1,1))+cx).clip(0, img.shape[1]-1) 19 | img[ys.ravel(), xs.ravel()] = value 20 | 21 | class Plugin(Tool): 22 | title = 'Pencil' 23 | 24 | para = {'width':1, 'value':(255, 255, 255)} 25 | view = [(int, 'width', (0,30), 0, 'width', 'pix'), 26 | ('color', 'value', 'color', '')] 27 | 28 | def __init__(self): 29 | self.status = False 30 | self.oldp = (0,0) 31 | 32 | def mouse_down(self, ips, x, y, btn, **key): 33 | self.status = True 34 | self.oldp = (y, x) 35 | ips.snapshot() 36 | 37 | def mouse_up(self, ips, x, y, btn, **key): 38 | self.status = False 39 | 40 | def mouse_move(self, ips, x, y, btn, **key): 41 | if not self.status:return 42 | w, value = self.para['width'], self.para['value'] 43 | drawline(ips.img, self.oldp, (y, x), w, value) 44 | self.oldp = (y, x) 45 | ips.update() 46 | 47 | def mouse_wheel(self, ips, x, y, d, **key):pass 48 | ``` 49 | 50 | 通过重载`mouse_down`, `mouse_up`, `mouse_move`方法,可以实现鼠标交互,这里我们实现一个最常见的画笔工具。鼠标按下时,标记`status`为`True`,在鼠标移动过程中进行绘图,并更新显示。 51 | 52 | ![14](http://idoc.imagepy.org/demoplugin/24.png) 53 | 54 |
画笔工具

55 | 56 | 57 | **Tool的加载方式** 58 | 59 | 1. 文件必须以`_tol.py`结尾,类名必须叫`Plugin`(一个文件只能实现一个工具) 60 | 2. 必须位于`tools`目录下的一级子菜单下 61 | 3. 需要配有一个同名的,16*16的gif文件用于工具栏图标 62 | 4. 单击即可选中,并作用与画布,如有配置参数,双击可进行设置 63 | 64 | 65 | ![14](http://idoc.imagepy.org/demoplugin/25.png) 66 | 67 |
Tool的加载

68 | 69 | ## Tool 的运行机制 70 | 71 | **title:** 标题 72 | 73 | **mouse_down:** `mouse_down(self, ips, x, y, btn, **key):` 鼠标按下时触发,`ips`是当前作用图像的`ImagePlus`封装类,可以通过`ips.img`获取当前图像,也可以`ips.lut`, `ips.roi`, `ips.unit`获取图像的索引表,roi,比例尺和单位等附加信息。x, y是当前鼠标在数据坐标系下的位置,`btn`触发事件的鼠标按键,0:无,1:左键,2:中键,3:右键。可以通过`key['alt']`, `key['ctrl']``, key['shift']`获取相应功能键是否按下,通过`key['canvas']`获取触发事件的`Canvas`对象。 74 | 75 | **mouse_up:** `mouse_up(self, ips, x, y, btn, **key):` 鼠标抬起时触发,具体参数与`mouse_down`相同。 76 | 77 | **mouse_move:** `mouse_move(self, ips, x, y, btn, **key):` 鼠标移动时触发,具体参数与`mouse_down`相同。 78 | 79 | **mouse_wheel(self, ips, x, y, btn, ******key):** 鼠标滚轮滚动时触发,具体参数与`mouse_down`相同。 80 | 81 | -------------------------------------------------------------------------------- /doc/chinese/widget.md: -------------------------------------------------------------------------------- 1 | # Widget 插件 2 | 3 | Widget插件加载为一块面板,其实是继承与`wx.Panel`的一个ui对象,这给了我们非常大的自由空间,但代价是,我们无法隔绝`UI`,必须直接编写`wxpython`代码。例如右侧的导航栏,鹰眼就是`widget`扩展出的,而之前见到过的宏录制器同样也是`widget`。 4 | 5 | 6 | 7 | ## 桌面组件演示 8 | 9 | ```python 10 | from imagepy import IPy 11 | import wx 12 | 13 | class Plugin ( wx.Panel ): 14 | title = 'Widget Demo' 15 | def __init__( self, parent ): 16 | wx.Panel.__init__ ( self, parent) 17 | sizer = wx.BoxSizer( wx.VERTICAL ) 18 | self.lable = wx.StaticText( self, wx.ID_ANY, 'This is a widgets demo') 19 | self.lable.Wrap( -1 ) 20 | sizer.Add( self.lable, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) 21 | self.btn_invert = wx.Button( self, wx.ID_ANY, 'Invert curent image') 22 | sizer.Add( self.btn_invert, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) 23 | 24 | self.SetSizer( sizer ) 25 | self.Layout() 26 | self.Fit() 27 | # Connect Events 28 | self.btn_invert.Bind( wx.EVT_BUTTON, self.on_invert) 29 | 30 | def on_invert(self, event): 31 | ips = IPy.get_ips() 32 | if ips is None: return 33 | ips.img[:] = 255-ips.img 34 | ips.update() 35 | ``` 36 | 37 | 由于`wxpython`的内容本身比较多,如有必要自己编写`widget`,那么免不了对`wxpython`进行系统性学习,这里仅仅给出一个最简单的例子。 38 | 39 | ![14](http://idoc.imagepy.org/demoplugin/27.png) 40 | 41 |
widget

42 | 43 | **widget的加载方式** 44 | 45 | 1. 文件必须以`_wgt.py`结尾,类名必须叫`Plugin`,继承于`wx.Panel`(一个文件只能实现一个widget) 46 | 2. 文件可以位于`widgets`目录下的一级子菜单内,启动时会按照层级加载到右侧组件栏。也可以位于menus或其子菜单下,当用户点击菜单时以浮动窗口形式加载面板。 47 | 48 | ![14](http://idoc.imagepy.org/demoplugin/26.png) 49 | 50 |
Widget Demo

51 | 52 | ## widget 的运行机制 53 | 54 | widgets本质上就是一个`wx.Panel`的子类,必须有`title`字段作为插件名称,其他的,就是`wxpython`编程,通过编写`UI`,添加事件实现,这里不做详细讨论。 55 | 56 | -------------------------------------------------------------------------------- /doc/chinese/workflow.md: -------------------------------------------------------------------------------- 1 | # Workflow 插件 2 | 3 | Macros是一系列的命令记录按顺序执行,而Workflow是Macros和Markdown的混合,同样规定了处理流程,但并不会自动顺序执行,而是每一步可以由用户自己调整参数,甚至过程中可以添加或跳过一些流程,此外每个过程开发者可以设定提示信息,宏是自动化流程,而工作流是向导作用,降低了自动化程度,但更具有指导作用。 4 | 5 | 6 | 7 | 8 | ## 硬币分割工作流 9 | 10 | ```markdown 11 | Coins Segment Workflow Demo 12 | =========================== 13 | ## Open Image 14 | 1. coins 15 | open the coins demo image,we will segment and measure it. 16 | ## Segment 17 | 1. Up And Down Watershed 18 | check "preview", slide to mark every coins red more or less, mark background green more or less, use "up area". 19 | ## Repair the mask 20 | 1. Fill Holes 21 | Fill the holes in the conis. 22 | 2. Geometry Filter 23 | check "preview", give "area" 100, small fragment less than 100 become dark, then give "back color" 0 to clear them. 24 | ## Measure 25 | 1. Geometry Analysis 26 | check the indecate we need, here check the "cov", count the cov ellipse. 27 | ## Export Result 28 | 1. CSV Save 29 | save the measure result as a csv file. 30 | ``` 31 | 32 | ![14](http://idoc.imagepy.org/demoplugin/11.png) 33 | 34 |
Workflow

35 | 36 | 我们在之前的硬币分割宏基础上编写工作流,按照markdown规范,加上必要的注释和章节,后缀为wf,保存到menus或其子文件夹下,加载时会是一个横向的分块面板,分为不同的章节,从左到右依次点击即可。鼠标放在每个小节会显示相应提示信息,点击右上角,可以浏览全部过程。 37 | 38 | ![14](http://idoc.imagepy.org/demoplugin/12.png) 39 | 40 |
Workflow Demo

41 | 42 | **工作流编写及加载方式** 43 | 44 | 1. 工作流是一个markdown格式的文件,后缀为wf 45 | 2. 前两行是主标题,解析成面板的主标题 46 | 3. 二级标题代表章,是一个功能分块,解析为一个矩形面板 47 | 4. 数字是要执行的命令,用数字序号开头,不带参数,解析为一个按钮 48 | 5. 每个命令下面都可以添加一行注释,当用户鼠标移动到某个按钮上,会展示其对应的说明 49 | 6. 可以拷贝到menus或其子菜单下,启动时被解析成菜单项 50 | 7. 也可以拖拽到ImagePy最下方的状态栏加载工作流 -------------------------------------------------------------------------------- /lang/Chinese/demoplugin.dic: -------------------------------------------------------------------------------- 1 | Demos::插件示例 2 | 3 | Start Here::从这里开始 4 | 5 | Hello World::你好,ImagePy 6 | Hello World, I am ImagePy!::你好,我是ImagePy! 7 | 8 | Who Are You::你是谁 9 | name::姓名 10 | please::请填写 11 | age::年龄 12 | years old::岁 13 | 14 | Questionnaire::调查问卷 15 | This is a questionnaire::这是一张调查问卷 16 | name::姓名 17 | please::请填写 18 | age::年龄 19 | years old::岁 20 | height::身高 21 | m::米 22 | kg::公斤 23 | do you like sport::你喜欢运动吗 24 | favourite::喜爱 25 | system::操作系统 26 | lanuage you like(multi)::你喜欢的操作系统(可多选) 27 | which::你喜欢的 28 | you like::颜色 29 | 30 | Markdown Demo::文档示例 31 | 32 | Macros Demo::宏示例 33 | 34 | Macros Gaussian Invert::高斯-反向 35 | 36 | Macros Coins Segment::硬币分割 37 | 38 | Workflow Demo::工作流示例 39 | 40 | Workflow Coins Demo::硬币分割 工作流 41 | 42 | Report Demo::报表示例 43 | 44 | Personal Information::个人信息 45 | 46 | Coins Report::硬币结果报表 47 | 48 | Filter Demo::Filter示例 49 | 50 | Gaussian Demo::高斯滤波示例 51 | 52 | Invert Demo::反向示例 53 | 54 | Simple Demo::Simple示例 55 | 56 | Gaussian 3D Demo::三维高斯滤波示例 57 | sigma::标准差 58 | pix::像素 59 | 60 | Set LUT Demo::设置颜色索引示例 61 | 62 | Inflate ROI Demo::扩张ROI示例 63 | radius::半径 64 | pix::像素 65 | 66 | Scale And Unit Demo::比例尺和单位示例 67 | scale::比例尺 68 | unit::单位 69 | 70 | Random Points Demo::随机点示例 71 | 72 | Table Demo::Table示例 73 | 74 | Student Score::学生成绩示例 75 | 76 | Table Sort Demo::表格排序示例 77 | item::项目 78 | 79 | Score Chart Demo::成绩图标示例 80 | select items::选择绘制项目 81 | 82 | Free Demo::Free示例 83 | 84 | New Image Demo::新建图像示例 85 | name::名称 86 | width::宽度 87 | height::高度 88 | pix::像素 89 | 90 | About Demo::关于对话框示例 91 | 92 | Exit Program Demo::退出程序示例 93 | 94 | DemoTool::示例 95 | 96 | Widget Demo::控件示例 97 | This is a widgets demo::这是一个控件示例 98 | Invert curent image::反向当前图像 -------------------------------------------------------------------------------- /menus/Demos/Filter Demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Filter Demo/__init__.py -------------------------------------------------------------------------------- /menus/Demos/Filter Demo/filtersdemo_plgs.py: -------------------------------------------------------------------------------- 1 | from imagepy.core.engine import Filter 2 | from scipy.ndimage import gaussian_filter 3 | 4 | class Invert(Filter): 5 | title = 'Invert Demo' 6 | note = ['all', 'auto_msk', 'auto_snap'] 7 | 8 | def run(self, ips, snap, img, para = None): 9 | return 255-snap 10 | 11 | class Gaussian(Filter): 12 | title = 'Gaussian Demo' 13 | note = ['all', 'auto_msk', 'auto_snap','preview'] 14 | para = {'sigma':2} 15 | view = [(float, 'sigma', (0,30), 1, 'sigma', 'pix')] 16 | 17 | def run(self, ips, snap, img, para = None): 18 | gaussian_filter(snap, para['sigma'], output=img) 19 | 20 | plgs = [Invert, Gaussian] -------------------------------------------------------------------------------- /menus/Demos/Free Demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Free Demo/__init__.py -------------------------------------------------------------------------------- /menus/Demos/Free Demo/freedemo_plgs.py: -------------------------------------------------------------------------------- 1 | from imagepy.core.engine import Free 2 | import numpy as np 3 | 4 | class NewImage(Free): 5 | title = 'New Image Demo' 6 | para = {'name':'new image','w':300, 'h':300} 7 | view = [(str, 'name', 'name',''), 8 | (int, 'w', (1,2048), 0, 'width', 'pix'), 9 | (int, 'h', (1,2048), 0, 'height', 'pix')] 10 | 11 | def run(self, para = None): 12 | imgs = [np.zeros((para['h'], para['w']), dtype=np.uint8)] 13 | self.app.show_img(imgs, para['name']) 14 | 15 | class About(Free): 16 | title = 'About Demo' 17 | 18 | def run(self, para=None): 19 | self.app.alert('ImagePy v0.2') 20 | 21 | class Close(Free): 22 | title = 'Exit Program Demo' 23 | asyn = False 24 | 25 | def run(self, para = None): 26 | self.app.Close() 27 | 28 | plgs = [NewImage, About, Close] -------------------------------------------------------------------------------- /menus/Demos/Macros Demo/Macros Coins Segment.mc: -------------------------------------------------------------------------------- 1 | coins>None 2 | Up And Down Watershed>{'thr1': 36, 'thr2': 169, 'type': 'up area'} 3 | Fill Holes>None 4 | Geometry Filter>{'con': '4-connect', 'inv': False, 'area': 100.0, 'l': 0.0, 'holes': 0, 'solid': 0.0, 'e': 0.0, 'front': 255, 'back': 0} 5 | Geometry Analysis>{'con': '8-connect', 'center': True, 'area': True, 'l': True, 'extent': False, 'cov': True, 'slice': False, 'ed': False, 'holes': False, 'ca': False, 'fa': False, 'solid': False} -------------------------------------------------------------------------------- /menus/Demos/Macros Demo/Macros Gaussian Invert.mc: -------------------------------------------------------------------------------- 1 | Gaussian>{'sigma':8.0} 2 | Invert>None -------------------------------------------------------------------------------- /menus/Demos/Macros Demo/__init__.py: -------------------------------------------------------------------------------- 1 | catlog = ['Macros Gaussian Invert', 'Macros Coins Segment'] -------------------------------------------------------------------------------- /menus/Demos/Markdown Demo/MarkDown Demo.md: -------------------------------------------------------------------------------- 1 | # Markdown Demo 2 | This is a Mark Down Demo -------------------------------------------------------------------------------- /menus/Demos/Markdown Demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Markdown Demo/__init__.py -------------------------------------------------------------------------------- /menus/Demos/Report Demo/Coins Report.rpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Report Demo/Coins Report.rpt -------------------------------------------------------------------------------- /menus/Demos/Report Demo/Personal Information.rpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Report Demo/Personal Information.rpt -------------------------------------------------------------------------------- /menus/Demos/Report Demo/__init__.py: -------------------------------------------------------------------------------- 1 | catlog = ['Personal Information', 'Coins Report'] -------------------------------------------------------------------------------- /menus/Demos/Simple Demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Simple Demo/__init__.py -------------------------------------------------------------------------------- /menus/Demos/Simple Demo/simpledemo_plgs.py: -------------------------------------------------------------------------------- 1 | from imagepy.core.engine import Simple 2 | from sciapp.object import ROI, mark2shp, geom2shp, geom_flatten 3 | import scipy.ndimage as ndimg 4 | import numpy as np 5 | 6 | class Gaussian3D(Simple): 7 | title = 'Gaussian 3D Demo' 8 | note = ['all', 'stack3d'] 9 | 10 | para = {'sigma':2} 11 | view = [(float, 'sigma', (0,30), 1, 'sigma', 'pix')] 12 | 13 | def run(self, ips, imgs, para = None): 14 | imgs[:] = ndimg.gaussian_filter(imgs, para['sigma']) 15 | 16 | class SetLUT(Simple): 17 | title = 'Set LUT Demo' 18 | note = ['8-bit'] 19 | para = {'lut':'red'} 20 | view = [(list, 'lut', ['red', 'green', 'blue'], str, 'look up', 'table')] 21 | 22 | def run(self, ips, imgs, para = None): 23 | cmap = [[i==para['lut']] for i in ['red', 'green', 'blue']] 24 | ips.lut = (cmap*np.arange(256)).astype(np.uint8).T 25 | 26 | class Inflate(Simple): 27 | title = 'Inflate ROI Demo' 28 | note = ['all', 'req_roi'] 29 | para = {'r':5} 30 | view = [(int, 'r', (1,100),0, 'radius', 'pix')] 31 | 32 | def run(self, ips, imgs, para = None): 33 | geom = ips.roi.to_geom().buffer(para['r']) 34 | ips.roi = ROI(geom2shp(geom_flatten(geom))) 35 | 36 | class Unit(Simple): 37 | title = 'Scale And Unit Demo' 38 | note = ['all'] 39 | para = {'scale':1, 'unit':'mm'} 40 | view = [(float, 'scale', (1e-3,1e3), 3, 'scale', ''), 41 | (str, 'unit', 'unit', '')] 42 | 43 | def run(self, ips, imgs, para = None): 44 | ips.unit = (para['scale'], para['unit']) 45 | 46 | class Mark(Simple): 47 | title = 'Random Points Demo' 48 | note = ['all'] 49 | 50 | def run(self, ips, imgs, para = None): 51 | pts = (np.random.rand(200)*512).reshape((100,2)) 52 | ips.mark = mark2shp({'type':'points', 'color':(255,0,0), 'lw':1, 'body':pts}) 53 | 54 | plgs = [Gaussian3D, SetLUT, Inflate, Unit, Mark] -------------------------------------------------------------------------------- /menus/Demos/Start Here/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Start Here/__init__.py -------------------------------------------------------------------------------- /menus/Demos/Start Here/start_plg.py: -------------------------------------------------------------------------------- 1 | from imagepy.core.engine import Free 2 | 3 | class HelloWorld(Free): 4 | title = 'Hello World' 5 | 6 | def run(self, para=None): 7 | self.app.alert('Hello World, I am ImagePy!') 8 | 9 | class WhoAreYou(Free): 10 | title = 'Who Are You' 11 | para = {'name':'', 'age':0} 12 | view = [(str, 'name', 'name', 'please'), 13 | (int, 'age', (0,120), 0, 'age', 'years old')] 14 | 15 | def run(self, para=None): 16 | self.app.alert('Name:\t%s\r\nAge:\t%d'%(para['name'], para['age'])) 17 | 18 | class Questionnaire(Free): 19 | title = 'Questionnaire' 20 | 21 | para = {'name':'yxdragon', 'age':10, 'h':1.72, 'w':70, 'sport':True, 'sys':'Mac', 'lan':['C/C++', 'Python'], 'c':(255,0,0)} 22 | 23 | view = [('lab', 'lab', 'This is a questionnaire'), # 标签 24 | (str, 'name', 'name', 'please'), # 字符 25 | (int, 'age', (0,150), 0, 'age', 'years old'), # 整数 26 | (float, 'h', (0.3, 2.5), 2, 'height', 'm'), # 浮点 27 | ('slide', 'w', (1, 150), 0, 'kg'), # 滑块 28 | (bool, 'sport', 'do you like sport'), # 勾选 29 | (list, 'sys', ['Windows','Mac','Linux'], str, 'favourite', 'system'), # 单选 30 | ('chos', 'lan', ['C/C++','Java','Python'], 'lanuage you like(multi)'), # 多选 31 | ('color', 'c', 'which', 'you like')] # 颜色 32 | 33 | def run(self, para=None): 34 | rst = ['Questionnaire Result', 35 | 'Name:%s'%para['name'], 36 | 'Age:%s'%para['age'], 37 | 'Height:%sm'%para['h'], 38 | 'Weight:%skg'%para['w'], 39 | 'Like Sport:%s'%para['sport'], 40 | 'Favourite System:%s'%para['sys'], 41 | 'Like lanuage:%s'%para['lan'], 42 | 'Favourite Color:%s'%str(para['c'])] 43 | 44 | self.app.alert('\r\n'.join(rst)) 45 | 46 | plgs = [HelloWorld, WhoAreYou, Questionnaire] -------------------------------------------------------------------------------- /menus/Demos/Table Demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Table Demo/__init__.py -------------------------------------------------------------------------------- /menus/Demos/Table Demo/tabledemo_plg.py: -------------------------------------------------------------------------------- 1 | from imagepy.core.engine import Free, Table 2 | import numpy as np 3 | import pandas as pd 4 | 5 | class Score(Free): 6 | title = 'Student Score' 7 | 8 | def run(self, para=None): 9 | index = ['Stutent%s'%i for i in range(1,6)] 10 | columns = ['Math', 'Physics', 'Biology', 'History'] 11 | score = (np.random.rand(20)*40+60).reshape((5,4)).astype(np.uint8) 12 | self.app.show_table(pd.DataFrame(score, index, columns), 'Scores') 13 | 14 | class Sort(Table): 15 | title = 'Table Sort Demo' 16 | 17 | para = {'by':'Math'} 18 | view = [('field', 'by', 'item', '')] 19 | 20 | def run(self, tps, snap, data, para=None): 21 | tps.data.sort_values(by=para['by'], inplace=True) 22 | 23 | class Bar(Table): 24 | title = 'Score Chart Demo' 25 | asyn = False 26 | 27 | para = {'item':[]} 28 | view = [('fields', 'item', 'select items')] 29 | 30 | def run(self, tps, snap, data, para = None): 31 | plt = self.app.show_plot('Score Chart') 32 | data[para['item']].plot.bar(stacked=True, grid=True, 33 | title='Score Chart', ax=plt.add_subplot()) 34 | plt.Show() 35 | 36 | plgs = [Score, Sort, Bar] -------------------------------------------------------------------------------- /menus/Demos/Widget Demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Widget Demo/__init__.py -------------------------------------------------------------------------------- /menus/Demos/Widget Demo/widgetdemo_wgt.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | class Plugin ( wx.Panel ): 4 | title = 'Widget Demo' 5 | def __init__( self, parent, app=None): 6 | wx.Panel.__init__ ( self, parent) 7 | self.app = app 8 | sizer = wx.BoxSizer( wx.VERTICAL ) 9 | self.lable = wx.StaticText( self, wx.ID_ANY, 'This is a widgets demo') 10 | self.lable.Wrap( -1 ) 11 | sizer.Add( self.lable, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) 12 | self.btn_invert = wx.Button( self, wx.ID_ANY, 'Invert curent image') 13 | sizer.Add( self.btn_invert, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) 14 | 15 | self.SetSizer( sizer ) 16 | self.Layout() 17 | self.Fit() 18 | self.btn_invert.Bind( wx.EVT_BUTTON, self.on_invert) 19 | 20 | def on_invert(self, event): 21 | ips = self.app.get_img() 22 | if ips is None: return 23 | ips.img[:] = 255-ips.img 24 | ips.update() -------------------------------------------------------------------------------- /menus/Demos/Workflow Demo/Workflow Coins Demo.wf: -------------------------------------------------------------------------------- 1 | Coins Segment Workflow Demo 2 | =========================== 3 | ## Open Image 4 | 1. coins 5 | open the coins demo image,we will segment and measure it. 6 | ## Segment 7 | 1. Up And Down Watershed 8 | check "preview", slide to mark every coins red more or less, mark background green more or less, use "up area". 9 | ## Repair the mask 10 | 1. Fill Holes 11 | Fill the holes in the conis. 12 | 2. Geometry Filter 13 | check "preview", give "area" 100, small fragment less than 100 become dark, then give "back color" 0 to clear them. 14 | ## Measure 15 | 1. Geometry Analysis 16 | check the indecate we need, here check the "cov", count the cov ellipse. 17 | ## Export Result 18 | 1. CSV Save 19 | save the measure result as a csv file. 20 | 2. Coins Report 21 | generate result report. -------------------------------------------------------------------------------- /menus/Demos/Workflow Demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/Demos/Workflow Demo/__init__.py -------------------------------------------------------------------------------- /menus/Demos/__init__.py: -------------------------------------------------------------------------------- 1 | catlog = ['Start Here', '-', 'Markdown Demo', 'Macros Demo', 'Workflow Demo', 'Report Demo', '-', 'Filter Demo', 'Simple Demo', 'Table Demo', 'Free Demo', '-', 'WidgetDemo'] -------------------------------------------------------------------------------- /menus/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/menus/__init__.py -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/requirements.txt -------------------------------------------------------------------------------- /tools/DemoTool/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/tools/DemoTool/__init__.py -------------------------------------------------------------------------------- /tools/DemoTool/tooldemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/tools/DemoTool/tooldemo.gif -------------------------------------------------------------------------------- /tools/DemoTool/tooldemo_tol.py: -------------------------------------------------------------------------------- 1 | from sciapp.action import Tool 2 | from skimage.draw import line, circle 3 | 4 | def drawline(img, oldp, newp, w, value): 5 | if img.ndim == 2: value = sum(value)/3 6 | oy, ox = line(*[int(round(i)) for i in oldp+newp]) 7 | cy, cx = circle(0, 0, w/2+1e-6) 8 | ys = (oy.reshape((-1,1))+cy).clip(0, img.shape[0]-1) 9 | xs = (ox.reshape((-1,1))+cx).clip(0, img.shape[1]-1) 10 | img[ys.ravel(), xs.ravel()] = value 11 | 12 | class Plugin(Tool): 13 | title = 'Pencil Demo' 14 | 15 | para = {'width':1, 'value':(255, 255, 255)} 16 | view = [(int, 'width', (0,30), 0, 'width', 'pix'), 17 | ('color', 'value', 'color', '')] 18 | 19 | def __init__(self): 20 | self.status = False 21 | self.oldp = (0,0) 22 | 23 | def mouse_down(self, ips, x, y, btn, **key): 24 | self.status = True 25 | self.oldp = (y, x) 26 | ips.snapshot() 27 | 28 | def mouse_up(self, ips, x, y, btn, **key): 29 | self.status = False 30 | 31 | def mouse_move(self, ips, x, y, btn, **key): 32 | if not self.status:return 33 | w, value = self.para['width'], self.para['value'] 34 | drawline(ips.img, self.oldp, (y, x), w, value) 35 | self.oldp = (y, x) 36 | ips.update() 37 | 38 | def mouse_wheel(self, ips, x, y, d, **key):pass -------------------------------------------------------------------------------- /tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/tools/__init__.py -------------------------------------------------------------------------------- /widgets/DemoWidgets/widgetdemo_wgt.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | class Plugin ( wx.Panel ): 4 | title = 'Widget Demo' 5 | def __init__( self, parent, app=None): 6 | wx.Panel.__init__ ( self, parent) 7 | self.app = app 8 | sizer = wx.BoxSizer( wx.VERTICAL ) 9 | self.lable = wx.StaticText( self, wx.ID_ANY, 'This is a widgets demo') 10 | self.lable.Wrap( -1 ) 11 | sizer.Add( self.lable, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) 12 | self.btn_invert = wx.Button( self, wx.ID_ANY, 'Invert curent image') 13 | sizer.Add( self.btn_invert, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) 14 | 15 | self.SetSizer( sizer ) 16 | self.Layout() 17 | self.Fit() 18 | self.btn_invert.Bind( wx.EVT_BUTTON, self.on_invert) 19 | 20 | def on_invert(self, event): 21 | ips = self.app.get_img() 22 | if ips is None: return 23 | ips.img[:] = 255-ips.img 24 | ips.update() -------------------------------------------------------------------------------- /widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Image-Py/demoplugin/26e576a12fa757e8a12897e04e04e02bdcb8277f/widgets/__init__.py --------------------------------------------------------------------------------