├── .gitignore ├── .travis.yml ├── LICENSE.md ├── Makefile ├── README.md ├── _init_path.py ├── build-tools ├── .gitignore ├── build-ubuntu-binary.sh ├── build-windows-binary.sh └── envsetup.sh ├── contributors.txt ├── data └── predefined_classes.txt ├── demo ├── demo.png └── demo2.png ├── icons ├── cancel.png ├── close.png ├── color.png ├── color_line.png ├── copy.png ├── delete.png ├── done.png ├── done.svg ├── edit.png ├── expert1.png ├── expert2.png ├── eye.png ├── feBlend-icon.png ├── file.png ├── fit-width.png ├── fit-window.png ├── fit.png ├── help.png ├── labels.png ├── labels.svg ├── new.png ├── next.png ├── objects.png ├── open.png ├── open.svg ├── prev.png ├── quit.png ├── save-as.png ├── save-as.svg ├── save.png ├── save.svg ├── undo-cross.png ├── undo.png ├── zoom-in.png ├── zoom-out.png └── zoom.png ├── labelImg.py ├── libs ├── canvas.py ├── colorDialog.py ├── labelDialog.py ├── labelFile.py ├── lib.py ├── pascal_voc_io.py ├── shape.py ├── toolBar.py └── zoomWidget.py ├── read_xml.py ├── read_xml_correct_rotation.py ├── read_xml_correct_rotation_left.py ├── resources.qrc ├── rotation_opencv_fasterRCNN.py ├── rotation_opencv_fasterRCNN_correct_rotation.py └── tests ├── test.bmp ├── test.py └── 臉書.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | icons/.DS_Store 2 | 3 | resources.py 4 | 5 | *.pyc 6 | .*.swp 7 | 8 | build/ 9 | dist/ 10 | 11 | tags 12 | cscope* 13 | .ycm_extra_conf.py 14 | .subvimrc 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # vim: set ts=2 et: 2 | 3 | # run xvfb with 32-bit color 4 | # xvfb-run -s '-screen 0 1600x1200x24+32' command_goes_here 5 | 6 | matrix: 7 | include: 8 | 9 | # Python 2.7 + QT4 10 | - os: linux 11 | dist: trusty 12 | sudo: required 13 | language: generic 14 | python: "2.7" 15 | env: 16 | - QT=4 17 | addons: 18 | apt: 19 | packages: 20 | - cmake 21 | - python-qt4 22 | - pyqt4-dev-tools 23 | - xvfb 24 | before_install: 25 | - sudo pip install lxml 26 | - make qt4py2 27 | - xvfb-run make testpy2 28 | 29 | # Python 2.7 + QT4 30 | - os: linux 31 | dist: trusty 32 | sudo: required 33 | language: generic 34 | python: "2.7" 35 | env: 36 | - QT=4 37 | - CONDA=4.2.0 38 | addons: 39 | apt: 40 | packages: 41 | - cmake 42 | #- python-qt4 43 | #- pyqt4-dev-tools 44 | - xvfb 45 | before_install: 46 | # ref: https://www.continuum.io/downloads 47 | - curl -O https://repo.continuum.io/archive/Anaconda2-4.2.0-Linux-x86_64.sh 48 | # ref: http://conda.pydata.org/docs/help/silent.html 49 | - /bin/bash Anaconda2-4.2.0-Linux-x86_64.sh -b -p $HOME/anaconda2 50 | - export PATH="$HOME/anaconda2/bin:$PATH" 51 | # ref: http://stackoverflow.com/questions/21637922/how-to-install-pyqt4-in-anaconda 52 | - conda create -y -n labelImg-py2qt4 python=2.7 53 | - source activate labelImg-py2qt4 54 | - conda install -y pyqt=4 55 | - conda install -y lxml 56 | - make qt4py2 57 | - xvfb-run make testpy2 58 | 59 | # Python 2 + QT5 60 | # disabled; can't get it to work 61 | #- os: linux 62 | # dist: trusty 63 | # sudo: required 64 | # language: generic 65 | # python: "2.7" 66 | # env: 67 | # - QT=5 68 | # addons: 69 | # apt: 70 | # packages: 71 | # - cmake 72 | # - pyqt5-dev-tools 73 | # - xvfb 74 | # before_install: 75 | # - sudo apt-get update 76 | # - sudo apt-get install -y python-pip 77 | # - sudo pip install lxml 78 | # - pyrcc5 --help || true # does QT5 support python2 out of the box? 79 | # - make qt5py3 80 | # - xvfb-run make testpy2 81 | 82 | # Python 3 + QT4 83 | - os: linux 84 | dist: trusty 85 | sudo: required 86 | language: generic 87 | python: "3.5" 88 | env: 89 | - QT=4 90 | addons: 91 | apt: 92 | packages: 93 | - cmake 94 | - python3-pyqt4 95 | - pyqt4-dev-tools 96 | - xvfb 97 | before_install: 98 | - sudo apt-get update 99 | - sudo apt-get install -y python3-pip 100 | - sudo pip3 install lxml 101 | - make qt4py3 102 | - xvfb-run make testpy3 103 | 104 | # Python 3 + QT5 105 | - os: linux 106 | dist: trusty 107 | sudo: required 108 | language: generic 109 | python: "3.5" 110 | env: 111 | - QT=5 112 | addons: 113 | apt: 114 | packages: 115 | - cmake 116 | - pyqt5-dev-tools 117 | - xvfb 118 | before_install: 119 | - sudo apt-get update 120 | - sudo apt-get install -y python3-pip 121 | - sudo pip3 install lxml 122 | - make qt5py3 123 | - xvfb-run make testpy3 124 | 125 | # Python 3 + QT5 126 | - os: linux 127 | dist: trusty 128 | sudo: required 129 | language: generic 130 | python: "3.5" 131 | env: 132 | - QT=5 133 | - CONDA=4.2.0 134 | addons: 135 | apt: 136 | packages: 137 | - cmake 138 | - xvfb 139 | before_install: 140 | # ref: https://www.continuum.io/downloads 141 | - curl -O https://repo.continuum.io/archive/Anaconda3-4.2.0-Linux-x86_64.sh 142 | # ref: http://conda.pydata.org/docs/help/silent.html 143 | - /bin/bash Anaconda3-4.2.0-Linux-x86_64.sh -b -p $HOME/anaconda3 144 | - export PATH="$HOME/anaconda3/bin:$PATH" 145 | # ref: http://stackoverflow.com/questions/21637922/how-to-install-pyqt4-in-anaconda 146 | - conda create -y -n labelImg-py3qt5 python=3.5 147 | - source activate labelImg-py3qt5 148 | - conda install -y pyqt=5 149 | - conda install -y lxml 150 | - make qt5py3 151 | - xvfb-run make testpy3 152 | 153 | # OS X 10.10 Python 3 + QT5 154 | - os: osx 155 | osx_image: xcode6.4 # Xcode 6.4, OS X 10.10 156 | sudo: required 157 | language: generic 158 | python: "3.6" 159 | env: 160 | - QT=5 161 | before_install: 162 | #- brew update 163 | - brew install libxml2 164 | - brew install pyqt5 165 | - which python3 pip3 166 | - python3 --version 167 | #- sudo -H pip3 install --user --upgrade lxml # pyqt5 installs python3.x, which installs pip3 168 | - sudo -H easy_install-3.6 lxml || true 169 | - python3 -c 'import sys; print(sys.path)' 170 | - python3 -c 'import lxml' 171 | - make qt5py3 172 | - python3 -c 'help("modules")' 173 | - make testpy3 # FIXME: does not work, segfault on travis-ci 174 | 175 | # OS X 10.11 Python 3 + QT5 176 | - os: osx 177 | osx_image: xcode8 # Xcode 8, OS X 10.11 178 | sudo: required 179 | language: generic 180 | python: "3.6" 181 | env: 182 | - QT=5 183 | before_install: 184 | #- brew update 185 | - brew install libxml2 186 | - brew install pyqt5 187 | - which python3 pip3 188 | - python3 --version 189 | #- sudo -H pip3 install --user --upgrade lxml # pyqt5 installs python3.x, which installs pip3 190 | - sudo -H easy_install-3.6 lxml || true 191 | - python3 -c 'import sys; print(sys.path)' 192 | - python3 -c 'import lxml' 193 | - make qt5py3 194 | - python3 -c 'help("modules")' 195 | - make testpy3 # FIXME: does not work, segfault on travis-ci 196 | 197 | # OS X 10.12 Python 3 + QT5 198 | - os: osx 199 | osx_image: xcode8.2 # OS X 10.12 200 | sudo: required 201 | language: generic 202 | python: "3.6" 203 | env: 204 | - QT=5 205 | before_install: 206 | #- brew update 207 | - brew install libxml2 208 | - brew install pyqt5 209 | - which python3 pip3 210 | - python3 --version 211 | #- sudo -H pip3 install --user --upgrade lxml # pyqt5 installs python3.x, which installs pip3 212 | - sudo -H easy_install-3.6 lxml || true 213 | - python3 -c 'import sys; print(sys.path)' 214 | - python3 -c 'import lxml' 215 | - make qt5py3 216 | - python3 -c 'help("modules")' 217 | #- make testpy3 # FIXME: does not work, segfault on travis-ci 218 | # just make sure the app runs... :-/ 219 | - ( python3 labelImg.py ) & sleep 10; kill $! 220 | 221 | # XXX: building QT4 from source takes forever... 222 | 223 | # OS X 10.11 Python 2 + QT4 224 | #- os: osx 225 | # osx_image: xcode7.3 # OS X 10.11 226 | # sudo: required 227 | # language: generic 228 | # python: "2.7" 229 | # env: 230 | # - QT=4 231 | # before_install: 232 | # - brew install libxml2 233 | # # build PyQT4... 234 | # - curl -L -O https://sourceforge.net/projects/pyqt/files/sip/sip-4.19/sip-4.19.tar.gz 235 | # - tar zxvf sip-4.19.tar.gz 236 | # - (cd sip-4.19 && python configure.py -d /Library/Python/2.7/site-packages --arch x86_64 && make && sudo make install) 237 | # # NOTE: produces insane amounts of output... 238 | # - brew install -v cartr/qt4/qt --with-qt3support --without-webkit | sed -e's/ .* / ... /' 239 | # - brew linkapps qt 240 | # - curl -L -O http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.12/PyQt4_gpl_mac-4.12.tar.gz 241 | # - tar zxvf PyQt4_gpl_mac-4.12.tar.gz 242 | # - cd PyQt4_gpl_mac-4.12 243 | # - python configure.py --help 244 | # - python configure.py -d /Library/Python/2.7/site-packages --use-arch=x86_64 --confirm-license 245 | # - make 246 | # - sudo make install 247 | # - cd - 248 | # - which python pip 249 | # - python --version 250 | # - sudo -H easy_install-2.7 lxml || true 251 | # - python -c 'import sys; print(sys.path)' 252 | # - python -c 'import lxml' 253 | # - make qt4py2 254 | # - python -c 'help("modules")' 255 | # - make testpy2 256 | 257 | # OS X 10.11 Python 3 + QT4 258 | #- os: osx 259 | # osx_image: xcode7.3 # OS X 10.11 260 | # sudo: required 261 | # language: generic 262 | # python: "3.6" 263 | # env: 264 | # - QT=4 265 | # before_install: 266 | # - brew install libxml2 267 | # - brew install python3 268 | # - which python pip python3 pip3 || true 269 | # - curl -L -O https://sourceforge.net/projects/pyqt/files/sip/sip-4.19/sip-4.19.tar.gz 270 | # - tar zxvf sip-4.19.tar.gz 271 | # - ( cd sip-4.19 && python3 configure.py -d /Library/Python/3.6/site-packages --arch x86_64 && make && sudo make install ) 272 | # # NOTE: produces insane amounts of output... 273 | # - brew install -v cartr/qt4/qt --with-qt3support --without-webkit | sed -e's/ .* / ... /' 274 | # - brew linkapps qt 275 | # - curl -L -O http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.12/PyQt4_gpl_mac-4.12.tar.gz 276 | # - tar zxvf PyQt4_gpl_mac-4.12.tar.gz 277 | # - cd PyQt4_gpl_mac-4.12 278 | # - python3 configure.py --help 279 | # - python3 configure.py -d /Library/Python/3.6/site-packages --use-arch=x86_64 --confirm-license 280 | # - make 281 | # - sudo make install 282 | # - cd - 283 | # - which python3 pip3 284 | # - python3 --version 285 | # - sudo -H easy_install-3.6 lxml || true 286 | # - python3 -c 'import sys; print(sys.path)' 287 | # - python3 -c 'import lxml' 288 | # - make qt4py3 289 | # - python3 -c 'help("modules")' 290 | # - make testpy3 291 | 292 | script: 293 | - exit 0 294 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) <2015-2016> Tzutalin 2 | 3 | Copyright (C) 2013 MIT, Computer Science and Artificial Intelligence Laboratory. Bryan Russell, Antonio Torralba, William T. Freeman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ex: set ts=8 noet: 2 | 3 | all: qt4 4 | 5 | test: testpy2 6 | 7 | testpy2: 8 | python -m unittest discover tests 9 | 10 | testpy3: 11 | python3 -m unittest discover tests 12 | 13 | qt4: qt4py2 14 | 15 | qt5: qt4py3 16 | 17 | qt4py2: 18 | pyrcc4 -py2 -o resources.py resources.qrc 19 | 20 | qt4py3: 21 | pyrcc4 -py3 -o resources.py resources.qrc 22 | 23 | qt5py3: 24 | pyrcc5 -o resources.py resources.qrc 25 | 26 | .PHONY: test 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LabelImg 2 | 3 | [![Build Status](https://travis-ci.org/tzutalin/labelImg.png)](https://travis-ci.org/tzutalin/labelImg) 4 | 5 | LabelImg is a graphical image annotation tool. 6 | 7 | It is written in Python and uses Qt for its graphical interface. 8 | 9 | The annotation file will be saved as an XML file. The annotation format is PASCAL VOC format, and the format is the same as [ImageNet](http://www.image-net.org/) 10 | 11 | ![](demo/demo.png) 12 | 13 | ![](demo/demo2.png) 14 | 15 | [![Demo video](https://j.gifs.com/4xy9z2.gif)](https://www.youtube.com/watch?v=p0nR2YsCY_U&feature=youtu.be) 16 | 17 | ## Build source and use it 18 | 19 | Linux/Ubuntu/Mac requires at least [Python 2.6](http://www.python.org/getit/) and has been tested with [PyQt 20 | 4.8](http://www.riverbankcomputing.co.uk/software/pyqt/intro). 21 | 22 | In order to build the resource and assets, you need to install pyqt4-dev-tools and lxml: 23 | 24 | ### Ubuntu 25 | 26 | sudo apt-get install pyqt4-dev-tools 27 | sudo pip install lxml 28 | make all 29 | ./labelImg.py 30 | 31 | ### OS X 32 | 33 | brew install qt qt4 34 | brew install libxml2 35 | make all 36 | ./labelImg.py 37 | 38 | ### Windows 39 | 40 | Need to download and setup [Python 2.6](https://www.python.org/downloads/windows/) or later and [PyQt4](https://www.riverbankcomputing.com/software/pyqt/download). Also, you need to install lxml. 41 | 42 | Open cmd and go to [labelImg] 43 | 44 | pyrcc4 -o resources.py resources.qrc 45 | python labelImg.py 46 | 47 | 48 | ## Download the prebuilt binary directly 49 | [http://tzutalin.github.io/labelImg/](http://tzutalin.github.io/labelImg/). However, there are only prebuilt binaries for Windows and Linux because I don't have Mac OS to do that. If someone can help me to write a script to build binary for Mac OS, I will appreciate that. 50 | 51 | ## Usage 52 | After cloning the code, you should run `$ make all` to generate the resource file. 53 | 54 | You can then start annotating by running `$ ./labelImg.py`. For usage 55 | instructions you can see [Here](https://youtu.be/p0nR2YsCY_U) 56 | 57 | At the moment annotations are saved as an XML file. The format is PASCAL VOC format, and the format is the same as [ImageNet](http://www.image-net.org/) 58 | 59 | You can also see [ImageNet Utils](https://github.com/tzutalin/ImageNet_Utils) to download image, create a label text for machine learning, etc 60 | 61 | 62 | ### General steps from scratch 63 | 64 | * Build and launch: `$ make all; python labelImg.py` 65 | 66 | * Click 'Change default saved annotation folder' in Menu/File 67 | 68 | * Click 'Open Dir' 69 | 70 | * Click 'Create RectBox' 71 | 72 | The annotation will be saved to the folder you specify 73 | 74 | ### Create pre-defined classes 75 | 76 | You can edit the [data/predefined_classes.txt](https://github.com/tzutalin/labelImg/blob/master/data/predefined_classes.txt) to load pre-defined classes 77 | 78 | ### Hotkeys 79 | 80 | * Ctrl + r : Change the defult target dir which saving annotation files 81 | 82 | * Ctrl + s : Save 83 | 84 | * w : Create a bounding box 85 | 86 | * d : Next image 87 | 88 | * a : Previous image 89 | 90 | ### How to contribute 91 | Send a pull request 92 | 93 | ### License 94 | [License](LICENSE.md) 95 | 96 | -------------------------------------------------------------------------------- /_init_path.py: -------------------------------------------------------------------------------- 1 | """Set up paths""" 2 | import sys 3 | 4 | def add_path(path): 5 | if path not in sys.path: 6 | sys.path.insert(0, path) 7 | 8 | add_path('libs') 9 | -------------------------------------------------------------------------------- /build-tools/.gitignore: -------------------------------------------------------------------------------- 1 | *.spec 2 | build 3 | dist 4 | pyinstaller 5 | python-2.* 6 | pywin32* 7 | virtual-wine 8 | venv_wine 9 | PyQt4-* 10 | lxml-* 11 | -------------------------------------------------------------------------------- /build-tools/build-ubuntu-binary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### Ubuntu use pyinstall v3.0 3 | THIS_SCRIPT_PATH=`readlink -f $0` 4 | THIS_SCRIPT_DIR=`dirname ${THIS_SCRIPT_PATH}` 5 | cd pyinstaller 6 | git checkout v3.2 7 | cd ${THIS_SCRIPT_DIR} 8 | 9 | rm -r build 10 | rm -r dist 11 | rm labelImg.spec 12 | python pyinstaller/pyinstaller.py --hidden-import=xml \ 13 | --hidden-import=xml.etree \ 14 | --hidden-import=xml.etree.ElementTree \ 15 | --hidden-import=lxml.etree \ 16 | -D -F -n labelImg -c "../labelImg.py" -p ../libs 17 | 18 | FOLDER=$(git describe --abbrev=0 --tags) 19 | FOLDER="linux_"$FOLDER 20 | rm -rf "$FOLDER" 21 | mkdir "$FOLDER" 22 | cp dist/labelImg $FOLDER 23 | cp -rf ../data $FOLDER/data 24 | zip "$FOLDER.zip" -r $FOLDER 25 | -------------------------------------------------------------------------------- /build-tools/build-windows-binary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### Window requires pyinstall v2.1 3 | THIS_SCRIPT_PATH=`readlink -f $0` 4 | THIS_SCRIPT_DIR=`dirname ${THIS_SCRIPT_PATH}` 5 | cd pyinstaller 6 | git checkout v2.1 7 | cd ${THIS_SCRIPT_DIR} 8 | 9 | . venv_wine/bin/activate 10 | rm -r build 11 | rm -r dist 12 | rm labelImg.spec 13 | wine c:/Python27/python.exe pyinstaller/pyinstaller.py --hidden-import=xml \ 14 | --hidden-import=xml.etree \ 15 | --hidden-import=xml.etree.ElementTree \ 16 | --hidden-import=lxml.etree \ 17 | -D -F -n labelImg -c "../labelImg.py" -p ../libs 18 | 19 | FOLDER=$(git describe --abbrev=0 --tags) 20 | FOLDER="windows_"$FOLDER 21 | rm -rf "$FOLDER" 22 | mkdir "$FOLDER" 23 | cp dist/labelImg.exe $FOLDER 24 | cp -rf ../data $FOLDER/data 25 | zip "$FOLDER.zip" -r $FOLDER 26 | -------------------------------------------------------------------------------- /build-tools/envsetup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | THIS_SCRIPT_PATH=`readlink -f $0` 4 | THIS_SCRIPT_DIR=`dirname ${THIS_SCRIPT_PATH}` 5 | #OS Ubuntu 14.04 6 | ### Common packages for linux/windows 7 | if [ ! -e "pyinstaller" ]; then 8 | git clone https://github.com/pyinstaller/pyinstaller 9 | cd pyinstaller 10 | git checkout v2.1 -b v2.1 11 | cd ${THIS_SCRIPT_DIR} 12 | fi 13 | 14 | echo "Going to clone and download packages for building windows" 15 | #Pacakges 16 | #> pyinstaller (2.1) 17 | #> wine (1.6.2) 18 | #> virtual-wine (0.1) 19 | #> python-2.7.8.msi 20 | #> pywin32-218.win32-py2.7.exe 21 | 22 | ## tool to install on Ubuntu 23 | #$ sudo apt-get install wine 24 | 25 | ### Clone a repo to create virtual wine env 26 | if [ ! -e "virtual-wine" ]; then 27 | git clone https://github.com/htgoebel/virtual-wine.git 28 | fi 29 | 30 | apt-get install scons 31 | ### Create virtual env 32 | rm -rf venv_wine 33 | ./virtual-wine/vwine-setup venv_wine 34 | #### Active virutal env 35 | . venv_wine/bin/activate 36 | 37 | ### Use wine to install packages to virtual env 38 | if [ ! -e "python-2.7.8.msi" ]; then 39 | wget "https://www.python.org/ftp/python/2.7.8/python-2.7.8.msi" 40 | fi 41 | 42 | if [ ! -e "pywin32-218.win32-py2.7.exe" ]; then 43 | wget "http://nchc.dl.sourceforge.net/project/pywin32/pywin32/Build%20218/pywin32-218.win32-py2.7.exe" 44 | fi 45 | 46 | if [ ! -e "PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe" ]; then 47 | wget "http://nchc.dl.sourceforge.net/project/pyqt/PyQt4/PyQt-4.11.4/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe" 48 | fi 49 | 50 | if [ ! -e "lxml-2.3.win32-py2.7.exe" ]; then 51 | wget "https://pypi.python.org/packages/3d/ee/affbc53073a951541b82a0ba2a70de266580c00f94dd768a60f125b04fca/lxml-2.3.win32-py2.7.exe#md5=9c02aae672870701377750121f5a6f84" 52 | fi 53 | 54 | wine msiexec -i python-2.7.8.msi 55 | wine pywin32-218.win32-py2.7.exe 56 | wine PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe 57 | wine lxml-2.3.win32-py2.7.exe 58 | -------------------------------------------------------------------------------- /contributors.txt: -------------------------------------------------------------------------------- 1 | TzuTa Lin 2 | [LabelMe](http://labelme2.csail.mit.edu/Release3.0/index.php) 3 | -------------------------------------------------------------------------------- /data/predefined_classes.txt: -------------------------------------------------------------------------------- 1 | dog 2 | person 3 | cat 4 | tv 5 | car 6 | -------------------------------------------------------------------------------- /demo/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/demo/demo.png -------------------------------------------------------------------------------- /demo/demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/demo/demo2.png -------------------------------------------------------------------------------- /icons/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/cancel.png -------------------------------------------------------------------------------- /icons/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/close.png -------------------------------------------------------------------------------- /icons/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/color.png -------------------------------------------------------------------------------- /icons/color_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/color_line.png -------------------------------------------------------------------------------- /icons/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/copy.png -------------------------------------------------------------------------------- /icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/delete.png -------------------------------------------------------------------------------- /icons/done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/done.png -------------------------------------------------------------------------------- /icons/done.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 27 | 29 | 36 | 40 | 44 | 48 | 52 | 56 | 57 | 64 | 68 | 72 | 76 | 80 | 84 | 85 | 92 | 96 | 100 | 104 | 108 | 112 | 113 | 121 | 125 | 129 | 133 | 137 | 141 | 142 | 143 | 145 | 147 | begin='' id='W5M0MpCehiHzreSzNTczkc9d' 148 | 150 | 151 | 153 | 154 | Adobe PDF library 5.00 155 | 156 | 158 | 160 | 162 | 163 | 2003-12-22T22:34:35+02:00 164 | 165 | 2004-04-17T21:25:50Z 166 | 167 | Adobe Illustrator 10.0 168 | 169 | 2004-01-19T17:51:02+01:00 170 | 171 | 172 | 174 | 175 | JPEG 176 | 177 | 256 178 | 179 | 256 180 | 181 | /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA 182 | AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK 183 | DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f 184 | Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER 185 | AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA 186 | AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB 187 | UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 188 | 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ 189 | qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy 190 | obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 191 | 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo 192 | +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 193 | FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F 194 | XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX 195 | Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY 196 | 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 342 | 343 | 344 | 345 | 346 | 348 | 349 | uuid:4b4d592f-95b8-4bcd-a892-74a536c5e52f 350 | 351 | 353 | 354 | image/svg+xml 355 | 356 | 357 | 359 | test.ai 360 | 361 | 362 | 363 | 364 | 365 | end='w' 366 | 367 | 372 | 376 | 380 | 384 | 388 | 392 | 396 | 400 | 401 | -------------------------------------------------------------------------------- /icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/edit.png -------------------------------------------------------------------------------- /icons/expert1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/expert1.png -------------------------------------------------------------------------------- /icons/expert2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/expert2.png -------------------------------------------------------------------------------- /icons/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/eye.png -------------------------------------------------------------------------------- /icons/feBlend-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/feBlend-icon.png -------------------------------------------------------------------------------- /icons/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/file.png -------------------------------------------------------------------------------- /icons/fit-width.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/fit-width.png -------------------------------------------------------------------------------- /icons/fit-window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/fit-window.png -------------------------------------------------------------------------------- /icons/fit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/fit.png -------------------------------------------------------------------------------- /icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/help.png -------------------------------------------------------------------------------- /icons/labels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/labels.png -------------------------------------------------------------------------------- /icons/labels.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 31 | 33 | 34 | 35 | 36 | 43 | 47 | 51 | 55 | 59 | 63 | 64 | 65 | 66 | 73 | 77 | 81 | 85 | 89 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 107 | 111 | 115 | 119 | 123 | 127 | 128 | 129 | 137 | 141 | 145 | 149 | 153 | 157 | 158 | 159 | 166 | 170 | 174 | 178 | 182 | 186 | 190 | 194 | 198 | 199 | 200 | 201 | 202 | 203 | 211 | 215 | 219 | 223 | 227 | 231 | 232 | 233 | 241 | 245 | 249 | 253 | 257 | 261 | 265 | 269 | 273 | 274 | 275 | 282 | 286 | 290 | 294 | 298 | 302 | 306 | 310 | 314 | 318 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 399 | 411 | 413 | 414 | 415 | 421 | 422 | 428 | 429 | 432 | 439 | 440 | 441 | 442 | begin='' id='W5M0MpCehiHzreSzNTczkc9d' 444 | 446 | 447 | 449 | 451 | 452 | Adobe PDF library 5.00 453 | 454 | 456 | 458 | 460 | 461 | 2004-01-26T11:58:28+02:00 462 | 463 | 2004-03-28T20:41:40Z 464 | 465 | Adobe Illustrator 10.0 466 | 467 | 2004-02-16T23:58:32+01:00 468 | 469 | 470 | 472 | 473 | JPEG 474 | 475 | 256 476 | 477 | 256 478 | 479 | /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA 480 | AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK 481 | DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f 482 | Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER 483 | AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA 484 | AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB 485 | UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 486 | 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ 487 | qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy 488 | obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 489 | 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo 490 | +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 491 | FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqlvmDzFo 492 | 3l7TJdT1e5W1tItuTbszHoiKN2Y+AxV4j5g/5ydvTcMnl/SYlgU0Se/LOzDxMcTIF/4M4qk//QzP 493 | nv8A5YNL/wCRVx/2UYq7/oZnz3/ywaX/AMirj/soxV3/AEMz57/5YNL/AORVx/2UYq7/AKGZ89/8 494 | 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 677 | f//Z 678 | 679 | 680 | 681 | 682 | 684 | 685 | uuid:4ee3f24b-6ed2-4a2e-8f7a-50b762c8da8b 686 | 687 | 689 | 690 | image/svg+xml 691 | 692 | 693 | 695 | mime.ai 696 | 697 | 698 | 699 | image/svg+xml 702 | end='w' 704 | 705 | 800 | Labels 819 | -------------------------------------------------------------------------------- /icons/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/new.png -------------------------------------------------------------------------------- /icons/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/next.png -------------------------------------------------------------------------------- /icons/objects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/objects.png -------------------------------------------------------------------------------- /icons/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/open.png -------------------------------------------------------------------------------- /icons/open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | image/svg+xml 42 | 43 | 45 | 52 | 54 | 55 | 56 | 58 | 60 | 67 | 68 | 70 | 77 | 81 | 85 | 89 | 92 | 95 | 98 | 101 | 104 | 105 | 109 | 116 | 120 | 124 | 128 | 132 | 135 | 138 | 141 | 144 | 147 | 150 | 153 | 154 | 158 | 165 | 169 | 173 | 177 | 181 | 185 | 188 | 191 | 194 | 195 | 199 | 206 | 210 | 214 | 218 | 222 | 226 | 229 | 232 | 235 | 236 | 240 | 247 | 251 | 255 | 258 | 261 | 264 | 265 | 269 | 276 | 280 | 284 | 288 | 291 | 294 | 297 | 300 | 303 | 304 | 308 | 315 | 319 | 323 | 327 | 330 | 333 | 336 | 339 | 342 | 343 | 347 | 354 | 358 | 362 | 365 | 368 | 371 | 372 | 376 | 383 | 387 | 391 | 395 | 399 | 403 | 407 | 411 | 415 | 418 | 421 | 424 | 425 | 429 | 433 | 440 | 444 | 448 | 451 | 454 | 457 | 458 | 462 | 466 | 473 | 477 | 481 | 484 | 487 | 490 | 491 | 495 | 502 | 506 | 510 | 514 | 517 | 520 | 523 | 526 | 529 | 530 | 534 | 541 | 545 | 549 | 552 | 555 | 558 | 559 | 563 | 567 | 574 | 575 | 576 | 577 | -------------------------------------------------------------------------------- /icons/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/prev.png -------------------------------------------------------------------------------- /icons/quit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/quit.png -------------------------------------------------------------------------------- /icons/save-as.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/save-as.png -------------------------------------------------------------------------------- /icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/save.png -------------------------------------------------------------------------------- /icons/save.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 27 | 29 | 31 | 33 | begin='' id='W5M0MpCehiHzreSzNTczkc9d' 34 | 36 | 37 | 39 | 40 | Adobe PDF library 5.00 41 | 42 | 44 | 46 | 48 | 49 | 2004-02-04T02:08:51+02:00 50 | 51 | 2004-03-29T09:20:16Z 52 | 53 | Adobe Illustrator 10.0 54 | 55 | 2004-02-29T14:54:28+01:00 56 | 57 | 58 | 60 | 61 | JPEG 62 | 63 | 256 64 | 65 | 256 66 | 67 | /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA 68 | AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK 69 | DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f 70 | Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER 71 | AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA 72 | AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB 73 | UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 74 | 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ 75 | qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy 76 | obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 77 | 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo 78 | +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 79 | FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F 80 | XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX 81 | Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY 82 | 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 268 | 269 | 270 | 271 | 272 | 274 | 275 | uuid:f3c53255-be8a-4b04-817b-695bf2c54c8b 276 | 277 | 279 | 280 | image/svg+xml 281 | 282 | 283 | 285 | filesave.ai 286 | 287 | 288 | 289 | 290 | 291 | end='w' 292 | 293 | 295 | 299 | 303 | 307 | 311 | 315 | 323 | 327 | 331 | 335 | 339 | 343 | 344 | 348 | 352 | 359 | 363 | 367 | 371 | 375 | 379 | 380 | 384 | 391 | 395 | 399 | 403 | 407 | 411 | 412 | 416 | 420 | 428 | 432 | 436 | 440 | 444 | 448 | 449 | 453 | 457 | 464 | 468 | 472 | 476 | 480 | 484 | 488 | 492 | 496 | 497 | 501 | 509 | 513 | 517 | 521 | 525 | 529 | 533 | 537 | 541 | 542 | 549 | 556 | 560 | 564 | 568 | 572 | 576 | 577 | 581 | 589 | 593 | 597 | 601 | 605 | 609 | 613 | 617 | 621 | 625 | 629 | 633 | 634 | 638 | 646 | 650 | 654 | 658 | 662 | 666 | 667 | 674 | 678 | 679 | 680 | -------------------------------------------------------------------------------- /icons/undo-cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/undo-cross.png -------------------------------------------------------------------------------- /icons/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/undo.png -------------------------------------------------------------------------------- /icons/zoom-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/zoom-in.png -------------------------------------------------------------------------------- /icons/zoom-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/zoom-out.png -------------------------------------------------------------------------------- /icons/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/icons/zoom.png -------------------------------------------------------------------------------- /libs/canvas.py: -------------------------------------------------------------------------------- 1 | 2 | try: 3 | from PyQt5.QtGui import * 4 | from PyQt5.QtCore import * 5 | from PyQt5.QtWidgets import * 6 | except ImportError: 7 | from PyQt4.QtGui import * 8 | from PyQt4.QtCore import * 9 | 10 | #from PyQt4.QtOpenGL import * 11 | 12 | from shape import Shape 13 | from lib import distance 14 | 15 | CURSOR_DEFAULT = Qt.ArrowCursor 16 | CURSOR_POINT = Qt.PointingHandCursor 17 | CURSOR_DRAW = Qt.CrossCursor 18 | CURSOR_MOVE = Qt.ClosedHandCursor 19 | CURSOR_GRAB = Qt.OpenHandCursor 20 | 21 | #class Canvas(QGLWidget): 22 | class Canvas(QWidget): 23 | zoomRequest = pyqtSignal(int) 24 | scrollRequest = pyqtSignal(int, int) 25 | newShape = pyqtSignal() 26 | selectionChanged = pyqtSignal(bool) 27 | shapeMoved = pyqtSignal() 28 | drawingPolygon = pyqtSignal(bool) 29 | 30 | CREATE, EDIT = list(range(2)) 31 | 32 | epsilon = 11.0 33 | 34 | def __init__(self, *args, **kwargs): 35 | super(Canvas, self).__init__(*args, **kwargs) 36 | # Initialise local state. 37 | self.mode = self.EDIT 38 | self.shapes = [] 39 | self.current = None 40 | self.selectedShape=None # save the selected shape here 41 | self.selectedShapeCopy=None 42 | self.lineColor = QColor(0, 0, 255) 43 | self.line = Shape(line_color=self.lineColor) 44 | self.prevPoint = QPointF() 45 | self.offsets = QPointF(), QPointF() 46 | self.scale = 1.0 47 | self.pixmap = QPixmap() 48 | self.visible = {} 49 | self._hideBackround = False 50 | self.hideBackround = False 51 | self.hShape = None 52 | self.hVertex = None 53 | self._painter = QPainter() 54 | self._cursor = CURSOR_DEFAULT 55 | # Menus: 56 | self.menus = (QMenu(), QMenu()) 57 | # Set widget options. 58 | self.setMouseTracking(True) 59 | self.setFocusPolicy(Qt.WheelFocus) 60 | 61 | def enterEvent(self, ev): 62 | self.overrideCursor(self._cursor) 63 | 64 | def leaveEvent(self, ev): 65 | self.restoreCursor() 66 | 67 | def focusOutEvent(self, ev): 68 | self.restoreCursor() 69 | 70 | def isVisible(self, shape): 71 | return self.visible.get(shape, True) 72 | 73 | def drawing(self): 74 | return self.mode == self.CREATE 75 | 76 | def editing(self): 77 | return self.mode == self.EDIT 78 | 79 | def setEditing(self, value=True): 80 | self.mode = self.EDIT if value else self.CREATE 81 | if not value: # Create 82 | self.unHighlight() 83 | self.deSelectShape() 84 | 85 | def unHighlight(self): 86 | if self.hShape: 87 | self.hShape.highlightClear() 88 | self.hVertex = self.hShape = None 89 | 90 | def selectedVertex(self): 91 | return self.hVertex is not None 92 | 93 | def mouseMoveEvent(self, ev): 94 | """Update line with last point and current coordinates.""" 95 | pos = self.transformPos(ev.pos()) 96 | 97 | self.restoreCursor() 98 | 99 | # Polygon drawing. 100 | if self.drawing(): 101 | self.overrideCursor(CURSOR_DRAW) 102 | if self.current: 103 | color = self.lineColor 104 | if self.outOfPixmap(pos): 105 | # Don't allow the user to draw outside the pixmap. 106 | # Project the point to the pixmap's edges. 107 | pos = self.intersectionPoint(self.current[-1], pos) 108 | elif len(self.current) > 1 and self.closeEnough(pos, self.current[0]): 109 | # Attract line to starting point and colorise to alert the user: 110 | pos = self.current[0] 111 | color = self.current.line_color 112 | self.overrideCursor(CURSOR_POINT) 113 | self.current.highlightVertex(0, Shape.NEAR_VERTEX) 114 | self.line[1] = pos 115 | self.line.line_color = color 116 | self.repaint() 117 | self.current.highlightClear() 118 | return 119 | 120 | # Polygon copy moving. 121 | if Qt.RightButton & ev.buttons(): 122 | if self.selectedShapeCopy and self.prevPoint: 123 | self.overrideCursor(CURSOR_MOVE) 124 | self.boundedMoveShape(self.selectedShapeCopy, pos) 125 | self.repaint() 126 | elif self.selectedShape: 127 | self.selectedShapeCopy = self.selectedShape.copy() 128 | self.repaint() 129 | return 130 | 131 | # Polygon/Vertex moving. 132 | if Qt.LeftButton & ev.buttons(): 133 | if self.selectedVertex(): 134 | self.boundedMoveVertex(pos) 135 | self.shapeMoved.emit() 136 | self.repaint() 137 | elif self.selectedShape and self.prevPoint: 138 | self.overrideCursor(CURSOR_MOVE) 139 | self.boundedMoveShape(self.selectedShape, pos) 140 | self.shapeMoved.emit() 141 | self.repaint() 142 | return 143 | 144 | # Just hovering over the canvas, 2 posibilities: 145 | # - Highlight shapes 146 | # - Highlight vertex 147 | # Update shape/vertex fill and tooltip value accordingly. 148 | self.setToolTip("Image") 149 | for shape in reversed([s for s in self.shapes if self.isVisible(s)]): 150 | # Look for a nearby vertex to highlight. If that fails, 151 | # check if we happen to be inside a shape. 152 | index = shape.nearestVertex(pos, self.epsilon) 153 | if index is not None: 154 | if self.selectedVertex(): 155 | self.hShape.highlightClear() 156 | self.hVertex, self.hShape = index, shape 157 | shape.highlightVertex(index, shape.MOVE_VERTEX) 158 | self.overrideCursor(CURSOR_POINT) 159 | self.setToolTip("Click & drag to move point") 160 | self.setStatusTip(self.toolTip()) 161 | self.update() 162 | break 163 | elif shape.containsPoint(pos): 164 | if self.selectedVertex(): 165 | self.hShape.highlightClear() 166 | self.hVertex, self.hShape = None, shape 167 | self.setToolTip("Click & drag to move shape '%s'" % shape.label) 168 | self.setStatusTip(self.toolTip()) 169 | self.overrideCursor(CURSOR_GRAB) 170 | self.update() 171 | break 172 | else: # Nothing found, clear highlights, reset state. 173 | if self.hShape: 174 | self.hShape.highlightClear() 175 | self.update() 176 | self.hVertex, self.hShape = None, None 177 | 178 | def mousePressEvent(self, ev): 179 | pos = self.transformPos(ev.pos()) 180 | 181 | if ev.button() == Qt.LeftButton: 182 | if self.drawing(): 183 | if self.current and self.current.reachMaxPoints() is False: 184 | initPos = self.current[0] 185 | minX = initPos.x() 186 | minY = initPos.y() 187 | targetPos = self.line[1] 188 | maxX = targetPos.x() 189 | maxY = targetPos.y() 190 | self.current.addPoint(QPointF(maxX, minY)) 191 | self.current.addPoint(targetPos) 192 | self.current.addPoint(QPointF(minX, maxY)) 193 | self.current.addPoint(initPos) 194 | self.line[0] = self.current[-1] 195 | if self.current.isClosed(): 196 | self.finalise() 197 | elif not self.outOfPixmap(pos): 198 | self.current = Shape() 199 | self.current.addPoint(pos) 200 | self.line.points = [pos, pos] 201 | self.setHiding() 202 | self.drawingPolygon.emit(True) 203 | self.update() 204 | else: 205 | self.selectShapePoint(pos) 206 | self.prevPoint = pos 207 | self.repaint() 208 | elif ev.button() == Qt.RightButton and self.editing(): 209 | self.selectShapePoint(pos) 210 | self.prevPoint = pos 211 | self.repaint() 212 | 213 | def mouseReleaseEvent(self, ev): 214 | if ev.button() == Qt.RightButton: 215 | menu = self.menus[bool(self.selectedShapeCopy)] 216 | self.restoreCursor() 217 | if not menu.exec_(self.mapToGlobal(ev.pos()))\ 218 | and self.selectedShapeCopy: 219 | # Cancel the move by deleting the shadow copy. 220 | self.selectedShapeCopy = None 221 | self.repaint() 222 | elif ev.button() == Qt.LeftButton and self.selectedShape: 223 | self.overrideCursor(CURSOR_GRAB) 224 | 225 | def endMove(self, copy=False): 226 | assert self.selectedShape and self.selectedShapeCopy 227 | shape = self.selectedShapeCopy 228 | #del shape.fill_color 229 | #del shape.line_color 230 | if copy: 231 | self.shapes.append(shape) 232 | self.selectedShape.selected = False 233 | self.selectedShape = shape 234 | self.repaint() 235 | else: 236 | shape.label = self.selectedShape.label 237 | self.deleteSelected() 238 | self.shapes.append(shape) 239 | self.selectedShapeCopy = None 240 | 241 | def hideBackroundShapes(self, value): 242 | self.hideBackround = value 243 | if self.selectedShape: 244 | # Only hide other shapes if there is a current selection. 245 | # Otherwise the user will not be able to select a shape. 246 | self.setHiding(True) 247 | self.repaint() 248 | 249 | def setHiding(self, enable=True): 250 | self._hideBackround = self.hideBackround if enable else False 251 | 252 | def canCloseShape(self): 253 | return self.drawing() and self.current and len(self.current) > 2 254 | 255 | def mouseDoubleClickEvent(self, ev): 256 | # We need at least 4 points here, since the mousePress handler 257 | # adds an extra one before this handler is called. 258 | if self.canCloseShape() and len(self.current) > 3: 259 | self.current.popPoint() 260 | self.finalise() 261 | 262 | def selectShape(self, shape): 263 | self.deSelectShape() 264 | shape.selected = True 265 | self.selectedShape = shape 266 | self.setHiding() 267 | self.selectionChanged.emit(True) 268 | self.update() 269 | 270 | def selectShapePoint(self, point): 271 | """Select the first shape created which contains this point.""" 272 | self.deSelectShape() 273 | if self.selectedVertex(): # A vertex is marked for selection. 274 | index, shape = self.hVertex, self.hShape 275 | shape.highlightVertex(index, shape.MOVE_VERTEX) 276 | return 277 | for shape in reversed(self.shapes): 278 | if self.isVisible(shape) and shape.containsPoint(point): 279 | shape.selected = True 280 | self.selectedShape = shape 281 | self.calculateOffsets(shape, point) 282 | self.setHiding() 283 | self.selectionChanged.emit(True) 284 | return 285 | 286 | def calculateOffsets(self, shape, point): 287 | rect = shape.boundingRect() 288 | x1 = rect.x() - point.x() 289 | y1 = rect.y() - point.y() 290 | x2 = (rect.x() + rect.width()) - point.x() 291 | y2 = (rect.y() + rect.height()) - point.y() 292 | self.offsets = QPointF(x1, y1), QPointF(x2, y2) 293 | 294 | def boundedMoveVertex(self, pos): 295 | index, shape = self.hVertex, self.hShape 296 | point = shape[index] 297 | if self.outOfPixmap(pos): 298 | pos = self.intersectionPoint(point, pos) 299 | 300 | shiftPos = pos - point 301 | shape.moveVertexBy(index, shiftPos) 302 | 303 | lindex = (index + 1) % 4 304 | rindex = (index + 3) % 4 305 | lshift = None 306 | rshift = None 307 | if index % 2 == 0: 308 | rshift = QPointF(shiftPos.x(), 0) 309 | lshift = QPointF(0, shiftPos.y()) 310 | else: 311 | lshift = QPointF(shiftPos.x(), 0) 312 | rshift = QPointF(0, shiftPos.y()) 313 | shape.moveVertexBy(rindex, rshift) 314 | shape.moveVertexBy(lindex, lshift) 315 | 316 | def boundedMoveShape(self, shape, pos): 317 | if self.outOfPixmap(pos): 318 | return False # No need to move 319 | o1 = pos + self.offsets[0] 320 | if self.outOfPixmap(o1): 321 | pos -= QPointF(min(0, o1.x()), min(0, o1.y())) 322 | o2 = pos + self.offsets[1] 323 | if self.outOfPixmap(o2): 324 | pos += QPointF(min(0, self.pixmap.width() - o2.x()), 325 | min(0, self.pixmap.height()- o2.y())) 326 | # The next line tracks the new position of the cursor 327 | # relative to the shape, but also results in making it 328 | # a bit "shaky" when nearing the border and allows it to 329 | # go outside of the shape's area for some reason. XXX 330 | #self.calculateOffsets(self.selectedShape, pos) 331 | dp = pos - self.prevPoint 332 | if dp: 333 | shape.moveBy(dp) 334 | self.prevPoint = pos 335 | return True 336 | return False 337 | 338 | def deSelectShape(self): 339 | if self.selectedShape: 340 | self.selectedShape.selected = False 341 | self.selectedShape = None 342 | self.setHiding(False) 343 | self.selectionChanged.emit(False) 344 | self.update() 345 | 346 | def deleteSelected(self): 347 | if self.selectedShape: 348 | shape = self.selectedShape 349 | self.shapes.remove(self.selectedShape) 350 | self.selectedShape = None 351 | self.update() 352 | return shape 353 | 354 | def copySelectedShape(self): 355 | if self.selectedShape: 356 | shape = self.selectedShape.copy() 357 | self.deSelectShape() 358 | self.shapes.append(shape) 359 | shape.selected = True 360 | self.selectedShape = shape 361 | self.boundedShiftShape(shape) 362 | return shape 363 | 364 | def boundedShiftShape(self, shape): 365 | # Try to move in one direction, and if it fails in another. 366 | # Give up if both fail. 367 | point = shape[0] 368 | offset = QPointF(2.0, 2.0) 369 | self.calculateOffsets(shape, point) 370 | self.prevPoint = point 371 | if not self.boundedMoveShape(shape, point - offset): 372 | self.boundedMoveShape(shape, point + offset) 373 | 374 | def paintEvent(self, event): 375 | if not self.pixmap: 376 | return super(Canvas, self).paintEvent(event) 377 | 378 | p = self._painter 379 | p.begin(self) 380 | p.setRenderHint(QPainter.Antialiasing) 381 | p.setRenderHint(QPainter.HighQualityAntialiasing) 382 | p.setRenderHint(QPainter.SmoothPixmapTransform) 383 | 384 | p.scale(self.scale, self.scale) 385 | p.translate(self.offsetToCenter()) 386 | 387 | p.drawPixmap(0, 0, self.pixmap) 388 | Shape.scale = self.scale 389 | for shape in self.shapes: 390 | if (shape.selected or not self._hideBackround) and self.isVisible(shape): 391 | shape.fill = shape.selected or shape == self.hShape 392 | shape.paint(p) 393 | if self.current: 394 | self.current.paint(p) 395 | self.line.paint(p) 396 | if self.selectedShapeCopy: 397 | self.selectedShapeCopy.paint(p) 398 | 399 | # Paint rect 400 | if self.current is not None and len(self.line) == 2: 401 | leftTop = self.line[0] 402 | rightBottom = self.line[1] 403 | rectWidth = rightBottom.x() - leftTop.x() 404 | rectHeight = rightBottom.y() - leftTop.y() 405 | color = QColor(0, 220, 0) 406 | p.setPen(color) 407 | brush = QBrush(Qt.BDiagPattern) 408 | p.setBrush(brush) 409 | p.drawRect(leftTop.x(), leftTop.y(), rectWidth, rectHeight) 410 | 411 | p.end() 412 | 413 | def transformPos(self, point): 414 | """Convert from widget-logical coordinates to painter-logical coordinates.""" 415 | return point / self.scale - self.offsetToCenter() 416 | 417 | def offsetToCenter(self): 418 | s = self.scale 419 | area = super(Canvas, self).size() 420 | w, h = self.pixmap.width() * s, self.pixmap.height() * s 421 | aw, ah = area.width(), area.height() 422 | x = (aw-w)/(2*s) if aw > w else 0 423 | y = (ah-h)/(2*s) if ah > h else 0 424 | return QPointF(x, y) 425 | 426 | def outOfPixmap(self, p): 427 | w, h = self.pixmap.width(), self.pixmap.height() 428 | return not (0 <= p.x() <= w and 0 <= p.y() <= h) 429 | 430 | def finalise(self): 431 | assert self.current 432 | self.current.close() 433 | self.shapes.append(self.current) 434 | self.current = None 435 | self.setHiding(False) 436 | self.newShape.emit() 437 | self.update() 438 | 439 | def closeEnough(self, p1, p2): 440 | #d = distance(p1 - p2) 441 | #m = (p1-p2).manhattanLength() 442 | #print "d %.2f, m %d, %.2f" % (d, m, d - m) 443 | return distance(p1 - p2) < self.epsilon 444 | 445 | def intersectionPoint(self, p1, p2): 446 | # Cycle through each image edge in clockwise fashion, 447 | # and find the one intersecting the current line segment. 448 | # http://paulbourke.net/geometry/lineline2d/ 449 | size = self.pixmap.size() 450 | points = [(0,0), 451 | (size.width(), 0), 452 | (size.width(), size.height()), 453 | (0, size.height())] 454 | x1, y1 = p1.x(), p1.y() 455 | x2, y2 = p2.x(), p2.y() 456 | d, i, (x, y) = min(self.intersectingEdges((x1, y1), (x2, y2), points)) 457 | x3, y3 = points[i] 458 | x4, y4 = points[(i+1)%4] 459 | if (x, y) == (x1, y1): 460 | # Handle cases where previous point is on one of the edges. 461 | if x3 == x4: 462 | return QPointF(x3, min(max(0, y2), max(y3, y4))) 463 | else: # y3 == y4 464 | return QPointF(min(max(0, x2), max(x3, x4)), y3) 465 | return QPointF(x, y) 466 | 467 | def intersectingEdges(self, x1y1, x2y2, points): 468 | """For each edge formed by `points', yield the intersection 469 | with the line segment `(x1,y1) - (x2,y2)`, if it exists. 470 | Also return the distance of `(x2,y2)' to the middle of the 471 | edge along with its index, so that the one closest can be chosen.""" 472 | x1, y1 = x1y1 473 | x2, y2 = x2y2 474 | for i in range(4): 475 | x3, y3 = points[i] 476 | x4, y4 = points[(i+1) % 4] 477 | denom = (y4-y3) * (x2 - x1) - (x4 - x3) * (y2 - y1) 478 | nua = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3) 479 | nub = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3) 480 | if denom == 0: 481 | # This covers two cases: 482 | # nua == nub == 0: Coincident 483 | # otherwise: Parallel 484 | continue 485 | ua, ub = nua / denom, nub / denom 486 | if 0 <= ua <= 1 and 0 <= ub <= 1: 487 | x = x1 + ua * (x2 - x1) 488 | y = y1 + ua * (y2 - y1) 489 | m = QPointF((x3 + x4)/2, (y3 + y4)/2) 490 | d = distance(m - QPointF(x2, y2)) 491 | yield d, i, (x, y) 492 | 493 | # These two, along with a call to adjustSize are required for the 494 | # scroll area. 495 | def sizeHint(self): 496 | return self.minimumSizeHint() 497 | 498 | def minimumSizeHint(self): 499 | if self.pixmap: 500 | return self.scale * self.pixmap.size() 501 | return super(Canvas, self).minimumSizeHint() 502 | 503 | def wheelEvent(self, ev): 504 | if ev.orientation() == Qt.Vertical: 505 | mods = ev.modifiers() 506 | if Qt.ControlModifier == int(mods): 507 | self.zoomRequest.emit(ev.delta()) 508 | else: 509 | self.scrollRequest.emit(ev.delta(), 510 | Qt.Horizontal if (Qt.ShiftModifier == int(mods))\ 511 | else Qt.Vertical) 512 | else: 513 | self.scrollRequest.emit(ev.delta(), Qt.Horizontal) 514 | ev.accept() 515 | 516 | def keyPressEvent(self, ev): 517 | key = ev.key() 518 | if key == Qt.Key_Escape and self.current: 519 | print('ESC press') 520 | self.current = None 521 | self.drawingPolygon.emit(False) 522 | self.update() 523 | elif key == Qt.Key_Return and self.canCloseShape(): 524 | self.finalise() 525 | 526 | def setLastLabel(self, text): 527 | assert text 528 | self.shapes[-1].label = text 529 | return self.shapes[-1] 530 | 531 | def undoLastLine(self): 532 | assert self.shapes 533 | self.current = self.shapes.pop() 534 | self.current.setOpen() 535 | self.line.points = [self.current[-1], self.current[0]] 536 | self.drawingPolygon.emit(True) 537 | 538 | def resetAllLines(self): 539 | assert self.shapes 540 | self.current = self.shapes.pop() 541 | self.current.setOpen() 542 | self.line.points = [self.current[-1], self.current[0]] 543 | self.drawingPolygon.emit(True) 544 | self.current = None 545 | self.drawingPolygon.emit(False) 546 | self.update() 547 | 548 | def loadPixmap(self, pixmap): 549 | self.pixmap = pixmap 550 | self.shapes = [] 551 | self.repaint() 552 | 553 | def loadShapes(self, shapes): 554 | self.shapes = list(shapes) 555 | self.current = None 556 | self.repaint() 557 | 558 | def setShapeVisible(self, shape, value): 559 | self.visible[shape] = value 560 | self.repaint() 561 | 562 | def overrideCursor(self, cursor): 563 | self.restoreCursor() 564 | self._cursor = cursor 565 | QApplication.setOverrideCursor(cursor) 566 | 567 | def restoreCursor(self): 568 | QApplication.restoreOverrideCursor() 569 | 570 | def resetState(self): 571 | self.restoreCursor() 572 | self.pixmap = None 573 | self.update() 574 | 575 | -------------------------------------------------------------------------------- /libs/colorDialog.py: -------------------------------------------------------------------------------- 1 | try: 2 | from PyQt5.QtGui import * 3 | from PyQt5.QtCore import * 4 | from PyQt5.QtWidgets import QColorDialog, QDialogButtonBox 5 | except ImportError: 6 | from PyQt4.QtGui import * 7 | from PyQt4.QtCore import * 8 | 9 | BB = QDialogButtonBox 10 | 11 | class ColorDialog(QColorDialog): 12 | def __init__(self, parent=None): 13 | super(ColorDialog, self).__init__(parent) 14 | self.setOption(QColorDialog.ShowAlphaChannel) 15 | # The Mac native dialog does not support our restore button. 16 | self.setOption(QColorDialog.DontUseNativeDialog) 17 | ## Add a restore defaults button. 18 | # The default is set at invocation time, so that it 19 | # works across dialogs for different elements. 20 | self.default = None 21 | self.bb = self.layout().itemAt(1).widget() 22 | self.bb.addButton(BB.RestoreDefaults) 23 | self.bb.clicked.connect(self.checkRestore) 24 | 25 | def getColor(self, value=None, title=None, default=None): 26 | self.default = default 27 | if title: 28 | self.setWindowTitle(title) 29 | if value: 30 | self.setCurrentColor(value) 31 | return self.currentColor() if self.exec_() else None 32 | 33 | def checkRestore(self, button): 34 | if self.bb.buttonRole(button) & BB.ResetRole and self.default: 35 | self.setCurrentColor(self.default) 36 | 37 | -------------------------------------------------------------------------------- /libs/labelDialog.py: -------------------------------------------------------------------------------- 1 | try: 2 | from PyQt5.QtGui import * 3 | from PyQt5.QtCore import * 4 | from PyQt5.QtWidgets import * 5 | except ImportError: 6 | from PyQt4.QtGui import * 7 | from PyQt4.QtCore import * 8 | 9 | from lib import newIcon, labelValidator 10 | 11 | BB = QDialogButtonBox 12 | 13 | class LabelDialog(QDialog): 14 | 15 | def __init__(self, text="Enter object label", parent=None, listItem=None): 16 | super(LabelDialog, self).__init__(parent) 17 | self.edit = QLineEdit() 18 | self.edit.setText(text) 19 | self.edit.setValidator(labelValidator()) 20 | self.edit.editingFinished.connect(self.postProcess) 21 | layout = QVBoxLayout() 22 | layout.addWidget(self.edit) 23 | self.buttonBox = bb = BB(BB.Ok | BB.Cancel, Qt.Horizontal, self) 24 | bb.button(BB.Ok).setIcon(newIcon('done')) 25 | bb.button(BB.Cancel).setIcon(newIcon('undo')) 26 | bb.accepted.connect(self.validate) 27 | bb.rejected.connect(self.reject) 28 | layout.addWidget(bb) 29 | 30 | if listItem is not None and len(listItem) > 0: 31 | self.listWidget = QListWidget(self) 32 | for item in listItem: 33 | self.listWidget.addItem(item) 34 | self.listWidget.itemDoubleClicked.connect(self.listItemClick) 35 | layout.addWidget(self.listWidget) 36 | 37 | self.setLayout(layout) 38 | 39 | def validate(self): 40 | try: 41 | if self.edit.text().trimmed(): 42 | self.accept() 43 | except AttributeError: 44 | # PyQt5: AttributeError: 'str' object has no attribute 'trimmed' 45 | if self.edit.text().strip(): 46 | self.accept() 47 | 48 | def postProcess(self): 49 | try: 50 | self.edit.setText(self.edit.text().trimmed()) 51 | except AttributeError: 52 | # PyQt5: AttributeError: 'str' object has no attribute 'trimmed' 53 | self.edit.setText(self.edit.text()) 54 | 55 | def popUp(self, text='', move=True): 56 | self.edit.setText(text) 57 | self.edit.setSelection(0, len(text)) 58 | self.edit.setFocus(Qt.PopupFocusReason) 59 | if move: 60 | self.move(QCursor.pos()) 61 | return self.edit.text() if self.exec_() else None 62 | 63 | def listItemClick(self, tQListWidgetItem): 64 | try: 65 | text = tQListWidgetItem.text().trimmed() 66 | except AttributeError: 67 | # PyQt5: AttributeError: 'str' object has no attribute 'trimmed' 68 | text = tQListWidgetItem.text().strip() 69 | self.edit.setText(text) 70 | self.validate() 71 | -------------------------------------------------------------------------------- /libs/labelFile.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Tzutalin 2 | # Create by TzuTaLin 3 | 4 | try: 5 | from PyQt5.QtGui import QImage 6 | except ImportError: 7 | from PyQt4.QtGui import QImage 8 | 9 | from base64 import b64encode, b64decode 10 | from pascal_voc_io import PascalVocWriter 11 | import os.path 12 | import sys 13 | 14 | class LabelFileError(Exception): 15 | pass 16 | 17 | class LabelFile(object): 18 | # It might be changed as window creates 19 | suffix = '.lif' 20 | 21 | def __init__(self, filename=None): 22 | self.shapes = () 23 | self.imagePath = None 24 | self.imageData = None 25 | if filename is not None: 26 | self.load(filename) 27 | 28 | def savePascalVocFormat(self, filename, shapes, imagePath, imageData, 29 | lineColor=None, fillColor=None, databaseSrc=None): 30 | imgFolderPath = os.path.dirname(imagePath) 31 | imgFolderName = os.path.split(imgFolderPath)[-1] 32 | imgFileName = os.path.basename(imagePath) 33 | imgFileNameWithoutExt = os.path.splitext(imgFileName)[0] 34 | # Read from file path because self.imageData might be empty if saving to 35 | # Pascal format 36 | image = QImage() 37 | image.load(imagePath) 38 | imageShape = [image.height(), image.width(), 1 if image.isGrayscale() else 3] 39 | writer = PascalVocWriter(imgFolderName, imgFileNameWithoutExt,\ 40 | imageShape, localImgPath=imagePath) 41 | bSave = False 42 | for shape in shapes: 43 | points = shape['points'] 44 | label = shape['label'] 45 | bndbox = LabelFile.convertPoints2BndBox(points) 46 | writer.addBndBox(bndbox[0], bndbox[1], bndbox[2], bndbox[3], label) 47 | bSave = True 48 | 49 | if bSave: 50 | writer.save(targetFile = filename) 51 | return 52 | 53 | @staticmethod 54 | def isLabelFile(filename): 55 | fileSuffix = os.path.splitext(filename)[1].lower() 56 | return fileSuffix == LabelFile.suffix 57 | 58 | @staticmethod 59 | def convertPoints2BndBox(points): 60 | xmin = float('inf') 61 | ymin = float('inf') 62 | xmax = float('-inf') 63 | ymax = float('-inf') 64 | for p in points: 65 | x = p[0] 66 | y = p[1] 67 | xmin = min(x,xmin) 68 | ymin = min(y,ymin) 69 | xmax = max(x,xmax) 70 | ymax = max(y,ymax) 71 | 72 | # Martin Kersner, 2015/11/12 73 | # 0-valued coordinates of BB caused an error while 74 | # training faster-rcnn object detector. 75 | if (xmin < 1): 76 | xmin = 1 77 | 78 | if (ymin < 1): 79 | ymin = 1 80 | 81 | return (int(xmin), int(ymin), int(xmax), int(ymax)) 82 | -------------------------------------------------------------------------------- /libs/lib.py: -------------------------------------------------------------------------------- 1 | from math import sqrt 2 | 3 | try: 4 | from PyQt5.QtGui import * 5 | from PyQt5.QtCore import * 6 | from PyQt5.QtWidgets import * 7 | except ImportError: 8 | from PyQt4.QtGui import * 9 | from PyQt4.QtCore import * 10 | 11 | 12 | def newIcon(icon): 13 | return QIcon(':/' + icon) 14 | 15 | def newButton(text, icon=None, slot=None): 16 | b = QPushButton(text) 17 | if icon is not None: 18 | b.setIcon(newIcon(icon)) 19 | if slot is not None: 20 | b.clicked.connect(slot) 21 | return b 22 | 23 | def newAction(parent, text, slot=None, shortcut=None, icon=None, 24 | tip=None, checkable=False, enabled=True): 25 | """Create a new action and assign callbacks, shortcuts, etc.""" 26 | a = QAction(text, parent) 27 | if icon is not None: 28 | a.setIcon(newIcon(icon)) 29 | if shortcut is not None: 30 | if isinstance(shortcut, (list, tuple)): 31 | a.setShortcuts(shortcut) 32 | else: 33 | a.setShortcut(shortcut) 34 | if tip is not None: 35 | a.setToolTip(tip) 36 | a.setStatusTip(tip) 37 | if slot is not None: 38 | a.triggered.connect(slot) 39 | if checkable: 40 | a.setCheckable(True) 41 | a.setEnabled(enabled) 42 | return a 43 | 44 | 45 | def addActions(widget, actions): 46 | for action in actions: 47 | if action is None: 48 | widget.addSeparator() 49 | elif isinstance(action, QMenu): 50 | widget.addMenu(action) 51 | else: 52 | widget.addAction(action) 53 | 54 | def labelValidator(): 55 | return QRegExpValidator(QRegExp(r'^[^ \t].+'), None) 56 | 57 | 58 | class struct(object): 59 | def __init__(self, **kwargs): 60 | self.__dict__.update(kwargs) 61 | 62 | def distance(p): 63 | return sqrt(p.x() * p.x() + p.y() * p.y()) 64 | 65 | def fmtShortcut(text): 66 | mod, key = text.split('+', 1) 67 | return '%s+%s' % (mod, key) 68 | 69 | -------------------------------------------------------------------------------- /libs/pascal_voc_io.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf8 -*- 3 | import _init_path 4 | import sys 5 | from xml.etree import ElementTree 6 | from xml.etree.ElementTree import Element, SubElement 7 | from lxml import etree 8 | 9 | 10 | class PascalVocWriter: 11 | 12 | def __init__(self, foldername, filename, imgSize, databaseSrc='Unknown', localImgPath=None): 13 | self.foldername = foldername 14 | self.filename = filename 15 | self.databaseSrc = databaseSrc 16 | self.imgSize = imgSize 17 | self.boxlist = [] 18 | self.localImgPath = localImgPath 19 | 20 | def prettify(self, elem): 21 | """ 22 | Return a pretty-printed XML string for the Element. 23 | """ 24 | rough_string = ElementTree.tostring(elem, 'utf8') 25 | root = etree.fromstring(rough_string) 26 | return etree.tostring(root, pretty_print=True) 27 | 28 | def genXML(self): 29 | """ 30 | Return XML root 31 | """ 32 | # Check conditions 33 | if self.filename is None or \ 34 | self.foldername is None or \ 35 | self.imgSize is None or \ 36 | len(self.boxlist) <= 0: 37 | return None 38 | 39 | top = Element('annotation') 40 | folder = SubElement(top, 'folder') 41 | folder.text = self.foldername 42 | 43 | filename = SubElement(top, 'filename') 44 | filename.text = self.filename 45 | 46 | localImgPath = SubElement(top, 'path') 47 | localImgPath.text = self.localImgPath 48 | 49 | source = SubElement(top, 'source') 50 | database = SubElement(source, 'database') 51 | database.text = self.databaseSrc 52 | 53 | size_part = SubElement(top, 'size') 54 | width = SubElement(size_part, 'width') 55 | height = SubElement(size_part, 'height') 56 | depth = SubElement(size_part, 'depth') 57 | width.text = str(self.imgSize[1]) 58 | height.text = str(self.imgSize[0]) 59 | if len(self.imgSize) == 3: 60 | depth.text = str(self.imgSize[2]) 61 | else: 62 | depth.text = '1' 63 | 64 | segmented = SubElement(top, 'segmented') 65 | segmented.text = '0' 66 | return top 67 | 68 | def addBndBox(self, xmin, ymin, xmax, ymax, name): 69 | bndbox = {'xmin': xmin, 'ymin': ymin, 'xmax': xmax, 'ymax': ymax} 70 | bndbox['name'] = name 71 | self.boxlist.append(bndbox) 72 | 73 | def appendObjects(self, top): 74 | for each_object in self.boxlist: 75 | object_item = SubElement(top, 'object') 76 | name = SubElement(object_item, 'name') 77 | try: 78 | name.text = unicode(each_object['name']) 79 | except NameError: 80 | # Py3: NameError: name 'unicode' is not defined 81 | name.text = each_object['name'] 82 | pose = SubElement(object_item, 'pose') 83 | pose.text = "Unspecified" 84 | truncated = SubElement(object_item, 'truncated') 85 | truncated.text = "0" 86 | difficult = SubElement(object_item, 'difficult') 87 | difficult.text = "0" 88 | bndbox = SubElement(object_item, 'bndbox') 89 | xmin = SubElement(bndbox, 'xmin') 90 | xmin.text = str(each_object['xmin']) 91 | ymin = SubElement(bndbox, 'ymin') 92 | ymin.text = str(each_object['ymin']) 93 | xmax = SubElement(bndbox, 'xmax') 94 | xmax.text = str(each_object['xmax']) 95 | ymax = SubElement(bndbox, 'ymax') 96 | ymax.text = str(each_object['ymax']) 97 | 98 | def save(self, targetFile=None): 99 | root = self.genXML() 100 | self.appendObjects(root) 101 | out_file = None 102 | if targetFile is None: 103 | out_file = open(self.filename + '.xml', 'w') 104 | else: 105 | out_file = open(targetFile, 'w') 106 | 107 | prettifyResult = self.prettify(root) 108 | out_file.write(prettifyResult.decode('utf8')) 109 | out_file.close() 110 | 111 | 112 | class PascalVocReader: 113 | 114 | def __init__(self, filepath): 115 | # shapes type: 116 | # [labbel, [(x1,y1), (x2,y2), (x3,y3), (x4,y4)], color, color] 117 | self.shapes = [] 118 | self.filepath = filepath 119 | self.parseXML() 120 | 121 | def getShapes(self): 122 | return self.shapes 123 | 124 | def addShape(self, label, bndbox): 125 | xmin = int(bndbox.find('xmin').text) 126 | ymin = int(bndbox.find('ymin').text) 127 | xmax = int(bndbox.find('xmax').text) 128 | ymax = int(bndbox.find('ymax').text) 129 | points = [(xmin, ymin), (xmax, ymin), (xmax, ymax), (xmin, ymax)] 130 | self.shapes.append((label, points, None, None)) 131 | 132 | def parseXML(self): 133 | assert self.filepath.endswith('.xml'), "Unsupport file format" 134 | parser = etree.XMLParser(encoding='utf-8') 135 | xmltree = ElementTree.parse(self.filepath, parser=parser).getroot() 136 | filename = xmltree.find('filename').text 137 | 138 | for object_iter in xmltree.findall('object'): 139 | bndbox = object_iter.find("bndbox") 140 | label = object_iter.find('name').text 141 | self.addShape(label, bndbox) 142 | return True 143 | 144 | 145 | # tempParseReader = PascalVocReader('test.xml') 146 | # print tempParseReader.getShapes() 147 | """ 148 | # Test 149 | tmp = PascalVocWriter('temp','test', (10,20,3)) 150 | tmp.addBndBox(10,10,20,30,'chair') 151 | tmp.addBndBox(1,1,600,600,'car') 152 | tmp.save() 153 | """ 154 | -------------------------------------------------------------------------------- /libs/shape.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | try: 6 | from PyQt5.QtGui import * 7 | from PyQt5.QtCore import * 8 | except ImportError: 9 | from PyQt4.QtGui import * 10 | from PyQt4.QtCore import * 11 | 12 | from lib import distance 13 | 14 | DEFAULT_LINE_COLOR = QColor(0, 255, 0, 128) 15 | DEFAULT_FILL_COLOR = QColor(255, 0, 0, 128) 16 | DEFAULT_SELECT_LINE_COLOR = QColor(255, 255, 255) 17 | DEFAULT_SELECT_FILL_COLOR = QColor(0, 128, 255, 155) 18 | DEFAULT_VERTEX_FILL_COLOR = QColor(0, 255, 0, 255) 19 | DEFAULT_HVERTEX_FILL_COLOR = QColor(255, 0, 0) 20 | 21 | class Shape(object): 22 | P_SQUARE, P_ROUND = range(2) 23 | 24 | MOVE_VERTEX, NEAR_VERTEX = range(2) 25 | 26 | ## The following class variables influence the drawing 27 | ## of _all_ shape objects. 28 | line_color = DEFAULT_LINE_COLOR 29 | fill_color = DEFAULT_FILL_COLOR 30 | select_line_color = DEFAULT_SELECT_LINE_COLOR 31 | select_fill_color = DEFAULT_SELECT_FILL_COLOR 32 | vertex_fill_color = DEFAULT_VERTEX_FILL_COLOR 33 | hvertex_fill_color = DEFAULT_HVERTEX_FILL_COLOR 34 | point_type = P_ROUND 35 | point_size = 8 36 | scale = 1.0 37 | 38 | def __init__(self, label=None, line_color=None): 39 | self.label = label 40 | self.points = [] 41 | self.fill = False 42 | self.selected = False 43 | 44 | self._highlightIndex = None 45 | self._highlightMode = self.NEAR_VERTEX 46 | self._highlightSettings = { 47 | self.NEAR_VERTEX: (4, self.P_ROUND), 48 | self.MOVE_VERTEX: (1.5, self.P_SQUARE), 49 | } 50 | 51 | self._closed = False 52 | 53 | if line_color is not None: 54 | # Override the class line_color attribute 55 | # with an object attribute. Currently this 56 | # is used for drawing the pending line a different color. 57 | self.line_color = line_color 58 | 59 | def close(self): 60 | assert len(self.points) > 2 61 | self._closed = True 62 | 63 | def reachMaxPoints(self): 64 | if len(self.points) >=4: 65 | return True 66 | return False 67 | 68 | def addPoint(self, point): 69 | if self.points and point == self.points[0]: 70 | self.close() 71 | else: 72 | self.points.append(point) 73 | 74 | def popPoint(self): 75 | if self.points: 76 | return self.points.pop() 77 | return None 78 | 79 | def isClosed(self): 80 | return self._closed 81 | 82 | def setOpen(self): 83 | self._closed = False 84 | 85 | def paint(self, painter): 86 | if self.points: 87 | color = self.select_line_color if self.selected else self.line_color 88 | pen = QPen(color) 89 | # Try using integer sizes for smoother drawing(?) 90 | pen.setWidth(max(1, int(round(2.0 / self.scale)))) 91 | painter.setPen(pen) 92 | 93 | line_path = QPainterPath() 94 | vrtx_path = QPainterPath() 95 | 96 | line_path.moveTo(self.points[0]) 97 | # Uncommenting the following line will draw 2 paths 98 | # for the 1st vertex, and make it non-filled, which 99 | # may be desirable. 100 | #self.drawVertex(vrtx_path, 0) 101 | 102 | for i, p in enumerate(self.points): 103 | line_path.lineTo(p) 104 | self.drawVertex(vrtx_path, i) 105 | if self.isClosed(): 106 | line_path.lineTo(self.points[0]) 107 | 108 | painter.drawPath(line_path) 109 | painter.drawPath(vrtx_path) 110 | painter.fillPath(vrtx_path, self.vertex_fill_color) 111 | if self.fill: 112 | color = self.select_fill_color if self.selected else self.fill_color 113 | painter.fillPath(line_path, color) 114 | 115 | def drawVertex(self, path, i): 116 | d = self.point_size / self.scale 117 | shape = self.point_type 118 | point = self.points[i] 119 | if i == self._highlightIndex: 120 | size, shape = self._highlightSettings[self._highlightMode] 121 | d *= size 122 | if self._highlightIndex is not None: 123 | self.vertex_fill_color = self.hvertex_fill_color 124 | else: 125 | self.vertex_fill_color = Shape.vertex_fill_color 126 | if shape == self.P_SQUARE: 127 | path.addRect(point.x() - d/2, point.y() - d/2, d, d) 128 | elif shape == self.P_ROUND: 129 | path.addEllipse(point, d/2.0, d/2.0) 130 | else: 131 | assert False, "unsupported vertex shape" 132 | 133 | def nearestVertex(self, point, epsilon): 134 | for i, p in enumerate(self.points): 135 | if distance(p - point) <= epsilon: 136 | return i 137 | return None 138 | 139 | def containsPoint(self, point): 140 | return self.makePath().contains(point) 141 | 142 | def makePath(self): 143 | path = QPainterPath(self.points[0]) 144 | for p in self.points[1:]: 145 | path.lineTo(p) 146 | return path 147 | 148 | def boundingRect(self): 149 | return self.makePath().boundingRect() 150 | 151 | def moveBy(self, offset): 152 | self.points = [p + offset for p in self.points] 153 | 154 | def moveVertexBy(self, i, offset): 155 | self.points[i] = self.points[i] + offset 156 | 157 | def highlightVertex(self, i, action): 158 | self._highlightIndex = i 159 | self._highlightMode = action 160 | 161 | def highlightClear(self): 162 | self._highlightIndex = None 163 | 164 | def copy(self): 165 | shape = Shape("Copy of %s" % self.label ) 166 | shape.points= [p for p in self.points] 167 | shape.fill = self.fill 168 | shape.selected = self.selected 169 | shape._closed = self._closed 170 | if self.line_color != Shape.line_color: 171 | shape.line_color = self.line_color 172 | if self.fill_color != Shape.fill_color: 173 | shape.fill_color = self.fill_color 174 | return shape 175 | 176 | def __len__(self): 177 | return len(self.points) 178 | 179 | def __getitem__(self, key): 180 | return self.points[key] 181 | 182 | def __setitem__(self, key, value): 183 | self.points[key] = value 184 | 185 | -------------------------------------------------------------------------------- /libs/toolBar.py: -------------------------------------------------------------------------------- 1 | try: 2 | from PyQt5.QtGui import * 3 | from PyQt5.QtCore import * 4 | from PyQt5.QtWidgets import * 5 | except ImportError: 6 | from PyQt4.QtGui import * 7 | from PyQt4.QtCore import * 8 | 9 | 10 | class ToolBar(QToolBar): 11 | def __init__(self, title): 12 | super(ToolBar, self).__init__(title) 13 | layout = self.layout() 14 | m = (0, 0, 0, 0) 15 | layout.setSpacing(0) 16 | layout.setContentsMargins(*m) 17 | self.setContentsMargins(*m) 18 | self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint) 19 | 20 | def addAction(self, action): 21 | if isinstance(action, QWidgetAction): 22 | return super(ToolBar, self).addAction(action) 23 | btn = ToolButton() 24 | btn.setDefaultAction(action) 25 | btn.setToolButtonStyle(self.toolButtonStyle()) 26 | self.addWidget(btn) 27 | 28 | 29 | class ToolButton(QToolButton): 30 | """ToolBar companion class which ensures all buttons have the same size.""" 31 | minSize = (60, 60) 32 | def minimumSizeHint(self): 33 | ms = super(ToolButton, self).minimumSizeHint() 34 | w1, h1 = ms.width(), ms.height() 35 | w2, h2 = self.minSize 36 | ToolButton.minSize = max(w1, w2), max(h1, h2) 37 | return QSize(*ToolButton.minSize) 38 | 39 | -------------------------------------------------------------------------------- /libs/zoomWidget.py: -------------------------------------------------------------------------------- 1 | try: 2 | from PyQt5.QtGui import * 3 | from PyQt5.QtCore import * 4 | from PyQt5.QtWidgets import * 5 | except ImportError: 6 | from PyQt4.QtGui import * 7 | from PyQt4.QtCore import * 8 | 9 | class ZoomWidget(QSpinBox): 10 | def __init__(self, value=100): 11 | super(ZoomWidget, self).__init__() 12 | self.setButtonSymbols(QAbstractSpinBox.NoButtons) 13 | self.setRange(1, 500) 14 | self.setSuffix(' %') 15 | self.setValue(value) 16 | self.setToolTip(u'Zoom Level') 17 | self.setStatusTip(self.toolTip()) 18 | self.setAlignment(Qt.AlignCenter) 19 | 20 | def minimumSizeHint(self): 21 | height = super(ZoomWidget, self).minimumSizeHint().height() 22 | fm = QFontMetrics(self.font()) 23 | width = fm.width(str(self.maximum())) 24 | return QSize(width, height) 25 | 26 | -------------------------------------------------------------------------------- /read_xml.py: -------------------------------------------------------------------------------- 1 | import lxml.etree as et 2 | import xml.etree.ElementTree as ET 3 | import math 4 | 5 | 6 | def rotate_xml(filename, Alpha): 7 | """ Parse a PASCAL VOC xml file """ 8 | Alpha=math.radians(Alpha) 9 | tree = ET.parse(filename) 10 | objects = [] 11 | for obj in tree.findall('object'): 12 | # if not check(obj.find('name').text): 13 | # continue 14 | obj_struct = {} 15 | obj_struct['name'] = obj.find('name').text 16 | bbox = obj.find('bndbox') 17 | obj_struct['bbox'] = [int(bbox.find('xmin').text) - 1, 18 | int(bbox.find('ymin').text) - 1, 19 | int(bbox.find('xmax').text) - 1, 20 | int(bbox.find('ymax').text) - 1] 21 | # Read the original coordination 22 | x1=int(bbox.find('xmin').text) 23 | y1=int(bbox.find('ymin').text) 24 | x2=int(bbox.find('xmax').text) 25 | y2=int(bbox.find('ymax').text) 26 | # Transformation 27 | x1_n=x1+ int(y1*math.sin(Alpha)) 28 | y1_n=y1-int(x1*math.sin(Alpha)) 29 | x2_n=x2+int(y2*math.sin(Alpha)) 30 | y2_n=y2-int(x2*math.sin(Alpha)) 31 | print x1_n, y1_n, x2_n, y2_n, math.sin(Alpha), math.cos(Alpha) 32 | x1_new=x1_n 33 | y1_new=y1_n-int((x2-x1)*math.sin(Alpha)) 34 | x2_new=x1_n+int((x2-x1)*math.cos(Alpha)+(y2-y1)*math.sin(Alpha)) 35 | y2_new=y1_n+int((y2-y1)*math.cos(Alpha)) 36 | bbox.find('xmin').text=str(x1_new) 37 | bbox.find('ymin').text=str(y1_new) 38 | bbox.find('xmax').text=str(x2_new) 39 | bbox.find('ymax').text=str(y2_new) 40 | tree.write(filename) 41 | rotate_xml("test2.xml", 5) -------------------------------------------------------------------------------- /read_xml_correct_rotation.py: -------------------------------------------------------------------------------- 1 | import lxml.etree as et 2 | import xml.etree.ElementTree as ET 3 | import math 4 | import cv2 5 | import numpy as numpy 6 | import imutils 7 | 8 | from shutil import copyfile 9 | 10 | def copy_file(file_input, file_output): 11 | copyfile(file_input, file_output) 12 | return file_output 13 | def rotate_file_image(filename, Alpha): 14 | img=cv2.imread(filename,1) 15 | dst=imutils.rotate_bound(img,Alpha) 16 | w_n,h_n,d_n=dst.shape 17 | file_rotate_image=str(Alpha)+filename 18 | cv2.imwrite(file_rotate_image,dst) 19 | file_annotate=filename.replace("png", "xml") 20 | file_annotate_rotate=file_rotate_image.replace("png", "xml") 21 | copy_file(file_annotate,file_annotate_rotate) 22 | rotate_xml(file_annotate_rotate, Alpha,w_n, h_n) 23 | 24 | def rotate_xml(filename, Alpha, w,h): 25 | """ Parse a PASCAL VOC xml file """ 26 | Alpha=math.radians(Alpha) 27 | tree = ET.parse(filename) 28 | objects = [] 29 | 30 | 31 | for st in tree.findall('size'): 32 | w=int(st.find("width").text) -1 33 | h=int(st.find("height").text) -1 34 | h_n=int(w*math.sin(Alpha) + h*math.cos(Alpha)) 35 | w_n=int(h*math.sin(Alpha) + w*math.cos(Alpha)) 36 | st.find("width").text=str(w_n) 37 | st.find("height").text=str(h_n) 38 | tree.write(filename) 39 | 40 | for obj in tree.findall('object'): 41 | # if not check(obj.find('name').text): 42 | # continue 43 | obj_struct = {} 44 | obj_struct['name'] = obj.find('name').text 45 | bbox = obj.find('bndbox') 46 | obj_struct['bbox'] = [int(bbox.find('xmin').text) - 1, 47 | int(bbox.find('ymin').text) - 1, 48 | int(bbox.find('xmax').text) - 1, 49 | int(bbox.find('ymax').text) - 1] 50 | # Read the original coordination 51 | x1=int(bbox.find('xmin').text) 52 | y1=int(bbox.find('ymin').text) 53 | x2=int(bbox.find('xmax').text) 54 | y2=int(bbox.find('ymax').text) 55 | # Transformation 56 | y1_t=int(y1*math.cos(Alpha) + x1*math.sin(Alpha)) 57 | x1_t=int(x1*math.cos(Alpha) + y1*math.sin(Alpha)) 58 | x2_t=int(x2*math.cos(Alpha) + y2*math.sin(Alpha)) 59 | y2_t=int(y2*math.cos(Alpha) + x2*math.sin(Alpha)) 60 | 61 | 62 | x1_n=int((x1*math.cos(Alpha)-y1*math.sin(Alpha)) + (w_n-y2*(1-math.tan(Alpha)))*math.sin(Alpha)) 63 | x2_n=x1_n+int((x2-x1)*math.cos(Alpha)+(y2-y1)*math.sin(Alpha)) 64 | y1_n=y1_t 65 | y2_n=y2_t 66 | if(y2_n>w_n): 67 | y2_n=w_n 68 | if(x2_n>h_n): 69 | x2_n=h_n 70 | bbox.find('xmin').text=str(x1_n) 71 | bbox.find('ymin').text=str(y1_n) 72 | bbox.find('xmax').text=str(x2_n) 73 | bbox.find('ymax').text=str(y2_n) 74 | tree.write(filename) 75 | 76 | 77 | file_image="new1.png" 78 | rotate_file_image(file_image,5) 79 | 80 | 81 | #rotate_xml("test2.xml", 5) -------------------------------------------------------------------------------- /read_xml_correct_rotation_left.py: -------------------------------------------------------------------------------- 1 | import lxml.etree as et 2 | import xml.etree.ElementTree as ET 3 | import math 4 | import cv2 5 | import numpy as numpy 6 | import imutils 7 | 8 | from shutil import copyfile 9 | 10 | def copy_file(file_input, file_output): 11 | copyfile(file_input, file_output) 12 | return file_output 13 | def rotate_file_image(filename, Alpha): 14 | img=cv2.imread(filename,1) 15 | dst=imutils.rotate_bound(img,Alpha) 16 | w_n,h_n,d_n=dst.shape 17 | file_rotate_image=str(Alpha)+filename 18 | Alpha=-1*Alpha 19 | cv2.imwrite(file_rotate_image,dst) 20 | file_annotate=filename.replace("png", "xml") 21 | file_annotate_rotate=file_rotate_image.replace("png", "xml") 22 | copy_file(file_annotate,file_annotate_rotate) 23 | rotate_xml(file_annotate_rotate, Alpha,w_n, h_n) 24 | 25 | def rotate_xml(filename, Alpha, w,h): 26 | """ Parse a PASCAL VOC xml file """ 27 | Alpha=math.radians(Alpha) 28 | tree = ET.parse(filename) 29 | objects = [] 30 | 31 | 32 | for st in tree.findall('size'): 33 | w=int(st.find("width").text) -1 34 | h=int(st.find("height").text) -1 35 | h_n=int(w*math.sin(Alpha) + h*math.cos(Alpha)) 36 | w_n=int(h*math.sin(Alpha) + w*math.cos(Alpha)) 37 | st.find("width").text=str(w_n) 38 | st.find("height").text=str(h_n) 39 | tree.write(filename) 40 | 41 | for obj in tree.findall('object'): 42 | # if not check(obj.find('name').text): 43 | # continue 44 | obj_struct = {} 45 | obj_struct['name'] = obj.find('name').text 46 | bbox = obj.find('bndbox') 47 | obj_struct['bbox'] = [int(bbox.find('xmin').text) - 1, 48 | int(bbox.find('ymin').text) - 1, 49 | int(bbox.find('xmax').text) - 1, 50 | int(bbox.find('ymax').text) - 1] 51 | # Read the original coordination 52 | x1=int(bbox.find('xmin').text) 53 | y1=int(bbox.find('ymin').text) 54 | x2=int(bbox.find('xmax').text) 55 | y2=int(bbox.find('ymax').text) 56 | # Transformation 57 | y1_t=int(y1*math.cos(Alpha) + x1*math.sin(Alpha)) 58 | x1_t=int(x1*math.cos(Alpha) + y1*math.sin(Alpha)) 59 | x2_t=int(x2*math.cos(Alpha) + y2*math.sin(Alpha)) 60 | y2_t=int(y2*math.cos(Alpha) + x2*math.sin(Alpha)) 61 | 62 | # Transformation 63 | 64 | 65 | #x1_n=int((x1*math.cos(Alpha)-y1*math.sin(Alpha)) - (w_n-y2*(1-math.tan(Alpha)))*math.sin(Alpha)) 66 | #x2_n=x1_n+int((x2-x1)*math.cos(Alpha)+(y2-y1)*math.sin(Alpha)) 67 | x1_n=x1_t 68 | x2_n=x1_n+int((x2-x1)*math.cos(Alpha)+(y2-y1)*math.sin(Alpha)) 69 | y1_n=y1_t 70 | y2_n=y2_t 71 | # if(y2_n>w_n): 72 | # y2_n=w_n 73 | # if(x2_n>h_n): 74 | # x2_n=h_n 75 | bbox.find('xmin').text=str(x1_n) 76 | bbox.find('ymin').text=str(y1_n) 77 | bbox.find('xmax').text=str(x2_n) 78 | bbox.find('ymax').text=str(y2_n) 79 | tree.write(filename) 80 | 81 | 82 | file_image="new1.png" 83 | rotate_file_image(file_image,-3) 84 | 85 | 86 | #rotate_xml("test2.xml", 5) -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icons/help.png 5 | icons/expert2.png 6 | icons/expert2.png 7 | icons/done.png 8 | icons/file.png 9 | icons/labels.png 10 | icons/objects.png 11 | icons/close.png 12 | icons/fit-width.png 13 | icons/fit-window.png 14 | icons/undo.png 15 | icons/eye.png 16 | icons/quit.png 17 | icons/copy.png 18 | icons/edit.png 19 | icons/open.png 20 | icons/save.png 21 | icons/save-as.png 22 | icons/color.png 23 | icons/color_line.png 24 | icons/zoom.png 25 | icons/zoom-in.png 26 | icons/zoom-out.png 27 | icons/cancel.png 28 | icons/next.png 29 | icons/prev.png 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /rotation_opencv_fasterRCNN.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as numpy 3 | import math 4 | img=cv2.imread("new2.png",1) 5 | x1,y1=412,254 6 | x2,y2=1000,310 7 | Alpha=math.radians(5) 8 | print (x2-x1)*math.cos(Alpha) 9 | rect=cv2.rectangle(img, (x1, y1), (x2, y2), (255,255,0), 2) 10 | cv2.imshow("rect", rect) 11 | rows,cols, tt=img.shape 12 | M=cv2.getRotationMatrix2D((0, 0),5,1) 13 | dst=cv2.warpAffine(img,M, (cols,rows)) 14 | cv2.imwrite("result.png",dst) 15 | cv2.imshow("img", dst) 16 | # Transformation 17 | x1_n=x1+ int(y1*math.sin(Alpha)) 18 | y1_n=y1-int(x1*math.sin(Alpha)) 19 | x2_n=x2+int(y2*math.sin(Alpha)) 20 | y2_n=y2-int(x2*math.sin(Alpha)) 21 | print x1_n, y1_n, x2_n, y2_n, math.sin(Alpha), math.cos(Alpha) 22 | # Calcul bouding box 23 | x1_new=x1_n 24 | y1_new=y1_n-int((x2-x1)*math.sin(Alpha)) 25 | x2_new=x1_n+int((x2-x1)*math.cos(Alpha)+(y2-y1)*math.sin(Alpha)) 26 | y2_new=y1_n+int((y2-y1)*math.cos(Alpha)) 27 | 28 | print x1_new,y1_new,x2_new, y2_new 29 | rect_new=cv2.rectangle(dst, (x1_new, y1_new), (x2_new,y2_new), (255,0,0), 2) 30 | cv2.imshow("rect_new", rect_new) 31 | cv2.waitKey(0) -------------------------------------------------------------------------------- /rotation_opencv_fasterRCNN_correct_rotation.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as numpy 3 | import math 4 | import imutils 5 | img=cv2.imread("new2.png",1) 6 | x1,y1=100,200 7 | x2,y2=550,350 8 | Alpha=math.radians(5) 9 | t=math.atan(y1*1.0/x1) 10 | #t=math.degrees(t) 11 | #print "goc: ", t 12 | 13 | y1_t=int(y1*math.cos(Alpha) + x1*math.sin(Alpha)) 14 | x1_t=int(x1*math.cos(Alpha) + y1*math.sin(Alpha)) 15 | 16 | x2_t=int(x2*math.cos(Alpha) + y2*math.sin(Alpha)) 17 | y2_t=int(y2*math.cos(Alpha) + x2*math.sin(Alpha)) 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | print y1_t, x1_t, y2_t, x2_t 29 | 30 | 31 | 32 | 33 | print (x2-x1)*math.cos(Alpha) 34 | rect=cv2.rectangle(img, (x1, y1), (x2, y2), (255,255,0), 2) 35 | w,h,d=rect.shape 36 | cv2.imshow("rect", rect) 37 | rows,cols, tt=img.shape 38 | #M=cv2.getRotationMatrix2D((0, 0),10,1) 39 | #dst=cv2.warpAffine(img,M, (cols,rows)) 40 | dst=imutils.rotate_bound(img,5) 41 | 42 | w_n,h_n,d_n=dst.shape 43 | 44 | print "size: ",w , w*math.sin(Alpha) + h*math.cos(Alpha), w_n, h_n 45 | 46 | x1_n=int((x1*math.cos(Alpha)-y1*math.sin(Alpha)) + (w_n-y2*(1-math.tan(Alpha)))*math.sin(Alpha)) 47 | y1_n=int(x1*math.sin(Alpha)+y1*math.cos(Alpha)) 48 | 49 | x2_n=x1_n+int((x2-x1)*math.cos(Alpha)+(y2-y1)*math.sin(Alpha)) 50 | #x1_k=int(w_n*1.0/w)*x1_n 51 | 52 | 53 | rect1=cv2.rectangle(dst, (x1_n, y1_t), (x2_n, y2_t), (0,255,0), 2) 54 | cv2.imshow("rect1", rect1) 55 | 56 | 57 | 58 | # r=h_n*1.0/h 59 | # x1_t=x1_t-(w_n-w) 60 | 61 | # x2_t=x2_t- (w_n-w) 62 | # rect1=cv2.rectangle(dst, (x1_t, y1_t), (x2_t, y2_t), (0,255,0), 2) 63 | # print "r=", r*(x2-x1) 64 | # cv2.imshow("rect1", rect1) 65 | 66 | # cv2.imwrite("result.png",dst) 67 | # #cv2.imshow("img", dst) 68 | 69 | # # Transformation 70 | # x1_n=x1_t 71 | # y1_n=y1_t 72 | # x2_n=x2_t 73 | # y2_n=y2_t 74 | # print x1_n, y1_n, x2_n, y2_n, math.sin(Alpha), math.cos(Alpha) 75 | # # Calcul bouding box 76 | # x1_new=x1_n 77 | # y1_new=y1_n-int((x2-x1)*math.sin(Alpha)) 78 | # x2_new=x1_n+int((x2-x1)*math.cos(Alpha)+(y2-y1)*math.sin(Alpha)) 79 | # y2_new=y1_n+int((y2-y1)*math.cos(Alpha)) 80 | 81 | 82 | 83 | 84 | # print x1_new,y1_new,x2_new, y2_new 85 | # rect_new=cv2.rectangle(dst, (x1_new, y1_new), (x2_new,y2_new), (255,0,0), 2) 86 | #cv2.imshow("rect_new", rect_new) 87 | cv2.waitKey(0) -------------------------------------------------------------------------------- /tests/test.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/tests/test.bmp -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | 2 | from unittest import TestCase 3 | 4 | from labelImg import get_main_app 5 | 6 | 7 | class TestMainWindow(TestCase): 8 | 9 | app = None 10 | win = None 11 | 12 | def setUp(self): 13 | self.app, self.win = get_main_app() 14 | 15 | def tearDown(self): 16 | self.win.close() 17 | self.app.quit() 18 | 19 | def test_noop(self): 20 | pass 21 | 22 | -------------------------------------------------------------------------------- /tests/臉書.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manhcuogntin4/Label-Annotation-VOC-Pascal/aef69b078443ad0baab4d189ddde3ab165ae9b23/tests/臉書.jpg --------------------------------------------------------------------------------